Fft-окна в Python, выбор и оптимизация

В настоящее время я пытаюсь рассчитать THD, минимальный уровень шума и другие измерения звука (IMD, частотная характеристика с Python). Для этого я импортирую волновой файл в массив numpy, а затем вычисляю fft с помощью модулей scipy. Чтобы избежать наложения псевдонимов, мне нужно просмотреть мои данные, прежде чем выполнять fft. Итак, я пытаюсь сравнить разные окна, и вот некоторый результат (синусоида 997 кГц, 32 бита, 192 кГц, сгенерированная Adobe Audition):

Мне нужна точность: минимальный уровень шума должен быть как можно ниже, а отклик за пределами пика — как можно более плоским. Итак, мой вопрос: действительно ли Райф-Винсент лучший вариант, который у меня есть? Я пропустил другое «секретное» окно, которое я не знаю и не проверял?

Если я решу сохранить окно Райфа-Винсента, проблема заключается в расчете времени! Остальные окна реализованы в модуле scipy и очень быстро вычисляются. Я рассчитываю коэффициенты Райфа-Винсента следующим образом:

w = np.empty(M,dtype=np.float64)
a = 2*np.pi/M
for i in np.arange(0, M):
    w[i] = (35 - 56*np.cos(a*i) + 28*np.cos(2*a*i) - 8*np.cos(3*a*i) + np.cos(4*a*i))/128

Где M — длина моих данных, которая может быть довольно большой. Это очень трудоемко, может ли кто-нибудь помочь мне оптимизировать его?


person Nessy W.    schedule 18.07.2014    source источник
comment
Что означают 997 кГц синус, 192 кГц?   -  person Davidmh    schedule 18.07.2014
comment
Чистый синусоидальный сигнал с частотой 997 Гц (это была ошибка, извините за это ;)) с частотой дискретизации 192 кГц.   -  person Nessy W.    schedule 18.07.2014


Ответы (1)


Чтобы ответить, как вычислить окно:

a = 2*np.pi/M
x = np.arange(0, M)
w = (35 - 56 * np.cos(a * x) + 28 * np.cos(2 * a * x) - 8 * np.cos(3 * a * x) + np.cos(4 * a * x))/128

должно быть довольно быстро. Вы можете сохранить себе некоторые временные переменные, выполнив следующие действия:

w = 35 - 56 * np.cos(a * x)
w +=  28 * np.cos(2 * a * x)
w -= 8 * np.cos(3 * a * x)
w += np.cos(4 * a * x)
w /= 128.

но это сэкономит вам только 1 секунду примерно из 7 за 3e7 очков.

Если вы хотите, чтобы это было быстрее, вы должны использовать numexpr:

w = ne.evaluate('(35 - 56 * cos(a * x) + 28 * cos(2 * a * x) - 8 * cos(3 * a * x) + cos(4 * a * x))/128')

который будет компилировать и вычислять его параллельно; на моем компьютере время идет от 7 до 2 с.

person Davidmh    schedule 18.07.2014
comment
Большое спасибо, это очень хорошее улучшение! Возможно ли также сократить время загрузки модуля, такого как matplotlib (~ 2 с) и Scipy? - person Nessy W.; 18.07.2014
comment
@НессиВ. это другой вопрос. Но правда в том, что это не должно занять так много времени. На моем ящике MPL загружается за 250 мс, а scipy за 80. Не забудьте добавить к своему вопросу вашу ОС и как они были установлены. - person Davidmh; 18.07.2014
comment
Мой вопрос был не совсем корректно сформулирован, признаю. Я действительно хотел спросить, это нормально, что это занимает так много времени (я работаю над Raspberry Pi :))? Кстати, я слишком быстро тестировал ваш метод numepxr: он быстрее, но не дает того же результата ^^ Я работаю над этим и вернусь, когда найду причину... - person Nessy W.; 18.07.2014
comment
О, тогда вы мало что можете сделать, кроме как исправить свой собственный numpy и уменьшить то, что вы делаете при импорте. Например, вы можете отключить модуль тестирования. - person Davidmh; 19.07.2014