SigmaStudio export human-readable values

Dear EngineerZone,

it is a long time ago i asked a similar question but the question is now closed. So I will ask again.

Is there any way to export all human-readable parameters out of sigma studio, like frequency, q, ripple and so on?

We are working on several projects where a microcontroller controls the DSP (ADAU1452). The user can change filter-frequency and a lot of different parameters or load whole presets. A very common use case. This means that we have to store all parameters inside the MCU to calculate the coefficiants. At the moment we have to copy all values from sigmastudio into our code by hand, which is a lot of work and not failure safe. Also when you think of whole presets. When we pepare a new preset in sigmastudio we have to copy everything again by hand. 

It would be great if there is a way to get on these vaules instead of only the coefficiants. 

Best regards and thanks in advance, 

Eric

  • 0
    •  Super User 
    on Jul 4, 2019 3:14 PM over 1 year ago

         Hello Eric,

         This is most often done by storing only the filter parameters (frequency, Q, and boost) in your micro, then have it calculate the coefficients on the fly in order to safeload the filters inside the ADAU1452's parameter memory.  Inside SigmaStudio, use ordinary general 2nd-order filters with dummy values which your uC writes over at power-up and as needed.  With the micro handling all this, there's no need to hand copy coefficients from SigmaStudio.

         This is easiest when you limit your input parameters as is commonly done in digital EQ:  frequency choices in 1/6 octave steps, boost in 1 dB steps, and bandwidth in fixed choices.  The micro can be programmed with a combination of lookup tables and math to figure the filter coefficients.  Presets are simply stored parameters which can go through the same math on the way to the DSP.  The basic formulas for calculating coefficients are found in the SigmaStudio wiki.  You may find it easier to extract these formulas from the spreadsheet I've attached.  You can test whether your calculations are correct by hand entering the resulting coefficients into a General Second-Order Filter set for IIR Coefficient.  The most common error is the sign of the "a" coefficients; often they need to be inverted.

         Best regards,

         Bob

    Multi-EQ_IIR-Coefficient_Calculator.zip

  • Hello Bob,

    thanks a lot for your answer. Our problem is not the calculation. We do it excatly in the way you described above. So we store the filter parameters (frequency, Q and boost) in the MCU and calculate the coefficiants if a user change settings. But to do this we need the default values of these parameters to update the DSP on startup.

    Our problem is that our "audio engineers" are using SigmaStudio for the default setup. It is very convenient for them because the design the DSP schematic structure and they adjust the default values in real time during the device runs. 

    After they are ready with everything this file goes to the embedded department where they add the MCU control and so on. But in this moment we have to copy the values/parameters out of SigmaStudio that the DSP is updated on startup with the default settings. It would be great to export the parameters out of SigmaStudio. Is there a way to do this?

    Best regards and thanks in advance,

    Eric

  • Hello Bob,

    do you have any news for me regarding my last question/explanaiton? 

    Many thanks in advance and best regards,

    Eric 

  • One solution would be to read the coefficients from the DSP and reverse-engineer the filter settings based on those. In general it's not too hard to run the algorithms in reverse. The main challenge is determining the filter type, especially since no filter type might hold exactly anymore after rounding of the cofficients.

    For example, here's a python script that converts between close-to-"end-user" parameters and DSP coefficients for the subset of second-order filters that are "invertible" (peaking EQ, low shelf, and high shelf):

    #!/usr/bin/python3
    
    from math import pi, cos, sin, log10, floor, atan2, sqrt
    tau = 2 * pi
    
    def round( x ):
        return floor( x + 0.5 )
    
    
    # note: these two linear transforms are not exact inverses, their composition
    # multiplies all coefficients by 4, but we renormalize anyway so that's no prob
    
    def transform( gL, gC, gH ):
        g0 =   gL + 2*gC +   gH
        g1 = 2*gL        - 2*gH
        g2 =   gL - 2*gC +   gH
    
        return ( g0, g1, g2 )
    
    
    def itransform( g0, g1, g2 ):
        gL = g0 + g1 + g2
        gC = g0      - g2
        gH = g0 - g1 + g2
    
        return ( gL, gC, gH )
    
    
    fS = 48000
    
    
    def bq_to_dsp( f, Q, bL, bC, bH, aL=1, aC=1, aH=1 ):
        assert f > 0
        assert f < fS/2
        assert Q > 0
    
        f = f / fS * tau
        x = cos( f )
        y = sin( f )
        ζ = 0.5 / Q
    
        bL = ( 1 - x ) * bL;   aL = ( 1 - x ) * aL;
        bC = ( ζ * y ) * bC;   aC = ( ζ * y ) * aC;
        bH = ( 1 + x ) * bH;   aH = ( 1 + x ) * aH;
    
        ( b0, b1, b2 ) = transform( bL, bC, bH )
        ( a0, a1, a2 ) = transform( aL, aC, aH )
    
        b2 /= a0;  a2 /= a0;
        b1 /= a0;  a1 /= a0;
        b0 /= a0;  a0  = 1;
    
        return [ round( x * 2**24 ) for x in ( b2, b1, b0, -a2, -a1 ) ]
    
    
    def ibq_to_dsp( f, Q, gL, gC, gH ):
        # convert dB to sqrt of linear gain
        bL = 10**( gL / 40 )
        bC = 10**( gC / 40 )
        bH = 10**( gH / 40 )
    
        return bq_to_dsp( f, Q, bL, bC, bH, 1/bL, 1/bC, 1/bH )
    
    
    def dsp_to_ibq( coeffs ):
        ( b2, b1, b0, a2, a1 ) = ( x / 2**24 for x in coeffs )
        a0 = 1;  a1 = -a1;  a2 = -a2;
    
        ( bL, bC, bH ) = itransform( b0, b1, b2 )
        ( aL, aC, aH ) = itransform( a0, a1, a2 )
    
        dL = sqrt( bL * aL )
        dC = sqrt( bC * aC )
        dH = sqrt( bH * aH )
    
        x = ( dH - dL ) / ( dH + dL )
        y = sqrt( 1 - x**2 )
        f = atan2( y, x ) / tau * fS
        Q = ( dH + dL ) * y / dC / 4
    
        gL = log10( bL / aL ) * 20
        gC = log10( bC / aC ) * 20
        gH = log10( bH / aH ) * 20
    
        return ( f, Q, gL, gC, gH )
    
    
    f = 1500;  Q = sqrt(2);  gL = 0;  gC = 4; gH = 0;
    ( fx, Qx, gLx, gCx, gHx ) = dsp_to_ibq( ibq_to_dsp( f, Q, gL, gC, gH ) )
    
    print( "f  = %7.1f -> %7.1f" % ( f, fx ) )
    print( "Q  = %7.3f -> %7.3f" % ( Q, Qx ) )
    print( "gL = %+7.1f -> %+7.1f" % ( gL, gLx ) )
    print( "gC = %+7.1f -> %+7.1f" % ( gC, gCx ) )
    print( "gH = %+7.1f -> %+7.1f" % ( gH, gHx ) )

    The parameters gL, gC, and gH here require some explanation: for each "standard" type of invertible second-order filter these are subject to two linear constraints:

    • peaking EQ:  gL=0,  gH=0,  gC is the gain of the peak
    • low shelf:  gH=0,  gC=gL/2,  gL is the gain of the shelf
    • high shelf:  gL=0,  gC=gH/2,  gH is the gain of the shelf

    However, after rounding the DSP coefficients, none of these might hold anymore. You'd need to find the best fit for the type-selection and the remaining parameter, and the result might not exactly match the original values (although I'd be surprised if the result dsp coefficients differ from the original ones by more than 1). In practice, with 24 fractional bits of precisioin, this problem is likely to be quite minor.

    To make this complete, you'd also need to add detection of various other types. Many of them are in theory quite easy to detect, especially using (bL, bC, bH) as produced by itransform():

    • high-pass:  b0+b1+b2 == 0  (i.e. bL == 0)
    • low-pass:  b0-b1+b2 == 0  (i.e. bH == 0)
    • notch: b0-b2 == 0  (i.e. bC == 0)

    But again, these constraints might not hold exactly anymore after rounding.

  • 0
    •  Super User 
    on Jul 29, 2019 11:56 PM over 1 year ago in reply to matthijs

         Thanks Matthijs!  Good solution since SigmaStudio doesn't offer the export feature that Eric is looking for.  So his query amounts to a feature request.

         Eric -- sorry I didn't understand your needs at first.  Where I work, once completing my Sigma program I make a text file for the uC programming engineer with all the parameters and addresses he needs to put in his C code.  This is because he sits 20 feet from me -- and having done a little C coding myself (forgetting numerous semicolons), there's no way I would dump a .dspproj file on him to open & chase the stuff on his own.  "Real" programming is tough enough to begin with.