scipy/scipy — pull request #432 by WarrenWeckesser (2013-02-12 02:50:48+00:00)
Title: BUG: Fix the automatic frequency selection of scipy.signal.bode.

The automatic selection of the frequencies could miss zeros or resonance peaks, so use the existing function scipy.signal.findfreqs instead of _default_response_frequencies.

Specific changes:
* Modifed the function scipy.signal.bode to use scipy.signal.freqs.
* Added a docstring to scipy.signal.findfreqs.

### More details

The function `_default_response_frequencies` in ltisys.py, used by `signal.bode`, attempts to compute a good range of frequencies for showing the frequency response of an LTI system. This actually duplicates the functionality provided by the function `findfreqs` in filter_design.py.

Because `_default_response_frequencies` doesn't use the zeros or the imaginary parts of the poles of the system, it can generate bad frequency ranges.

For example, the follow either fail or miss important features of the frequency response:

>>> w, mag, phase = bode(([1],[1, 0, 100])) # Raises exception
>>> w, mag, phase = bode(([1],[1, 1e-2, 100])) # Misses the resonance peak near 10
>>> w, mag, phase = bode(([0.01j, -0.01j], [2,2], [0.5])) # Misses the zero at 0.01.

Compare the plots created by `semilogx(w, mag)` to the corresponding plots with data generated by `scipy.signal.freqs`, e.g

>>> system = lti([1], [1, 1e-2, 100])
>>> fw, fh = freqs(system.num, system.den, worN=1000)
>>> semilogx(fw, 20*numpy.log10(abs(fh)))

So in this pull request, I have changed the bode function to use `scipy.signal.freqs` instead of `_default_response_frequencies`. This improves the behavior of `bode` and removes redundant functionality.

I also added a docstring to `findfreqs` in filter_design.py. This is the function used by `freqs` to find the range of frequencies when the frequencies are not specified. It takes into account the zeros and the poles (real and imaginary parts) to choose the frequencies.

In the cases where `_default_response_frequencies` worked, it generally produced a larger range of values than `findfreqs` does, and this often looked better because it went a little further into the asymptotic ranges. Whether `findfreqs` should be tweaked to generate a wider range is something that could be discussed here or in another pull request.