# Analog Filter Prototype to Direct Form Second Order Cascade

I've been using the Faust programming language a lot lately for experimenting with DSP, and I've been digging into their implementation of an Elliptic (Cauer) Lowpass filter. Here's an example of such a filter with order three.

If you're unfamiliar with Faust, hopefully the example there is still fairly clear: they've designed a 3rd order Cauer filter with the properties listed in the comments and have implemented it as a second order direct form filter feeding into a first order direct form filter with the coefficients as listed.

I understand the analog prototype they've designed with [z,p,g] = ncauer(Rp,Rs,3); in Matlab/Octave, and I think I have a good understanding of how to factor the transfer function into cascaded first- and second-order filters. What I don't understand is their use of poly in Octave to find the coefficients there, and why the frequency of this elliptic filter is only governed by the last coefficient in the final first order filter? Intuitively it seems like so many more of those coefficients should depend on the frequency of the filter, especially if we have to consider multiple sample rates. Did they skip some steps here or make some assumptions that I'm missing? Any explanation to my confusion here would be greatly appreciated, thank you!

Update: I find it interesting that in Matlab/Octave I can compute [z,p,g] = ncauer(0.2,60,3); sos=zp2sos(z, p, g), deriving coefficients for second order sections without ever specifying the cutoff frequency. Maybe that's where I'm most confused?

• You should better ask on the Faust users list here: lists.sourceforge.net/lists/listinfo/faudiostream-users – sletz Mar 3 '17 at 15:17
• Where in the code do you see that only one coefficients of the first order filter determines the cut-off frequency? – Matt L. Mar 3 '17 at 17:23
• @sletz good point, I will do that. I would also appreciate an answer here in case the list is unresponsive! – ncthom91 Mar 3 '17 at 22:38
• @MattL. So the line lowpass3e(fc) = tf2s(b21,b11,b01,a11,a01,w1) : tf1s(0,1,a02,w1) defines a function which takes 1 parameter, fc, and the output is a 2nd order filter (tf2s) feeding into a 1st order filter (tf1s). Their coefficients there are specified and defined right underneath in the with block. The only reference to the input fc argument is in the definition of the w1 coefficient, the last one supplied to tf1s. All of the other coefficients are constant and thus unrelated to fc it seems. – ncthom91 Mar 3 '17 at 22:41
• i dunno the syntax, but it looks like both tf2s() and tf1s() have w1 as an argument, so i would expect that both the second-order and first-order IIR filters have coefficients that depend on w1 (and then fc.) – robert bristow-johnson Mar 4 '17 at 3:24

The coefficients in the function lowpass3() are the numerator and denominator coefficients of the two sections (first and second order) of the normalized continuous-time transfer function. The continuous-time transfer function looks like this:

$$H(s)=\frac{b_{21}s^2+b_{11}s+b_{01}}{s^2+a_{11}s+a_{01}}\cdot\frac{1}{s+a_{02}}\tag{1}$$

Note that this normalized filter has a cut-off frequency of $1$. The two functions tf2s and tf1s transform these two sections to the discrete-time domain using the bilinear transform, whereby the normalized cut-off frequency of the continuous-time filter is mapped to the desired cut-off frequency in the discrete-time domain. So whereas the coefficients in $(1)$ are independent of the cut-off frequency (because the filter is normalized), the coefficients of both final filter sections in the discrete-time domain do depend on the cut-off frequency.

Your example of using ncauer followed by zp2sos will not give you the coefficients of the discrete-time filter with the desired cut-off frequency. Instead, you just the compute the coefficients of the first and second order sections of the normalized continuous-time low pass filter, i.e., the coefficients hard-coded in lowpass3(). What you miss in that case is the transformation step from continuous-time to discrete-time, and the mapping of the normalized cut-off frequency to the desired cut-off frequency.

• Thank you this is very helpful. So because we're dealing with a normalized continuous-time transfer function, does that mean the analog cutoff frequency is 1? And the w1 parameter defines the mapping of the analog cutoff frequency to the digital cutoff frequency? – ncthom91 Mar 4 '17 at 17:17
• @ncthom91: Yes, that's why we can have the same coefficients as a basis for all filters. The desired cut-off frequency of the discrete-time filter is realized by adapting a constant in the bilinear transformation. – Matt L. Mar 4 '17 at 17:28
• I see, ok! I almost have all of this down I think. I didn't realize that the coefficients supplied to lowpass3e() were the coefficients of the analog polynomial; so the use of poly here is because the poles and zeros from ncauer are defined as complex conjugate pairs, and we need the roots? I'm trying to follow along in Octave and I can almost put it all together but I don't exactly understand how they found the coefficients here. – ncthom91 Mar 4 '17 at 17:32
• @ncthom91: Just look at ncauer and/or read this, to figure out how the poles and zeros of an analog Chebyshev filter are computed. As soon as you have the poles and zeros, you can find the corresponding polynomial coefficients by using poly. – Matt L. Mar 4 '17 at 17:36
• This has been so helpful, thank you. I think the last part is a bit of confusion about how you factored the sections in the transfer function you wrote above. Or, how one decides that factorization when designing these sections themselves. I've found a few resources that might be of help but I'd appreciate your thoughts as well. Either way, thank you, I'll mark this as the correct answer! – ncthom91 Mar 4 '17 at 18:59