This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Algorithm to generate IIR Biquad Coefficients

Other Parts Discussed in Thread: TLV320DAC3101

Hello,

I am writing a GUI to interface with the TLV320DAC3101. In particular I am trying to use the adaptive filtering capabilities to allow the user of the GUI to change the filter parameters in real time. I would like to use the user input (Gain and cutoff frequency) to generate both bass and treble shelving filters.

Could anyone share what algorithms the TIBQ (slac321a)  tool uses to calculate these coefficients? When using the tool, the filters sound great and work well, however I would like to generate my own coefficients from user input. 

My current method of calculating the coefficients is based on this article:

http://www.dsprelated.com/showcode/170.php

Which is based on the Digital Audio Effects  book by Udo Zolzer which I have read. However, the filter coefficients I am generating are resulting in unstable filters.

I know I need to convert the floating point coefficients to 1.15 fixed point (multiply by 2^15), and that the DAC's  a0 coefficient is 1.0, but I am having trouble finding a reliable method of normalizing the coefficients. I know this is because some of my floats are above 1.0 which is above the max value allowed representable in the 1.15 format (SLAS666A pg29).

Here is a sample of my current code for a Treble Shelf

 double Nrm = pow(2,15);
        double Fo = ui->filterFoDoubleSpinBox->value();
        double gain = ui->filterGaindoubleSpinBox->value();

        double K = tan((PI*Fo)/Fs);
        double V0 = pow(10, (gain/20));
        double root2 = sqrt(2);
        long gain_fixedP = static_cast<long>(gain);
        double b0;
        double b1;
        double b2;
        double a1;
        double a2;
        //***********************************************************************/
        // Coefficient code thanks to www.dsprelated.com/.../170.php
        //***********************************************************************/
        if(gain_fixedP >= 0)
        {

            b0 = (V0 + root2*sqrt(V0)*K + pow(K,2)) / (1 + root2*K + pow(K,2));
            b1 =             (2 * (pow(K,2) - V0) ) / (1 + root2*K + pow(K,2));
            b2 = (V0 - root2*sqrt(V0)*K + pow(K,2)) / (1 + root2*K + pow(K,2));
            a1 =              (2 * (pow(K,2) - 1) ) / (1 + root2*K + pow(K,2));
            a2 =           (1 - root2*K + pow(K,2)) / (1 + root2*K + pow(K,2));

        }
        else
        {
            b0 =               (1 + root2*K + pow(K,2)) / (V0 + root2*sqrt(V0)*K + pow(K,2));
            b1 =                  (2 * (pow(K,2) - 1) ) / (V0 + root2*sqrt(V0)*K + pow(K,2));
            b2 =               (1 - root2*K + pow(K,2)) / (V0 + root2*sqrt(V0)*K + pow(K,2));
            a1 =             (2 * ((pow(K,2))/V0 - 1) ) / (1 + root2/sqrt(V0)*K + pow(K,2)/V0);
            a2 = (1 - root2/sqrt(V0)*K + (pow(K,2))/V0) / (1 + root2/sqrt(V0)*K + pow(K,2)/V0);
        }

        double No = b0*Nrm;
        double N1 = b1*Nrm/2;
        double N2 = b2*Nrm;
        double D1 = a1*Nrm/(-2.0);
        double D2 = -a2*Nrm;

        unsigned short No_fixedPoint = static_cast<unsigned short>(No);
        unsigned short N1_fixedPoint = static_cast<unsigned short>(N1);
        unsigned short N2_fixedPoint = static_cast<unsigned short>(N2);
        unsigned short D1_fixedPoint = static_cast<unsigned short>(D1);
        unsigned short D2_fixedPoint = static_cast<unsigned short>(D2);

        SET_GROUP(activeGUIMsg->header, FILTER);
        ui->filterGroupBox->isChecked() ? EN_GROUP(activeGUIMsg->header) : DISABLE_GROUP(activeGUIMsg->header);
        activeGUIMsg->size = GUI_MSG_SIZE;
        int index = ui->filterSelComboBox->currentIndex();
        unsigned short filter_sel;
        if(-1 == index)
            return;//ERROR
        else
            filter_sel = static_cast<unsigned short>(index);
        activeGUIMsg->data[0] = filter_sel;
        activeGUIMsg->data[1] = ((No_fixedPoint & 0xFF00) >> 8);
        activeGUIMsg->data[2] = (No_fixedPoint & 0x00FF);
        activeGUIMsg->data[3] = ((N1_fixedPoint & 0xFF00) >> 8);
        activeGUIMsg->data[4] = (N1_fixedPoint & 0x00FF);
        activeGUIMsg->data[5] = ((N2_fixedPoint & 0xFF00) >> 8);
        activeGUIMsg->data[6] = (N2_fixedPoint & 0x00FF);
        activeGUIMsg->data[7] = ((D1_fixedPoint & 0xFF00) >> 8);
        activeGUIMsg->data[8] = (D1_fixedPoint & 0x00FF);
        activeGUIMsg->data[9] = ((D2_fixedPoint & 0xFF00) >> 8);
        activeGUIMsg->data[10] = (D2_fixedPoint & 0x00FF);
        for(int i = 11; i < GUI_MSG_SIZE - 2; ++i)
            activeGUIMsg->data[i] = 0;

        writeGUIMessage(activeGUIMsg);
    }

In short, what I am asking for is a reliable algorithm for generating the IIR biquad coefficients in my GUI from user input and normalizing them to appropriate format for the DAC to use. Thank you very much!