Chebychev filter

Low pass Chebychev filter

There are 2 types of Chebychev filters: Type 1 (the one that is covered in this article) is a filter type that allows some ripple ε in the pass band and therefore reaches a very steep slope towards the stop band. The transfer function of a Chebychev low pass filter of 4. Order looks like:

Chebychev

(Type 2 is the filter type that has some ripple in the stop band)


This steep slope is achieved by the transfer function

Chebychev

With TN(x) as a Chebyshev polynomial (see Integration by the use of Legendre or Chebychev polynomials) and ε as the ripple factor.


The Chebychev polynomial can be expressed as


Chebychev


Now, to implement a digital filter the above formulation must be transformed into a form like:


Chebychev


And therefore Chebychev first calculates the poles of his transfer function


Chebychev


They are there where


Chebychev


This is a complex equation and it has the solution


Chebychev


And with this the transfer function becomes


Chebychev


With V as an amplification vactor that has to be determined as next step. To do this we have to distinguish between the cases N is odd and N is even.

If N is even and we insert the Chebychev polynomial of an even order we get the transfer function


Chebychev



If s = 0 this equation is


Chebychev



But the transfer function we got with our poles gives for s = 0


Chebychev



That means V must be


Chebychev



If N is even.


If N is odd we have


Chebychev



And if s = 0


Chebychev



And so


Chebychev



So, if N is even the final transfer function becomes


Chebychev



and if N is odd


Chebychev


This part with the amplification is often missing in the literature. There they describe an algorithm which is not really correct and finally feed everything into MATLAB…And MATLAB just solves the problem :-)




In the literature there is often a form like


Chebychev



Used for the transfer function. That comes from the fact that the poles are always conjugate complex. The poles are lying on the left side of an ellipse like


Chebychev



and we always have conjugate complex pairs. Her for instance for N = 4


Chebychev



and these pairs are multiplied together like


Chebychev



and so


Chebychev

Chebychev



If N is odd we get a little different situation like


Chebychev



One pole is pure real here and we get


Chebychev

Chebychev



and


Chebychev



For both even N and odd N.




This finally implemented in a c# function is



public void CalcChebychev(int order, double t)
{
     int i = 1;
     double[] poly = new double[3];
     double[] poly2 = new double[2];
     double nu = Math.Log(1.0 / e + Math.Sqrt(1.0 / e * e + 1.0)) / order;
     double sigma;
     double omega;
     a_s = new double[1];
     a_s[0] = 1.0;
     b_s = 1.0;
 
     // The denominator of the transfer function
     if (order % 2 == 0)
     {
         poly[0] = 1.0;
         for (i = 0; i < order / 2; i++)
         {
              sigma = Math.Sinh(nu) * Math.Sin(Math.PI * (2.0 * i + 1.0) / 2.0 / order);
              omega = Math.Cosh(nu) * Math.Cos(Math.PI * (2.0 * i + 1.0) / 2.0 / order);
              poly[1] = 2.0 * sigma;
              poly[2] = sigma * sigma + omega * omega;
              a_s = Poly.Mult(a_s, poly);
              // the enumerator part
              b_s = b_s * sigma * sigma + omega * omega;
         }
     }
     else
     {
         poly[0] = 1.0;
         for (i = 0; i < (order + 1) / 2; i++)
         {
              sigma = -Math.Sinh(nu) * Math.Sin(Math.PI * (2.0 * i + 1.0) / 2.0 / order);
              omega = Math.Cosh(nu) * Math.Cos(Math.PI * (2.0 * i + 1.0) / 2.0 / order);
              if (i < (order) / 2)
              {
                   poly[1] = -2.0 * sigma;
                   poly[2] = sigma * sigma + omega * omega;
                   a_s = Poly.Mult(a_s, poly);
                   // the enumerator part
                   b_s = b_s * sigma * sigma + omega * omega;
              }
              else
              {
                   poly2[0] = 1;
                   poly2[1] = -sigma;
                   a_s = Poly.Mult(a_s, poly2);
                   // the enumerator part
                   b_s = b_s * sigma;
              }
         }
     }
     // the amplification in the enumerator
     if (order % 2 == 0)
         b_s = -b_s * Math.Sqrt(1.0 + e * e);
     else
         b_s = -b_s;
}



This function calculates the transfer function in the Laplace domain and puts it into the array a_s for the denominator and into the double value b_s for the enumerator. An important fact is here that these parameters are independent on any frequency. Here only the ripple ε and the order N of the Chebychev polynomial matter. The frequencies get into the scene when the transfer function is transformed into the z domain.

This transformation into the z domain is done the same way I did it in Digital filter design, by a bilinear transformation with

Chebychev

and

Chebychev


with fc = cut off frequency of the filter and fs = sampling frequency.

The transfer function in the z domain becomes

Chebychev


with fc = cut off frequency of the filter and fs = sampling frequency.

The function to transform is more or less the same as I used it in the Bessel filter . Only the initialisation of the enumerator is a bit different as the input is not just 1 for this.



public void TransformToZPlane()
{
     int i, j;
     List<double[]> aa = new List<double[]>();
     for (i = 0; i <= order; i++)
     {
         aa.Add(new double[] { 1.0, -1.0 });
     }
     double[] tempA = { 1.0, 1.0 };
 
     tempA[0] = 1;
     tempA[1] = 1;
     b_z = Poly.Power(tempA, order);
     b_z = Poly.Mult(b_z, b_s);
     tempA[1] = 1;
 
     for (i = 0; i <= order; i++)
     {
         double[] tempEl = aa.ElementAt(i);
         tempEl = Poly.Mult(Poly.Power(tempA, i), Poly.Power(tempEl, order - i));
         tempEl = Poly.Mult(tempEl, a_s[i] * Math.Pow(2.0 / tc, order - i));
         aa.RemoveAt(i);
         aa.Insert(i, tempEl);
     }
     for (i = 0; i <= order; i++)
     {
         a_z[i] = 0;
         for (j = 0; j <= order; j++)
              a_z[i] = a_z[i] + aa.ElementAt(j)[i];
     }
     for (i =0; i < b_z.Length; i++)
     {
         b_z[i] = b_z[i] / a_z[0];
     }
     for (i = a_z.Length-1; i >= 0; i--)
     {
         a_z[i] = a_z[i] / a_z[0];
     }
}




I initialize the filter like:


t = 2.0 * Math.PI * fc / fs;
TChebychev cheb = new TChebychev(order, t, 0.2);
cheb.CalcChebychev(order, t);
cheb.TransformToZPlane();




For a ripple of 0.2 dB and get the denominator and enumerator polynomial in


cheb.a_z;
cheb.b_z;



With these parameters I get with fs = 10 kHz and fc = 300 Hz and order = 4 the transfer functionn

Chebychev


It has a really steep slope. That looks quite cool. With higher order it get’s even steeper. But the higher the order the more critical the ripple becomes. The Chebychev filter is quite sensitive on too big ripples. If the order is bigger than 4 the ripple should be smaller than 0.1 dB else the algorithm goes crazy :-)




High pass filter

The transformation of the low pass filter into a high pass filter is done by a so called low-pass to high-pass transformation. That just means to replace s by 1/s in the transfer function like

Chebychev


That is

Chebychev


or without compound fraction

Chebychev


In the implementation that means I just have to switch the direction of the elements of my denominator polynomial and add the SN in the enumerator. This can be done in the transformation from Laplace to z domain.



public void TransformToZPlane(bool bHighPass)
{
     int i, j;
 
     double[] tempA = { 1.0, 1.0 };
 
     tempA[0] = 1;
     if (bHighPass)
     {
         tempA[1] = -1;
         b_z = Poly.Power(tempA, order);
         b_z = Poly.Mult(b_z, Math.Pow(2.0 / tc, order));
         double[] temp = new double[a_z.Length];
         for (i = 0; i < a_s.Length; i++)
              temp[i] = a_s[a_s.Length - 1 - i];
         for (i = 0; i < a_s.Length; i++)
              a_s[i] = temp[i];
     }
     else
     {
         tempA[1] = 1;
         b_z = Poly.Power(tempA, order);
     }
     b_z = Poly.Mult(b_z, b_s);
     tempA[1] = 1;




With this small modification the filter can work as high pass filter as well and shows a transfer function

Chebychev


That’s it :-)


The demo project consists of one main window. It processes a short sample signal (red curve) and displays the filtered signal (blue curve) the cut off frequency, sampling frequency and signal frequency can be set and in the left upper corner of the graphic is a checkbox where high or low pass behaviour can be selected.


Butter



A online solver in JavaScript, that returns the filter parameters, can be found on Chebychev filter


C# Demo Project Chebychev filter
  • Chebychev.zip