Difference between MATLAB zp2sos and python zpk2sos functions

I am trying to port some code from MATLAB to python. The goal is to use Butterworth filter (4th order, bandpass) API and convert it to second-order sections. I get the same output between MATLAB and python for the Butterworth filter coefficients but not for zp2sos/zpk2sos.

Using MATLAB R2019b, python 3.7, scipy 1.6.3.

Below is MATLAB code with output:

fs = 8000;
f1 = 200;
f2 = 400;

[z,p,k] = butter(4, [f1/(fs/2) f2/(fs/2)]);
[sos,gain] = zp2sos(z,p,k);


MATLAB Output

z = 1 1 1 1 -1 -1 -1 -1

p = 0.9173+0.2885i  0.9173-0.2885i 0.8934+0.2214i 0.8934-0.2214i
0.9237+0.1704i  0.9237-0.1704i 0.9671+0.1555i 0.9671-0.1555i

k = 3.1239e-05

sos = 1.0000    2.0000    1.0000    1.0000   -1.7867    0.8471
1.0000    2.0000    1.0000    1.0000   -1.8475    0.8823
1.0000   -2.0000    1.0000    1.0000   -1.8345    0.9246
1.0000   -2.0000    1.0000    1.0000   -1.9341    0.9594


My python code looks like this:

from scipy import signal

fs = 8000
f1 = 200
f2 = 400

z, p, k = signal.butter(4, [f1/(fs/2), f2/(fs/2)], 'bandpass', output='zpk')
sos = signal.zpk2sos(z, p, k)


Python Output:

z= [ 1.+0.j  1.+0.j  1.+0.j  1.+0.j -1.+0.j -1.+0.j -1.+0.j -1.+0.j]

p = [0.967057-0.15545929j   0.92374003-0.17042575j  0.92374003+0.17042575j 0.967057+0.15545929j
0.91727345+0.28846481j 0.89335425+0.22144318j  0.89335425-0.22144318j 0.91727345-0.28846481j]


Output ordering for 'p' is different than MATLAB but all values account for. Not sure if it matters?

k = 3.123897691708261e-05

sos=
[[ 3.12389769e-05  6.24779538e-05  3.12389769e-05  1.00000000e+00 -1.78670849e+00  8.47118894e-01]
[ 1.00000000e+00  2.00000000e+00  1.00000000e+00  1.00000000e+00 -1.84748005e+00  8.82340575e-01]
[ 1.00000000e+00 -2.00000000e+00  1.00000000e+00  1.00000000e+00 -1.83454690e+00  9.24602526e-01]
[ 1.00000000e+00 -2.00000000e+00  1.00000000e+00  1.00000000e+00 -1.93411400e+00  9.59366836e-01]]


I am not sure why the first 3 coefficients in python are always different than that of MATLAB. I have tried few different inputs. Unfortunately, I do not have experience with DSP or with scipy to understand what this means or how to debug this. I cannot change the MATLAB code but need something equivalent in python. Any help is appreciated.

• In python the scaling constant k is just incorporated into the first second-order section, which is just k*[1,2,1]. May 22, 2021 at 12:29

It's just a scaling. If you call Matlab's zp2sos without the second output argument, you will get the same three values as Python. If you need Python to match Matlab, use the first value of the sos as your "k" and divide the first three values in the sos by k (in your example this yields 1 2 1).