Set list according to setlist.fm
-
-
-
-
-
-
-
-
-
-
-
-
-
AOD (encore)
public List<Complex> getPoles(int order) { Debug.Assert(order <= 10); List<Complex> poles = null; switch (order) { case 1: poles = new List<Complex>() { new Complex(-1, 0) }; break; case 2: poles = new List<Complex>() { new Complex(-1.5, 0.8660254038), new Complex(-1.5, -0.8660254038) }; break; case 3: poles = new List<Complex>() { new Complex(-1.8389073227, 1.7543809598), new Complex(-2.3221853546,0), new Complex(-1.8389073227, 1.7543809598) }; break; case 4: poles = new List<Complex>() { new Complex(-2.1037893972, 2.6574180419), new Complex(-2.8962106028 , 0.8672341289), new Complex(-2.8962106028 , -0.8672341289), new Complex(-2.1037893972, -2.6574180419) }; break; case 5: poles = new List<Complex>() { new Complex(-3.646738595, 0), new Complex(-2.324674303, 3.57102292), new Complex(-3.351956399, 1.742661416), new Complex(-3.351956399, -1.742661416), new Complex(-2.324674303, 3.57102292) }; break; case 6: poles = new List<Complex>() { new Complex(-2.515932248, 4.492672954), new Complex(-3.735708356, 2.626272311), new Complex(-4.248359396, 0.867509673), new Complex(-4.248359396, -0.867509673), new Complex(-3.735708356, -2.626272311), new Complex(-2.515932248, -4.492672954) }; break; case 7: poles = new List<Complex>() { new Complex(-4.971786859, 0), new Complex(-2.685676879, 5.420694131), new Complex(-4.070139164, 3.517174048), new Complex(-4.758290528, 1.739286061), new Complex(-4.758290528, -1.739286061), new Complex(-4.070139164, -3.517174048), new Complex(-2.685676879, -5.420694131) }; break; case 8: poles = new List<Complex>() { new Complex(-2.838983949, 6.353911299), new Complex(-4.368289217, 4.414442501), new Complex(-5.204840791, 2.616175153), new Complex(-5.587886043, 0.867614445), new Complex(-5.587886043, -0.867614445), new Complex(-5.204840791, -2.616175153), new Complex(-4.368289217, -4.414442501), new Complex(-2.838983949, -6.353911299) }; break; case 9: poles = new List<Complex>() { new Complex(-6.297019182, 0), new Complex(-2.979260798, 7.291463688), new Complex(-4.638439887, 5.317271675), new Complex(-5.60442182, 3.498156918), new Complex(-6.129367904, 1.737848384), new Complex(-6.129367904, -1.737848384), new Complex(-5.60442182, -3.498156918), new Complex(-4.638439887, -5.317271675), new Complex(-2.979260798, 7.291463688) }; break; case 10: poles = new List<Complex>() { new Complex(-3.108916234, 8.232699459), new Complex(-4.886219567, 6.224985483), new Complex(-5.967528329, 4.384947189), new Complex(-6.615290966, 2.611567921), new Complex(-6.922044905, 0.867665196), new Complex(-6.922044905, 0.867665196), new Complex(-6.615290966, 2.611567921), new Complex(-5.967528329, 4.384947189), new Complex(-4.886219567, 6.224985483), new Complex(-3.108916234, 8.232699459) }; break; } return poles; }
public ComplexPlane MatchedZTransform() { ComplexPlane zplane = new ComplexPlane(); zplane.poles = new List<Complex>(); zplane.zeros = new List<Complex>(); for (int i = 0; i < poles.Count; i++) { // returns exponential function of the complex number zplane.poles.Add(Complex.FromPolarCoordinates(Math.Exp(poles[i].Real),poles[i].Imaginary)); } for (int i = 0; i < zeros.Count; i++) { // returns exponential function of the complex number zplane.zeros.Add(Complex.FromPolarCoordinates(Math.Exp(zeros[i].Real),zeros[i].Imaginary)); } return zplane; }
using System; using System.Diagnostics; using System.Numerics; using System.Collections.Generic; // Hondrou implementation of a Bessel filter building on the STK framework // // This approach uses the techniques from Tony Fischer at York in mkfilter // http://www-users.cs.york.ac.uk/~fisher/mkfilter/ // and builds on the Java implementation by Christian d'Heureuse // www.source-code.biz, www.inventec.ch/chdh // namespace AgSynth { public class Bessel : Iir { public List<Complex> getPoles(int order) { Debug.Assert(order <= 10); List<Complex> poles = null; switch (order) { case 1: poles = new List<Complex>() { new Complex(-1, 0) }; poles = Polynomial.multiply(poles, 1 / 1.731939); break; case 2: poles = new List<Complex>() { new Complex(-1.5, 0.8660254038), new Complex(-1.5, -0.8660254038) }; poles = Polynomial.multiply(poles, 1 / 1.977607); break; case 3: poles = new List<Complex>() { new Complex(-1.8389073227, 1.7543809598), new Complex(-2.3221853546,0), new Complex(-1.8389073227, 1.7543809598) }; poles = Polynomial.multiply(poles, 1 / 2.422182); break; case 4: poles = new List<Complex>() { new Complex(-2.1037893972, 2.6574180419), new Complex(-2.8962106028 , 0.8672341289), new Complex(-2.8962106028 , -0.8672341289), new Complex(-2.1037893972, -2.6574180419) }; poles = Polynomial.multiply(poles, 1 / 2.886229); break; case 5: poles = new List<Complex>() { new Complex(-3.646738595, 0), new Complex(-2.324674303, 3.57102292), new Complex(-3.351956399, 1.742661416), new Complex(-3.351956399, -1.742661416), new Complex(-2.324674303, 3.57102292) }; poles = Polynomial.multiply(poles, 1 / 3.324236); break; case 6: poles = new List<Complex>() { new Complex(-2.515932248, 4.492672954), new Complex(-3.735708356, 2.626272311), new Complex(-4.248359396, 0.867509673), new Complex(-4.248359396, -0.867509673), new Complex(-3.735708356, -2.626272311), new Complex(-2.515932248, -4.492672954) }; poles = Polynomial.multiply(poles, 1 / 3.725753); break; case 7: poles = new List<Complex>() { new Complex(-4.971786859, 0), new Complex(-2.685676879, 5.420694131), new Complex(-4.070139164, 3.517174048), new Complex(-4.758290528, 1.739286061), new Complex(-4.758290528, -1.739286061), new Complex(-4.070139164, -3.517174048), new Complex(-2.685676879, -5.420694131) }; poles = Polynomial.multiply(poles, 1 / 4.090078); break; case 8: poles = new List<Complex>() { new Complex(-2.838983949, 6.353911299), new Complex(-4.368289217, 4.414442501), new Complex(-5.204840791, 2.616175153), new Complex(-5.587886043, 0.867614445), new Complex(-5.587886043, -0.867614445), new Complex(-5.204840791, -2.616175153), new Complex(-4.368289217, -4.414442501), new Complex(-2.838983949, -6.353911299) }; poles = Polynomial.multiply(poles, 1 / 4.423721); break; case 9: poles = new List<Complex>() { new Complex(-6.297019182, 0), new Complex(-2.979260798, 7.291463688), new Complex(-4.638439887, 5.317271675), new Complex(-5.60442182, 3.498156918), new Complex(-6.129367904, 1.737848384), new Complex(-6.129367904, -1.737848384), new Complex(-5.60442182, -3.498156918), new Complex(-4.638439887, -5.317271675), new Complex(-2.979260798, 7.291463688) }; poles = Polynomial.multiply(poles, 1 / 4.732941); break; case 10: poles = new List<Complex>() { new Complex(-3.108916234, 8.232699459), new Complex(-4.886219567, 6.224985483), new Complex(-5.967528329, 4.384947189), new Complex(-6.615290966, 2.611567921), new Complex(-6.922044905, 0.867665196), new Complex(-6.922044905, 0.867665196), new Complex(-6.615290966, 2.611567921), new Complex(-5.967528329, 4.384947189), new Complex(-4.886219567, 6.224985483), new Complex(-3.108916234, 8.232699459) }; poles = Polynomial.multiply(poles, 1 / 5.022755); break; } return poles; } // fcf is the cutoff frequency in Hz public void lpf(double fcf, int order) { double nfcf = fcf / PcmStreamSource.SampleRate; // normalised corner frequency Debug.Assert(nfcf > 0 && nfcf <= 0.5); // greater than 0 and less than Nyquist List<Complex> poles = getPoles(order); double w1 = 2 * Math.PI * nfcf; ComplexPlane splane = new ComplexPlane(); splane.poles = Polynomial.multiply(poles, w1); splane.zeros = new List<Complex>(); ComplexPlane zplane = splane.MatchedZTransform(); TransferFunction transferfunction = zplane.getTransferFunction(); Coefficients coeffs = transferfunction.getCoefficients(); double gain = transferfunction.getGainAt(Complex.One); // DC Gain // normalise the gain by dividing coeffs.b by gain coeffs.scaleGain(gain); setNumerator(coeffs.b); setDenominator(coeffs.a); } } }
// Cheby1,algorithm in more usual form for (int i = 0; i < order / 2; ++i) { int k = 2 * i + 1 - order; double x = sinhA * Math.Cos(k * Math.PI / (2.0 * (double)order)); double y = coshA * Math.Sin(k * Math.PI / (2.0 * (double)order)); Complex pole = new Complex(x, y); poles.Add(pole); poles.Add(Complex.Conjugate(pole)); }
using System; using System.Diagnostics; using System.Numerics; using System.Collections.Generic; // Hondrou implementation of a Chebyshev2 filter building on the STK framework // // This approach uses the techniques from Tony Fischer at York in mkfilter // http://www-users.cs.york.ac.uk/~fisher/mkfilter/ // and builds on the Java implementation by Christian d'Heureuse // www.source-code.biz, www.inventec.ch/chdh // // The Chebyshev2 algorithm comes from the calculations by Vincent Falco in // his Collection of Useful C++ Classes for DSP // https://github.com/vinniefalco/DSPFilters namespace AgSynth { public class Cheby2 : Iir { // ripple is stopband ripple in this case, but same calculation public List<Complex> getPoles(int order, double ripple) { Debug.Assert(ripple <= 0.0); // ripple must be negative // 10 is correct because we need the square double rip = Math.Pow(10.0, -ripple / 10.0); double eps = Math.Sqrt(rip - 1.0); double a = asinh(1.0 / eps) / (double)order; Debug.Assert(a >= 0.0); double sinhA = -Math.Sinh(a); double coshA = Math.Cosh(a); List<Complex> poles = new List<Complex>(); int k = 1; for (int i = order/2; --i >= 0; k+=2) { double x = sinhA * Math.Cos((k - order) * Math.PI / (2.0 * (double)order)); double y = coshA * Math.Sin((k - order) * Math.PI / (2.0 * (double)order)); double d2 = x * x + y * y; Complex pole = new Complex(x/d2, y/d2); poles.Add(pole); poles.Add(Complex.Conjugate(pole)); } if (order % 2 != 0) //odd { poles.Add(Complex.FromPolarCoordinates(1 / sinhA, 0)); } return poles; } public List<Complex> getZeros(int order, double ripple) { List<Complex> zeros = new List<Complex>(); int k = 1; for (int i = order / 2; --i >= 0; k += 2) { double im = 1 / Math.Cos(k * Math.PI / (2.0 * (double)order)); Complex zero = new Complex(0, im); zeros.Add(zero); zeros.Add(Complex.Conjugate(zero)); } return zeros; } // fcf is the cutoff frequency in Hz public void lpf(double fcf, double ripple, int order) { double nfcf = fcf / PcmStreamSource.SampleRate; // normalised corner frequency Debug.Assert(nfcf > 0 && nfcf <= 0.5); // greater than 0 and less than Nyquist List<Complex> poles = getPoles(order, ripple); List<Complex> zeros = getZeros(order, ripple); // get warped freq double w1 = 2 * Math.PI * Math.Tan(Math.PI * nfcf) / Math.PI; ComplexPlane splane = new ComplexPlane(); splane.poles = Polynomial.multiply(poles, w1); splane.zeros = Polynomial.multiply(zeros, w1); ComplexPlane zplane = splane.BilinearTransform(); TransferFunction transferfunction = zplane.getTransferFunction(); Coefficients coeffs = transferfunction.getCoefficients(); double gain = transferfunction.getGainAt(Complex.One); // DC Gain // normalise the gain by dividing coeffs.b by gain coeffs.scaleGain(gain); setNumerator(coeffs.b); setDenominator(coeffs.a); } } }
using System; using System.Diagnostics; using System.Numerics; using System.Collections.Generic; // Hondrou implementation of a Chebyshev1 filter building on the STK framework // // This approach uses the techniques from Tony Fischer at York in mkfilter // http://www-users.cs.york.ac.uk/~fisher/mkfilter/ // and builds on the Java implementation by Christian d'Heureuse // www.source-code.biz, www.inventec.ch/chdh namespace AgSynth { public class Cheby1 : Iir { private static double asinh(double x) { return Math.Log(x + Math.Sqrt(1.0 + x * x)); } public List<Complex> getPoles(int order, double ripple) { Debug.Assert(ripple <= 0.0); // ripple must be negative double rip = Math.Pow(10.0, -ripple / 10.0); // 10 is correct because we need the square double eps = Math.Sqrt(rip - 1.0); double a = asinh(1.0 / eps) / order; Debug.Assert(y >= 0.0); double sinhY = Math.Sinh(a); double coshY = Math.Cosh(a); Complex[] poles = new Complex[order]; for (int i = 0; i < order; i++) { double theta = (order / 2.0 + 0.5 + i) * Math.PI / order; Complex circle = Complex.FromPolarCoordinates(1, theta); poles[i] = new Complex(circle.Real * sinhY, circle.Imaginary * coshY); } return new List<Complex>(poles); } // the rest of the lpf, hpf, bpf, bsf functions go here } }
setNumerator(coeffs.b); setDenominator(coeffs.a);
// fcf is the cutoff frequency in Hz public void hpf(double fcf, int order) { double nfcf = fcf / PcmStreamSource.SampleRate; // normalised corner frequency Debug.Assert(nfcf > 0 && nfcf <= 0.5); // greater than 0 and less than Nyquist List<Complex> poles = getPoles(order); // get warped freq double w1 = 2 * Math.PI * Math.Tan(Math.PI * nfcf) / Math.PI; ComplexPlane splane = new ComplexPlane(); splane.zeros = new List<Complex>(); splane.poles = new List<Complex>(new Complex[order]); for (int i = 0; i < order; i++) { splane.poles[i] = w1 / poles[i]; splane.zeros.Add(new Complex(0, 0)); } ComplexPlane zplane = splane.BilinearTransform(); TransferFunction transferfunction = zplane.getTransferFunction(); Coefficients coeffs = transferfunction.getCoefficients(); double gain = transferfunction.getGainAt(new Complex(-1,0)); //gain at Nyquist // normalise the gain by dividing coeffs.b by gain coeffs.scaleGain(gain); setNumerator(coeffs.b); setDenominator(coeffs.a); }
// fcf1 and fcf2 are the two cutoff frequencies in Hz. fcf1 < fcf2 public void bpf(double fcf1, double fcf2, int order) { double nfcf1 = fcf1 / PcmStreamSource.SampleRate; // normalised corner frequency double nfcf2 = fcf2 / PcmStreamSource.SampleRate; // normalised corner frequency Debug.Assert(nfcf1 > 0 && nfcf1 <= 0.5); // greater than 0 and less than Nyquist Debug.Assert(nfcf2 > 0 && nfcf2 <= 0.5); // greater than 0 and less than Nyquist Debug.Assert(fcf1 < fcf2); List<Complex> poles = getPoles(order); // get warped freq double w1 = 2 * Math.PI * Math.Tan(Math.PI * nfcf1) / Math.PI; double w2 = 2 * Math.PI * Math.Tan(Math.PI * nfcf2) / Math.PI; double w0 = Math.Sqrt(w1 * w2); double bw = w2 - w1; ComplexPlane splane = new ComplexPlane(); splane.poles = new List<Complex>(new Complex[order * 2]); splane.zeros = new List<Complex>(); for (int i = 0; i < order; i++) { Complex hba = poles[i] * (bw / 2.0); Complex temp = Complex.Sqrt(1 - Complex.Pow(w0 / hba, 2)); splane.poles[i] = hba * (1 + temp); splane.poles[order + i] = hba * (1 - temp); splane.zeros.Add(new Complex(0, 0)); } ComplexPlane zplane = splane.BilinearTransform(); TransferFunction transferfunction = zplane.getTransferFunction(); Coefficients coeffs = transferfunction.getCoefficients(); double centrefreq = (nfcf1 + nfcf2) / 2.0; Complex w = Complex.FromPolarCoordinates(1, 2 * Math.PI * centrefreq); double gain = transferfunction.getGainAt(w); // gain at centre freq // normalise the gain by dividing coeffs.b by gain coeffs.scaleGain(gain); setNumerator(coeffs.b); setDenominator(coeffs.a); }
// fcf1 and fcf2 are the two cutoff frequencies in Hz. fcf1 < fcf2 public void bsf(double fcf1, double fcf2, int order) { double nfcf1 = fcf1 / PcmStreamSource.SampleRate; // normalised corner frequency double nfcf2 = fcf2 / PcmStreamSource.SampleRate; // normalised corner frequency Debug.Assert(nfcf1 > 0 && nfcf1 <= 0.5); // greater than 0 and less than Nyquist Debug.Assert(nfcf2 > 0 && nfcf2 <= 0.5); // greater than 0 and less than Nyquist Debug.Assert(fcf1 < fcf2); List<Complex> poles = getPoles(order); // get warped freq double w1 = 2 * Math.PI * Math.Tan(Math.PI * nfcf1) / Math.PI; double w2 = 2 * Math.PI * Math.Tan(Math.PI * nfcf2) / Math.PI; double w0 = Math.Sqrt(w1 * w2); double bw = w2 - w1; ComplexPlane splane = new ComplexPlane(); splane.poles = new List<Complex>(new Complex[order * 2]); splane.zeros = new List<Complex>(new Complex[order * 2]); for (int i = 0; i < order; i++) { Complex hba = (bw / 2.0) / poles[i]; Complex temp = Complex.Sqrt(1 - Complex.Pow(w0 / hba, 2)); splane.poles[i] = hba * (1 + temp); splane.poles[order + i] = hba * (1 - temp); // 2n zeros at +-w0 splane.zeros[i] = new Complex(0, w0); splane.zeros[order + i] = new Complex(0, -w0); } ComplexPlane zplane = splane.BilinearTransform(); TransferFunction transferfunction = zplane.getTransferFunction(); Coefficients coeffs = transferfunction.getCoefficients(); double dcgain = transferfunction.getGainAt(Complex.One); // gain at dc double hfgain = transferfunction.getGainAt(new Complex(-1,0)); // gain at hf double gain = Math.Sqrt(dcgain * hfgain); // normalise the gain by dividing coeffs.b by gain coeffs.scaleGain(gain); setNumerator(coeffs.b); setDenominator(coeffs.a); }
using System; using System.Diagnostics; using System.Numerics; using System.Collections.Generic; // Hondrou implementation of a Butterworth filter building on the STK framework // // This approach uses the techniques from Tony Fischer at York in mkfilter // http://www-users.cs.york.ac.uk/~fisher/mkfilter/ // and builds on the Java implementation by Christian d'Heureuse // www.source-code.biz, www.inventec.ch/chdh namespace AgSynth { public class Butter : Iir { } }
public List<Complex> getPoles(int order) { Complex[] poles = new Complex[order]; for (int i = 0; i < order; i++) { double theta = (order / 2.0 + 0.5 + i) * Math.PI / order; poles[i] = Complex.FromPolarCoordinates(1, theta); } return new List<Complex>(poles); }
private void Dump(string message, List<Complex> cs, bool polar) { String text = message; foreach (Complex c in cs) { if (polar) { text += String.Format("[r={0:0.00} p={1:0.00}] ", c.Magnitude, c.Phase); } else { text += String.Format("{0:0.00}+i{1:0.00} ", c.Real, c.Magnitude); } } Debug.WriteLine(text); } private void test() { Butter b = new Butter(); Dump("n=1 ",b.getPoles(1),false); Dump("n=2 ",b.getPoles(2),false); Dump("n=3 ",b.getPoles(3),false); Dump("n=4 ",b.getPoles(4),false); }
// fcf is the cutoff frequency in Hz public void lpf(double fcf, int order) { double nfcf = fcf / PcmStreamSource.SampleRate; // normalised corner frequency Debug.Assert(nfcf > 0 && nfcf <= 0.5); // greater than 0 and less than Nyquist List<Complex> poles = getPoles(order); // get warped freq double w1 = 2 * Math.PI * Math.Tan(Math.PI * nfcf) / Math.PI; List<Complex> warpedpoles = Polynomial.multiply(poles, w1); // ..... more to come
public class Polynomial { public static List<Complex> multiply(List<Complex> a, double d) { Complex[] result = new Complex[a.Count]; for (int i = 0; i < a.Count; i++) { result[i] = a[i] * d; } return new List<Complex>(result); } }
public class ComplexPlane { public List<Complex> poles; public List<Complex> zeros; }
// get warped freq double w1 = 2 * Math.PI * Math.Tan(Math.PI * nfcf) / Math.PI; ComplexPlane splane = new ComplexPlane(); splane.poles = Polynomial.multiply(poles,w1); splane.zeros = new List<Complex>(); ComplexPlane zplane = splane.BilinearTransform();
public ComplexPlane BilinearTransform() { ComplexPlane zplane = new ComplexPlane(); zplane.poles = Polynomial.BilinearTransform(poles); List<Complex> a = Polynomial.BilinearTransform(zeros); // extend zeros with -1 to the number of poles zplane.zeros = Polynomial.extend(a, poles.Count, new Complex(-1,0)); return zplane; }
public static List<Complex> BilinearTransform(List<Complex> a) { Complex[] a2 = new Complex[a.Count]; for (int i = 0; i < a.Count; i++) { a2[i] = doBilinearTransform(a[i]); } return new List<Complex>(a2); } private static Complex doBilinearTransform(Complex x) { return ((2.0 + x) / (2.0 - x)); }
public static List<Complex> extend(List<Complex> a, int n, Complex fill) { List<Complex> result = null; if (a.Count >= n) { result = a; } else { Complex[] a2 = new Complex[n]; for (int i = 0; i < a.Count; i++) { a2[i] = a[i]; } for (int i = a.Count; i < n; i++) { a2[i] = fill; } result = new List<Complex>(a2); } return result; }
public class TransferFunction { public List<double> numerator; public List<double> denominator; }
public TransferFunction getTransferFunction() { List<Complex> numeratorComplexCoeff = Polynomial.expand(zeros); List<Complex> denominatorComplexCoeff = Polynomial.expand(poles); TransferFunction tf = new TransferFunction(); double eps = 1e-10; tf.numerator = Polynomial.toDouble(numeratorComplexCoeff, eps); tf.denominator = Polynomial.toDouble(denominatorComplexCoeff, eps); return tf; }
public static List<Complex> expand(List<Complex> zeros) { List<Complex> result = null; int n = zeros.Count; if (n == 0) { result = new List<Complex>() { Complex.One }; } else { List<Complex> a = new List<Complex>() { Complex.One, Complex.Negate(zeros[0]) }; for (int i = 1; i < n; i++) { List<Complex> a2 = new List<Complex> { Complex.One, Complex.Negate(zeros[i]) }; a = multiply(a, a2); } result = a; } return result; }
public static List<Complex> multiply(List<Complex> a1, List<Complex> a2) { int n1 = a1.Count - 1; int n2 = a2.Count - 1; int n3 = n1 + n2; //List<Complex> a3 = new List<Complex>(n3+1); Complex[] a3 = new Complex[n3 + 1]; for (int i = 0; i <= n3; i++) { Complex t = Complex.Zero; int p1 = Math.Max(0, i - n2); int p2 = Math.Min(n1, i); for (int j = p1; j <= p2; j++) { Complex tmul = a1[n1 - j] * a2[n2 - i + j]; t = t + tmul; } a3[n3 - i] = t; } return new List<Complex>(a3); }
Dump("n=1 ", Polynomial.expand(b.getPoles(1)), true); Dump("n=2 ", Polynomial.expand(b.getPoles(2)), true); Dump("n=3 ", Polynomial.expand(b.getPoles(3)), true); Dump("n=4 ", Polynomial.expand(b.getPoles(4)), true);
// Converts complex array into real double array, verifies that all imaginary parts // are equal or below eps</code. public static List<double> toDouble(List<Complex> a, double eps) { double[] a2 = new double[a.Count]; for (int i = 0; i < a.Count; i++) { double absIm = Math.Abs(a[i].Imaginary); Debug.Assert(absIm < eps && absIm < Math.Abs(a[i].Real * eps)); a2[i] = a[i].Real; } return new List<double>(a2); }
public double getGainAt(Complex w) { Debug.Assert(numerator.Count > 0); Complex sumn = new Complex(numerator[0], 0); for (int i = 1; i < numerator.Count; i++) { sumn = (sumn * w) + numerator[i]; } Debug.Assert(numerator.Count > 0); Complex sumd = new Complex(denominator[0], 0); for (int i = 1; i < denominator.Count; i++) { sumd = (sumd * w) + denominator[i]; } return (sumn / sumd).Magnitude; }
public class Coefficients { public List<double> a; public List<double> b; }
public Coefficients getCoefficients() { double scale = denominator[0]; Coefficients coeffs = new Coefficients(); coeffs.a = new List<double>(); coeffs.b = new List<double>(); coeffs.a.Add(1.0); // a[0] for (int i = 1; i < denominator.Count; i++) { coeffs.a.Add(denominator[i] / scale); } for (int i = 0; i < numerator.Count; i++) { coeffs.b.Add(numerator[i] / scale); } return coeffs; }
public class Coefficients { public List<double> a; public List<double> b; public void scaleGain(double gain) { for (int i = 0; i < b.Count; i++) { b[i] = b[i] / gain; } } }
// fcf is the cutoff frequency in Hz public void lpf(double fcf, int order) { double nfcf = fcf / PcmStreamSource.SampleRate; // normalised corner frequency Debug.Assert(nfcf > 0 && nfcf <= 0.5); // greater than 0 and less than Nyquist List<Complex> poles = getPoles(order); // get warped freq double w1 = 2 * Math.PI * Math.Tan(Math.PI * nfcf) / Math.PI; ComplexPlane splane = new ComplexPlane(); splane.poles = Polynomial.multiply(poles,w1); splane.zeros = new List<Complex>(); ComplexPlane zplane = splane.BilinearTransform(); TransferFunction transferfunction = zplane.getTransferFunction(); Coefficients coeffs = transferfunction.getCoefficients(); double gain = transferfunction.getGainAt(Complex.One); // DC Gain // normalise the gain by dividing coeffs.b by gain coeffs.scaleGain(gain); }
Butter b = new Butter(); b.lpf(10000, 2); b.lpf(10000, 3); b.lpf(10000, 4);