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$
  • $\begingroup$ See @RobertBristow-Johnson 's famous cookbook here which may help you: musicdsp.org/files/Audio-EQ-Cookbook.txt $\endgroup$ – Dan Boschen Feb 28 '17 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 '17 at 12:21
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).

| improve this answer | |
$\endgroup$
  • $\begingroup$ You're right about coeff mapping. But... how is the scaling calculated? And why? $\endgroup$ – Danijel Feb 28 '17 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 '17 at 14:54
  • $\begingroup$ @SleuthEye: Sure, that's a scaling of 1 (and a scalefactor=0). Thanks, just edited. $\endgroup$ – Matt L. Feb 28 '17 at 22:23
  • $\begingroup$ Resolved it, see above comment. $\endgroup$ – Danijel Mar 1 '17 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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