pythonscipysignalsfftspectrum

how to change x axis to find peaks from magnitude spectrum in python


I've loaded an audio file with librosa to plot its magnitude spectrum

signal, sr = librosa.load(audio_file, sr=44100)

signal_fft = np.fft.fft(signal)
magnitude = np.abs(signal_fft)
frequency = np.linspace(0, sr, len(magnitude))

plt.plot(frequency[:30000], magnitude[:30000]) # cutting the plot at the Nyquist frequency
plt.xlabel("Frequency (Hz)")
plt.ylabel("Magnitude")
plt.title("Magnitude spectrum")
plt.show()

Here is the magnitude spectrum :

magnitude spectrum

I have then tried to find the peaks of the spectrum with scipy.signal.find_peaks

peaks, _ = find_peaks(magnitude[:30000], height=350)
plt.plot(magnitude[:30000])
plt.plot(peaks, magnitude[peaks], "x")
plt.show()

Then I wanted to know if it is possible to plot the peaks on the frequency scale ? I'm having troubles to define the x axis because, when it is plotted it is appearing with another scale.

magnitude spectrum with peaks


Solution

  • As indicated in matplotlib.pyplot.plot's documentation:

    x values are optional and default to range(len(y))

    As a result, your second plot uses indices for the x-axis instead of frequencies. To get values in Hz you need the frequency at each of the plotted magnitude, which you fortunately have through your frequency variable. You can thus generate your second plot with the same scale as the first with the following:

    peaks, _ = find_peaks(magnitude[:30000], height=350)
    plt.plot(frequency[:30000], magnitude[:30000])
    plt.plot(frequency[peaks], magnitude[peaks], "x")
    plt.show()