Проблема непрерывности при применении фильтра БИХ на последовательных таймфреймах - PullRequest
0 голосов
/ 23 сентября 2018

Я хотел бы применить КИХ-фильтр или БИХ-фильтр (пример: фильтр нижних частот) на последовательных блоках / таймфреймах из 1024 выборок каждый.

Возможные применения:

  • обработка в реальном времени обработка звука, например EQing.В точное время у нас есть только следующие 1024 семпла в буфере.Следующие сэмплы для обработки еще не доступны (в режиме реального времени).

  • создают изменяющийся по времени фильтр отсечки, разделяя входной сигнал на блоки, как предложено в этом ответе .

Я пробовал это здесь:

import numpy as np
from scipy.io import wavfile
from scipy.signal import butter, lfilter, filtfilt, firwin

sr, x = wavfile.read('input.wav')
x = np.float32(x)
y = np.zeros_like(x)

N  = 1024  # buffer block size = 23ms for a 44.1 Khz audio file
f = 1000  # cutoff
pos = 0  # position

while True:
    b, a = butter(2, 2.0 * f / sr, btype='low')
    y[pos:pos+N] = filtfilt(b, a, x[pos:pos+N])
    pos += N
    f -= 1   # cutoff decreases of 1 hz every 23 ms, but the issue described here also present with constant cutoff!
    print f
    if pos+N > len(x):
        break

y /= max(y)  # normalize

wavfile.write('out_fir.wav', sr, y)

Я пробовал:

  • оба с фильтром Баттерворта илиРПИ (замените строку на b, a = firwin(1000, cutoff=f, fs=sr), 1.0)

  • с lfilter и filtfilt (последний имеетпреимущество применения фильтра вперед и назад, и это решает фазовые проблемы),

, но здесь есть проблема:

** На границах каждого таймфрейма'вывод, есть проблема непрерывности, которая делает аудио сигнал сильно искаженным.

Как решить эту проблему разрыва? Я думал о методе работы с окнами + OverlapAdd, но, безусловно, должен бытьболее простой способ.

enter image description here

1 Ответ

0 голосов
/ 23 сентября 2018

Как упомянуто @sobek в комментарии, конечно, необходимо указать начальные условия, чтобы обеспечить непрерывность.Это делается с параметром zi, равным lfilter.

Проблема решается путем изменения основного цикла следующим образом:

while True:
    b, a = butter(2, 2.0 * f / sr, btype='low')
    if pos == 0:
        zi = lfilter_zi(b, a)
    y[pos:pos+N], zi = lfilter(b, a, x[pos:pos+N], zi=zi)
    pos += N
    f -= 1 
    if pos+N > len(x):
        break

Это работает, даже если отсечка фильтра (и, следовательно, a и b) изменяется вкаждая итерация.

...