diff --git a/doc/api/api_changes/2017-06-11-DB_magnitude_spectrum.rst b/doc/api/api_changes/2017-06-11-DB_magnitude_spectrum.rst new file mode 100644 index 000000000000..67efbb580a99 --- /dev/null +++ b/doc/api/api_changes/2017-06-11-DB_magnitude_spectrum.rst @@ -0,0 +1,31 @@ +Correct scaling of :func:`magnitude_spectrum()` +``````````````````````````````````````````````` + +The functions :func:`matplotlib.mlab.magnitude_spectrum()` and :func:`matplotlib.pyplot.magnitude_spectrum()` implicitly assumed the sum +of windowing function values to be one. In Matplotlib and Numpy the +standard windowing functions are scaled to have maximum value of one, +which usually results in a sum of the order of n/2 for a n-point +signal. Thus the amplitude scaling :func:`magnitude_spectrum()` was +off by that amount when using standard windowing functions (`Bug 8417 +`_ ). Now the +behavior is consistent with :func:`matplotlib.pyplot.psd()` and +:func:`scipy.signal.welch()`. The following example demonstrates the +new and old scaling:: + + import matplotlib.pyplot as plt + import numpy as np + + tau, n = 10, 1024 # 10 second signal with 1024 points + T = tau/n # sampling interval + t = np.arange(n)*T + + a = 4 # amplitude + x = a*np.sin(40*np.pi*t) # 20 Hz sine with amplitude a + + # New correct behavior: Amplitude at 20 Hz is a/2 + plt.magnitude_spectrum(x, Fs=1/T, sides='onesided', scale='linear') + + # Original behavior: Amplitude at 20 Hz is (a/2)*(n/2) for a Hanning window + w = np.hanning(n) # default window is a Hanning window + plt.magnitude_spectrum(x*np.sum(w), Fs=1/T, sides='onesided', scale='linear') + diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 6a46414aafc5..93841e8f1a4e 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -6665,8 +6665,7 @@ def magnitude_spectrum(self, x, Fs=None, Fc=None, window=None, scale : [ 'default' | 'linear' | 'dB' ] The scaling of the values in the *spec*. 'linear' is no scaling. - 'dB' returns the values in dB scale. When *mode* is 'density', - this is dB power (10 * log10). Otherwise this is dB amplitude + 'dB' returns the values in dB scale, i.e., the dB amplitude (20 * log10). 'default' is 'linear'. Fc : integer diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index dfa22e01888b..e362bfcc6ae9 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -727,12 +727,12 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, elif mode == 'psd': result = np.conj(result) * result elif mode == 'magnitude': - result = np.abs(result) + result = np.abs(result) / np.abs(windowVals).sum() elif mode == 'angle' or mode == 'phase': # we unwrap the phase later to handle the onesided vs. twosided case result = np.angle(result) elif mode == 'complex': - pass + result /= np.abs(windowVals).sum() if mode == 'psd': diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png index ebc50c676692..15d32d399208 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png index 14f832a7355b..9dec3eef4339 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png index a18d0b40f43b..a8ceb982774b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png index c2deb9e2414d..95a64798607b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png differ