Реализация блочного низкочастотного фильтра IIR в Python - PullRequest
1 голос
/ 19 сентября 2019

Этот вопрос похож на https://dsp.stackexchange.com/questions/60694, но я переоцениваю его как вопрос реализации Python, чтобы быть более согласованным с решением, которое я ищу.

Я хочу реализовать Low-Фильтр Pass IIR, который работает практически с реальными фрагментами звука (441 точка данных на фрагмент X 100 Гц = 44,1 кГц).Есть много гудящих артефактов.Я ожидаю, что это как-то связано с тем, как я использую методы scipy.signal и устанавливаю начальные условия.

Сначала я попытался понять Теорию, лежащую в основе того, что я делаю, в беседе наФорум DSP, но я давно забыл свой курс в колледже DSP, так что для меня это не имеет особого смысла.Затем я попробовал много, много комбинаций кода, и единственное, что работает (без артефактов) - это очень специфическая комбинация функций и параметров.

Bparam, Aparam = signal.iirfilter(2, 0.020, btype = 'lowpass', analog =
       False, ftype = 'butter')       # 2nd order Butterworth coefficients

Z = signal.lfilter_zi(Bparam, Aparam) # Part of the init conditions calc

IC = Z * (prevSignal[::-1])[0:2]      # Reverse prevSignal and then grab
                                      #   only the last two elements

filteredSignal, _ = signal.lfilter(Bparam, Aparam, inputSignal, zi = IC)
                                      # Result is continuous and clear

prevSignal = filteredSignal           # Save for the next pass

Я тестирую свой фильтр двумя способами.Во-первых, inputSignal - это волна np.sin, а ожидаемый результат - неискаженная синусоида.Второй заключается в добавлении нескольких нечетных гармоник (построение прямоугольной волны с ограниченной полосой частот) и проверке того, что результат имеет меньшие амплитуды этих гармоник, как фильтр нижних частот.

Приведенный выше код соответствует ожиданиям, когдапорядок второго порядка, но при более высоких порядках искажение присутствует.Я пытался, например, установить диапазон IC на [0: 4], и он, кажется, не работает так же.

1 Ответ

1 голос
/ 20 сентября 2019

В статье @Warren (что имхо отлично) раздел Фильтрация длинного сигнала в пакетах помог мне ответить на мой вопрос.Наряду с примером кода, приведенным в этом разделе, я сформировал массив sos следующим образом:

Bparam, Aparam = signal.iirfilter(2, 0.02,
                   btype = 'lowpass', analog = False, ftype = 'butter')
Z, P, K = signal.tf2zpk(Bparam, Aparam)
sos = signal.zpk2sos(Z, P, K)

Я также пробовал это на фильтрах верхних частот, вплоть до 8-го порядка, без проблем!

...