Skip to content

Scaling of mlab.magnitude_spectrum() is inconsistent #8417

@DietBru

Description

@DietBru

Compared to signal.welch() and mlab.psd(), the scaling of mlab.magnitude_spectrum() is not consistent. The normalization of the window seems to be missing, as the following example shows:

spectrum_scaling

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import mlab
from scipy import signal

tau, n = 10, 2**10  # 10 second signal with 1024 points
T = tau/n  # sampling interval

t = np.arange(n)*T
x = 4*np.sin(40*np.pi*t)  # 20 Hz sine
w = signal.hanning(n, False)

f = np.fft.fftfreq(n, T)  # frequency slots
df = f[1] - f[0]
X = np.fft.fft(x*w)/w.sum()  # Windowed FFT scaled to amplitude

f_Pxx, Pxx = signal.welch(x, fs=1/T, window='hanning', nperseg=n, noverlap=0,
                          detrend=False, return_onesided=False,
                          scaling='spectrum')
P_psd, f_psd = mlab.psd(x, NFFT=n, Fs=1/T,  window=w,
                        sides='twosided', scale_by_freq=False)

# shift for plotting:
f, X, f_Pxx, Pxx = (np.fft.fftshift(zz) for zz in (f, X, f_Pxx, Pxx))

fg0, axx0 = plt.subplots(4, 1, sharex=True, num=1, figsize=(7, 7), clear=True)

axx0[0].set_title(r"FFT Magnitude Spectrum of $x(t)=4\sin(40\pi t)$")
axx0[0].plot(f, np.abs(X), 'C0.-')

axx0[1].set_title("Scipy's Welch Algorithm")
axx0[1].plot(f_Pxx, np.sqrt(Pxx), "C1.-")

axx0[2].set_title("psd()")
axx0[2].plot(f_psd, np.sqrt(P_psd), "C2.-")

axx0[3].set_title("magnitude_spectrum()")
axx0[3].magnitude_spectrum(x, Fs=1/T, sides='twosided', color="C3", marker='.',
                           scale='linear')
# Correct result:
# axx0[3].magnitude_spectrum(x, Fs=1/T, sides='twosided', color="C3", marker='.',
#                           scale='linear', window=w/w.sum())

axx0[-1].set_xlabel(r"Frequency $f$")
axx0[0].set_xlim(19, 21)
for ax in axx0:
    ax.grid(True)
    ax.set_ylabel(r"$|X(f)|$")
fg0.tight_layout()
plt.show()

I tried fixing it, but I could find the time to fix mlab._spectral_helper() to perform consistently with mlab.magnitude_spectrum() and mlab.spegram().

PS: Tested on Matplotlib 2.0.0 (Anaconda Python 3.6 on Debian).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions