fearless_fool
fearless_fool

Reputation: 35179

Applying scipy filter to multidimensional data

I have stereo audio data represented by a numpy array with a shape of (2500, 2). I'd like to filter it using scipy's signal.sosflt() function, but I'm getting:

ValueError: Invalid zi shape. With axis=0, an input with shape (2500, 2), and an sos array with 2 sections, zi must have shape (2, 2, 2), got (2, 2).

The only complexity in the code is that I'm initializing zi once when processing the first buffer, then using it to condition the filter on subsequent calls:

from scipy import signal

def setup():
    zi = None
    # define a narrow band filter centered around 440 Hz.
    sos = signal.butter(2, [438, 442], btype='bandpass', output='sos', fs=48000)

def process(src, dst):
    # src and dst shape = (2500, 0)
    if zi is None:
        zi = signal.sosfilt_zi(sos)  # initialize zi on first buffer
    dst, zi = signal.sosfilt(sos, src, axis=0, zi=zi)

(Note: I've tried axis=-1 and axis=1 but neither of those are correct.)

Upvotes: 2

Views: 804

Answers (1)

fearless_fool
fearless_fool

Reputation: 35179

A solution, but perhaps not the cleanest:

Since the source data is stereo, sosfilt needs two copies of zi, one for each channel. The following will work, but only if src has two columns:

from scipy import signal

def setup():
    zi = None
    # define a narrow band filter centered around 440 Hz.
    sos = signal.butter(2, [438, 442], btype='bandpass', output='sos', fs=48000)

def process(src, dst):
    # src and dst shape = (2500, 0)
    if zi is None:
        tmp = signal.sosfilt_zi(sos)
        zi = [tmp, tmp]               # assumes source data has two columns
    dst, zi = signal.sosfilt(sos, src, axis=0, zi=zi)

This works, but a more general solution would initialize zi based on the shape of the source data.

Upvotes: 1

Related Questions