Неправильная спектрограмма при использовании scipy.signal.spectrogram

Когда я использую plt.specgram из matplotlib, используя следующий код, сгенерированная спектрограмма является правильной

import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile
import numpy as np

sample_rate, samples = wavfile.read('.\\Wav\\test.wav')

Pxx, freqs, bins, im = plt.specgram(samples[:,1], NFFT=1024, Fs=44100, noverlap=900)

спектрограмма, созданная с помощью matplotlib

Однако, если я сгенерирую спектрограмму, используя пример кода, приведенного на странице scipy со следующим кодом, я получу что-то вроде этого:

import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile
import numpy as np

sample_rate, samples = wavfile.read('.\\Wav\\test.wav')

frequencies, times, spectrogram = signal.spectrogram(samples[:,1],sample_rate,nfft=1024,noverlap=900, nperseg=1024)

plt.pcolormesh(times, frequencies, spectrogram)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')

Чтобы отладить происходящее, я попытался использовать Pxx, freqs, bins, сгенерированный первым методом, а затем используйте второй метод для построения графика данных:

plt.pcolormesh(bins, freqs, Pxx)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')

Сгенерированный граф почти такой же, как и сгенерированный вторым методом. Так что, похоже, нет проблем с scipy.signal.spectrogram в конце концов. Проблема в том, как мы строим график. Интересно, если plt.pcolormesh является правильным способом построения спектрограммы, несмотря на то, что этот метод предложен в документе Scipy

Подобный вопрос был задан здесь, но пока нет решения вопроса.

3 ответа

Решение

Режим масштабирования по умолчанию для "Спектрама" - "дБ" (из документации по программе)

масштаб: ['по умолчанию' | "линейный" | 'дБ'] Масштабирование значений в спецификации. "линейный" не масштабирование. "дБ" возвращает значения в масштабе дБ. Когда режим "psd", это мощность дБ (10 * log10). В противном случае это амплитуда дБ (20 * log10). "default" - это "дБ", если mode - "psd" или "magnitude" и "linear" в противном случае. Это должно быть "линейно", если режим "угол" или "фаза".

режим: ['по умолчанию' | "PSD" | "величина" | "угол" | 'фаза'] Какой спектр использовать. По умолчанию используется значение "psd", которое принимает спектральную плотность мощности. 'complex' возвращает комплексный частотный спектр. "Величина" возвращает спектр величин. "угол" возвращает фазовый спектр без развертывания. "фаза" возвращает фазовый спектр с распаковкой.

Для достижения аналогичных результатов с pcolormesh вам нужно будет масштабировать данные эквивалентно.

plt.pcolormesh(times, frequencies, 10*np.log10(spectrogram))

Я не думаю, что пример pcolormesh правильный в своем масштабе. Вы можете ясно видеть несущую в примере, но добавленный шумовой сигнал не виден.

Вы должны использовать одну из нелинейных цветовых карт в своем pcolormesh функция.

Попробуйте установить norm=matplotlib.colors.LogNorm(vmin=np.amin(spectrogram), vmax=np.amax(spectrogram))

Или norm=matplotlib.colors.PowerNorm(gamma=0.5).

См. Https://matplotlib.org/stable/tutorials/colors/colormapnorms.html для получения дополнительной информации.

Используйте это вместо:

plt.pcolormesh(times, frequencies, spectrogram, norm = matplotlib.colors.Normalize(0,1))

Это нормализует данные перед построением графика, чтобы вы могли правильно визуализировать цвет. В документации на matplotlib.colors.Colormap говорится: "Обычно экземпляры Colormap используются для преобразования значений данных (с плавающей запятой) из интервала [0, 1] в цвет RGBA, который представляет соответствующая Colormap". Если ваши значения находятся за пределами этого диапазона, он, вероятно, отобразит его в темном цвете (я полагаю).

Другие вопросы по тегам