1
$\begingroup$

This is a biquad implementation I use:

float my_biquad(float in, float *coeffs, int scalefactor, float *delay) 
{
    float out = coeffs[2] * in + delay[0];    
    out = out * (float)pow( 2, scalefactor );    
    delay[0] = delay[1] + coeffs[1]*in - coeffs[4]*out;
    delay[1] = coeffs[0]*in - coeffs[3]*out;

    // etc...

    return out;
}

It cascades several biquads:

for(int j=0;j<num_biquads;j++) 
{
    tmp = biquad(...);
}

Each biquad has its coefficients and a scalefactor. Scalefactor is integer.


On the other hand, I have a Matlab filter:

[B_coeffs, A_coeffs ] = butter(4, 100/(16000/2), 'high');

I need to implement the Matlab filter using the above biquad.

I tried using tf2sos which gave me two biquad sections:

[ss, gn] = tf2sos(B_coeffs, A_coeffs);

but feeding ss coefficients to biquad in C gave different results than Matlab version. Gain gn is left unused, and I don't even have scalefactors.

How do I go from Matlab to this particular version of biquad in C? How to create proper coeffs and scalefactors?

$\endgroup$
2
  • $\begingroup$ See @RobertBristow-Johnson 's famous cookbook here which may help you: musicdsp.org/files/Audio-EQ-Cookbook.txt $\endgroup$ Feb 28, 2017 at 12:23
  • $\begingroup$ OK, I figured it out. First, gain is applied to nominator coeffs, and second, scalefactors just scale coeffs to fit into Q31 range [-1,1] (finding closest power of 2, to make descaling shift only in fixed-point domain). Therefore unscaling in the code: out = out * (float)pow( 2, scalefactor );. This produces the same result as Matlab version. $\endgroup$
    – Danijel
    Mar 1, 2017 at 12:21

1 Answer 1

2
$\begingroup$

What I can see from the code is the following mapping between the array coeffs[] and the filter coefficients $a_i$ and $b_i$ (note that $a_0=1$ and is not stored in coeffs[]):

$b_0=$coeffs[2], $b_1=$coeffs[1], $b_2=$coeffs[0]

$a_1=$coeffs[4], $a_2=$coeffs[3]

For the time being choose the scaling equal to $1$ (scalefactor=0) to check if everything else works. The final scaling per section will depend on the order of the sections, and on the goal of scaling (minimization of the possibility of overflow, or minimizing quantization noise).

$\endgroup$
4
  • $\begingroup$ You're right about coeff mapping. But... how is the scaling calculated? And why? $\endgroup$
    – Danijel
    Feb 28, 2017 at 14:49
  • $\begingroup$ @Danijel: In principle you can just use scaling=1. However, for a fixed-point implementation you may need to scale in order to avoid overflow. For a specific implementation you need to check at which points in your code overflow can occur and scale accordingly. $\endgroup$
    – Matt L.
    Feb 28, 2017 at 14:54
  • $\begingroup$ @SleuthEye: Sure, that's a scaling of 1 (and a scalefactor=0). Thanks, just edited. $\endgroup$
    – Matt L.
    Feb 28, 2017 at 22:23
  • $\begingroup$ Resolved it, see above comment. $\endgroup$
    – Danijel
    Mar 1, 2017 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.