2
// mkfilter-derived code
3
// ---------------------
5
// Copyright (c) 2002-2004 Jim Peters <http://uazu.net/>. This
6
// file is released under the GNU Lesser General Public License
7
// (LGPL) version 2.1 as published by the Free Software
8
// Foundation. See the file COPYING_LIB for details, or visit
9
// <http://www.fsf.org/licenses/licenses.html>.
11
// This is all code derived from 'mkfilter' by Tony Fisher of the
12
// University of York. I've rewritten it all in C, and given it
13
// a thorough overhaul, so there is actually none of his code
14
// here any more, but it is all still very strongly based on the
15
// algorithms and techniques that he used in 'mkfilter'.
17
// For those who didn't hear, Tony Fisher died in February 2000
18
// at the age of 43. See his web-site for information and a
21
// http://www-users.cs.york.ac.uk/~fisher/
22
// http://www-users.cs.york.ac.uk/~fisher/tribute.html
24
// The original C++ sources and the rest of the mkfilter tool-set
25
// are still available from his site:
27
// http://www-users.cs.york.ac.uk/~fisher/mkfilter/
30
// I've made a number of improvements and changes whilst
31
// rewriting the code in C. For example, I halved the
32
// calculations required in designing the filters by storing only
33
// one complex pole/zero out of each conjugate pair. This also
34
// made it much easier to output the filter as a list of
35
// sub-filters without lots of searching around to match up
36
// conjugate pairs later on. Outputting as a list of subfilters
37
// permits greater accuracy in calculation of the response, and
38
// also in the execution of the final filter. Also, some FIR
39
// coefficients can be marked as 'constant', allowing optimised
40
// routines to be generated for whole classes of filters, with
41
// just the variable coefficients filled in at run-time.
43
// On the down-side, complex numbers are not portably available
44
// in C before C99, so complex calculations here are done on
45
// double[] arrays with inline functions, which ends up looking
46
// more like assembly language than C. Never mind.
53
// Tony Fisher released his software on his University of York
54
// pages for free use and free download. The software itself has
55
// no licence terms attached, nor copyright messages, just the
56
// author's name, E-mail address and date. Nor are there any
57
// licence terms indicated on the website. I understand that
58
// under the Berne convention copyright does not have to be
59
// claimed explicitly, so these are in fact copyright files by
60
// legal default. However, the intention was obviously that
61
// these files should be used by others.
63
// None of this really helps, though, if we're going to try to be
64
// 100% legally correct, so I wrote to Anthony Moulds who is the
65
// contact name on Tony Fisher's pages now. I explained what I
66
// planned to do with the code, and he answered as follows:
68
// (Note that I was planning to use it 'as-is' at that time,
69
// rather than rewrite it as I have done now)
71
// > To: "Jim Peters" <jim@uazu.net>
72
// > From: "Anthony Moulds" <anthony@cs.york.ac.uk>
73
// > Subject: RE: mkfilter source
74
// > Date: Tue, 29 Oct 2002 15:30:19 -0000
78
// > Thanks for your email.
80
// > The University will be happy to let you use Dr Fisher's mkfilter
81
// > code since your intention is not to profit financially from his work.
83
// > It would be nice if in some way you could acknowledge his contribution.
85
// > Best wishes and good luck with your work,
88
// > Senior Experimental Officer,
89
// > Computer Science Department, University of York,
90
// > York, England, UK. Tel: 44(0)1904 434758 Fax: 44(0)19042767
91
// > ============================================================
94
// > > -----Original Message-----
95
// > > From: Jim Peters [mailto:jim@uazu.net]
96
// > > Sent: Monday, October 28, 2002 12:36 PM
97
// > > To: anthony@cs.york.ac.uk
98
// > > Subject: mkfilter source
101
// > > I'm very sorry to hear (rather late, I know) that Tony Fisher died --
102
// > > I've always gone straight to the filter page, rather than through his
103
// > > home page. I hope his work remains available for the future.
105
// > > Anyway, the reason I'm writing is to clarify the status of the
106
// > > mkfilter source code. Because copyright is not claimed on the web
107
// > > page nor in the source distribution, I guess that Tony's intention was
108
// > > that this code should be in the public domain. However, I would like
109
// > > to check this now to avoid complications later.
111
// > > I am using his code, modified, to provide a library of filter-design
112
// > > routines for a GPL'd filter design app, which is not yet released.
113
// > > The library could also be used standalone, permitting apps to design
114
// > > filters at run-time rather than using hard-coded compile-time filters.
115
// > > My interest in filters is as a part of my work on the OpenEEG project
117
// So this looks pretty clear to me. I am not planning to profit
118
// from the work, so everything is fine with the University. I
119
// guess others might profit from the work, indirectly, as with
120
// any free software release, but so long as I don't, we're fine.
122
// I hope this is watertight enough for Debian/etc. Otherwise
123
// I'll have to go back to Anthony Moulds for clarification.
125
// Even though there is no code cut-and-pasted from 'mkfilter'
126
// here, it is all very obviously based on that code, so it
127
// probably counts as a derived work -- although as ever "I Am
135
#define INF (1.0/0.0)
138
#define TWOPI (2*M_PI)
142
// Complex square root: aa= aa^0.5
147
return aa <= 0.0 ? 0.0 : sqrt(aa);
150
// 'csqrt' clashes with builtin in GCC 4, so call it 'c_sqrt'
153
double mag= hypot(aa[0], aa[1]);
154
double rr= my_sqrt((mag + aa[0]) * 0.5);
155
double ii= my_sqrt((mag - aa[0]) * 0.5);
156
if (aa[1] < 0.0) ii= -ii;
162
// Complex imaginary exponent: aa= e^i.theta
166
cexpj(double *aa, double theta) {
172
// Complex exponent: aa= e^aa
175
// 'cexp' clashes with builtin in GCC 4, so call it 'c_exp'
178
double mag= exp(aa[0]);
179
aa[0]= mag * cos(aa[1]);
180
aa[1]= mag * sin(aa[1]);
184
// Global temp buffer for generating filters. *NOT THREAD SAFE*
186
// Note that the poles and zeros are stored in a strange way.
187
// Rather than storing both a pole (or zero) and its complex
188
// conjugate, I'm storing just one of the pair. Also, for real
189
// poles, I'm not storing the imaginary part (which is zero).
190
// This results in a list of numbers exactly half the length you
191
// might otherwise expect. However, since some of these numbers
192
// are in pairs, and some are single, we need a separate flag
193
// array to indicate which is which. poltyp[] serves this
194
// purpose. An entry is 1 if the corresponding offset is a real
195
// pole, or 2 if it is the first of a pair of values making up a
196
// complex pole. The second value of the pair has an entry of 0
197
// attached. (Similarly for zeros in zertyp[])
202
static int n_pol; // Number of poles
203
static double pol[MAXPZ]; // Pole values (see above)
204
static char poltyp[MAXPZ]; // Pole value types: 1 real, 2 first of complex pair, 0 second
205
static int n_zer; // Same for zeros ...
206
static double zer[MAXPZ];
207
static char zertyp[MAXPZ];
211
// Pre-warp a frequency
215
prewarp(double val) {
216
return tan(val * M_PI) / M_PI;
221
// Bessel poles; final one is a real value for odd numbers of
225
static double bessel_1[]= {
229
static double bessel_2[]= {
230
-1.10160133059e+00, 6.36009824757e-01,
233
static double bessel_3[]= {
234
-1.04740916101e+00, 9.99264436281e-01,
238
static double bessel_4[]= {
239
-9.95208764350e-01, 1.25710573945e+00,
240
-1.37006783055e+00, 4.10249717494e-01,
243
static double bessel_5[]= {
244
-9.57676548563e-01, 1.47112432073e+00,
245
-1.38087732586e+00, 7.17909587627e-01,
249
static double bessel_6[]= {
250
-9.30656522947e-01, 1.66186326894e+00,
251
-1.38185809760e+00, 9.71471890712e-01,
252
-1.57149040362e+00, 3.20896374221e-01,
255
static double bessel_7[]= {
256
-9.09867780623e-01, 1.83645135304e+00,
257
-1.37890321680e+00, 1.19156677780e+00,
258
-1.61203876622e+00, 5.89244506931e-01,
262
static double bessel_8[]= {
263
-8.92869718847e-01, 1.99832584364e+00,
264
-1.37384121764e+00, 1.38835657588e+00,
265
-1.63693941813e+00, 8.22795625139e-01,
266
-1.75740840040e+00, 2.72867575103e-01,
269
static double bessel_9[]= {
270
-8.78399276161e-01, 2.14980052431e+00,
271
-1.36758830979e+00, 1.56773371224e+00,
272
-1.65239648458e+00, 1.03138956698e+00,
273
-1.80717053496e+00, 5.12383730575e-01,
277
static double bessel_10[]= {
278
-8.65756901707e-01, 2.29260483098e+00,
279
-1.36069227838e+00, 1.73350574267e+00,
280
-1.66181024140e+00, 1.22110021857e+00,
281
-1.84219624443e+00, 7.27257597722e-01,
282
-1.92761969145e+00, 2.41623471082e-01,
285
static double *bessel_poles[10]= {
286
bessel_1, bessel_2, bessel_3, bessel_4, bessel_5,
287
bessel_6, bessel_7, bessel_8, bessel_9, bessel_10
291
// Generate Bessel poles for the given order.
298
if (order > 10) error("Maximum Bessel order is 10");
300
memcpy(pol, bessel_poles[order-1], n_pol * sizeof(double));
302
for (a= 0; a<order-1; ) {
311
// Generate Butterworth poles for the given order. These are
312
// regularly-spaced points on the unit circle to the left of the
317
butterworth(int order) {
320
error("Maximum butterworth/chebyshev order is %d", MAXPZ);
322
for (a= 0; a<order-1; a += 2) {
325
cexpj(pol+a, M_PI - (order-a-1) * 0.5 * M_PI / order);
334
// Generate Chebyshev poles for the given order and ripple.
338
chebyshev(int order, double ripple) {
344
if (ripple >= 0.0) error("Chebyshev ripple in dB should be -ve");
346
eps= sqrt(-1.0 + pow(10.0, -0.1 * ripple));
347
y= asinh(1.0 / eps) / order;
348
if (y <= 0.0) error("Internal error; chebyshev y-value <= 0.0: %g", y);
352
for (a= 0; a<n_pol; ) {
364
// Adjust raw poles to LP filter
368
lowpass(double freq) {
373
for (a= 0; a<n_pol; a++)
378
for (a= 0; a<n_zer; a++) {
385
// Adjust raw poles to HP filter
389
highpass(double freq) {
394
for (a= 0; a<n_pol; ) {
395
if (poltyp[a] == 1) {
396
pol[a]= freq / pol[a];
407
for (a= 0; a<n_zer; a++) {
414
// Adjust raw poles to BP filter. The number of poles is
419
bandpass(double freq1, double freq2) {
420
double w0= TWOPI * sqrt(freq1*freq2);
421
double bw= 0.5 * TWOPI * (freq2-freq1);
424
if (n_pol * 2 > MAXPZ)
425
error("Maximum order for bandpass filters is %d", MAXPZ/2);
427
// Run through the list backwards, expanding as we go
428
for (a= n_pol, b= n_pol*2; a>0; ) {
430
// temp= c_sqrt(1.0 - square(w0 / hba));
431
// pole1= hba * (1.0 + temp);
432
// pole2= hba * (1.0 - temp);
434
if (poltyp[a-1] == 1) {
437
poltyp[b]= 2; poltyp[b+1]= 0;
439
cassz(pol+b, 1.0 - (w0 / hba) * (w0 / hba), 0.0);
441
caddz(pol+b, 1.0, 0.0);
443
} else { // Assume poltyp[] data is valid
446
poltyp[b]= 2; poltyp[b+1]= 0;
447
poltyp[b+2]= 2; poltyp[b+3]= 0;
455
caddz(pol+b, 1.0, 0.0);
458
cass(pol+b+2, pol+b);
468
for (a= 0; a<n_zer; a++) {
470
zer[a]= (a<n_zer/2) ? 0.0 : -INF;
475
// Adjust raw poles to BS filter. The number of poles is
480
bandstop(double freq1, double freq2) {
481
double w0= TWOPI * sqrt(freq1*freq2);
482
double bw= 0.5 * TWOPI * (freq2-freq1);
485
if (n_pol * 2 > MAXPZ)
486
error("Maximum order for bandstop filters is %d", MAXPZ/2);
488
// Run through the list backwards, expanding as we go
489
for (a= n_pol, b= n_pol*2; a>0; ) {
491
// temp= c_sqrt(1.0 - square(w0 / hba));
492
// pole1= hba * (1.0 + temp);
493
// pole2= hba * (1.0 - temp);
495
if (poltyp[a-1] == 1) {
498
poltyp[b]= 2; poltyp[b+1]= 0;
500
cassz(pol+b, 1.0 - (w0 / hba) * (w0 / hba), 0.0);
502
caddz(pol+b, 1.0, 0.0);
504
} else { // Assume poltyp[] data is valid
507
poltyp[b]= 2; poltyp[b+1]= 0;
508
poltyp[b+2]= 2; poltyp[b+3]= 0;
517
caddz(pol+b, 1.0, 0.0);
520
cass(pol+b+2, pol+b);
530
for (a= 0; a<n_zer; a+=2) {
531
zertyp[a]= 2; zertyp[a+1]= 0;
532
zer[a]= 0.0; zer[a+1]= w0;
537
// Convert list of poles+zeros from S to Z using bilinear
544
for (a= 0; a<n_pol; ) {
545
// Calculate (2 + val) / (2 - val)
546
if (poltyp[a] == 1) {
550
pol[a]= (2 + pol[a]) / (2 - pol[a]);
562
for (a= 0; a<n_zer; ) {
563
// Calculate (2 + val) / (2 - val)
564
if (zertyp[a] == 1) {
568
zer[a]= (2 + zer[a]) / (2 - zer[a]);
583
// Convert S to Z using matched-Z transform
590
for (a= 0; a<n_pol; ) {
591
// Calculate cexp(val)
592
if (poltyp[a] == 1) {
604
for (a= 0; a<n_zer; ) {
605
// Calculate cexp(val)
606
if (zertyp[a] == 1) {
620
// Generate a FidFilter for the current set of poles and zeros.
621
// The given gain is inserted at the start of the FidFilter as a
622
// one-coefficient FIR filter. This is positioned to be easily
623
// adjusted later to correct the filter gain.
625
// 'cbm' should be a bitmap indicating which FIR coefficients are
626
// constants for this filter type. Normal values are ~0 for all
627
// constant, or 0 for none constant, or some other bitmask for a
628
// mixture. Filters generated with lowpass(), highpass() and
629
// bandpass() above should pass ~0, but bandstop() requires 0x5.
631
// This routine requires that any lone real poles/zeros are at
632
// the end of the list. All other poles/zeros are handled in
633
// pairs (whether pairs of real poles/zeros, or conjugate pairs).
637
z2fidfilter(double gain, int cbm) {
643
n_head= 1 + n_pol + n_zer; // Worst case: gain + 2-element IIR/FIR
644
n_val= 1 + 2 * (n_pol+n_zer); // for each pole/zero
646
rv= ff= FFALLOC(n_head, n_val);
653
// Output as much as possible as 2x2 IIR/FIR filters
654
for (a= 0; a <= n_pol-2 && a <= n_zer-2; a += 2) {
655
// Look for a pair of values for an IIR
656
if (poltyp[a] == 1 && poltyp[a+1] == 1) {
661
ff->val[1]= -(pol[a] + pol[a+1]);
662
ff->val[2]= pol[a] * pol[a+1];
664
} else if (poltyp[a] == 2) {
665
// A complex value and its conjugate pair
669
ff->val[1]= -2 * pol[a];
670
ff->val[2]= pol[a] * pol[a] + pol[a+1] * pol[a+1];
672
} else error("Internal error -- bad poltyp[] values for z2fidfilter()");
674
// Look for a pair of values for an FIR
675
if (zertyp[a] == 1 && zertyp[a+1] == 1) {
677
// Skip if constant and 0/0
678
if (!cbm || zer[a] != 0.0 || zer[a+1] != 0.0) {
683
ff->val[1]= -(zer[a] + zer[a+1]);
684
ff->val[2]= zer[a] * zer[a+1];
687
} else if (zertyp[a] == 2) {
688
// A complex value and its conjugate pair
689
// Skip if constant and 0/0
690
if (!cbm || zer[a] != 0.0 || zer[a+1] != 0.0) {
695
ff->val[1]= -2 * zer[a];
696
ff->val[2]= zer[a] * zer[a] + zer[a+1] * zer[a+1];
699
} else error("Internal error -- bad zertyp[] values");
702
// Clear up any remaining bits and pieces. Should only be a 1x1
704
if (n_pol-a == 0 && n_zer-a == 0)
706
else if (n_pol-a == 1 && n_zer-a == 1) {
707
if (poltyp[a] != 1 || zertyp[a] != 1)
708
error("Internal error; bad poltyp or zertyp for final pole/zero");
715
// Skip FIR if it is constant and zero
716
if (!cbm || zer[a] != 0.0) {
725
error("Internal error: unexpected poles/zeros at end of list");
732
rv= realloc(rv, ((char*)ff)-((char*)rv));
733
if (!rv) error("Out of memory");
738
// Setup poles/zeros for a band-pass resonator. 'qfact' gives
739
// the Q-factor; 0 is a special value indicating +infinity,
740
// giving an oscillator.
744
bandpass_res(double freq, double qfact) {
746
double th0, th1, th2;
747
double theta= freq * TWOPI;
749
double tmp1[2], tmp2[2], tmp3[2], tmp4[2];
753
poltyp[0]= 2; poltyp[1]= 0;
755
zertyp[0]= 1; zertyp[1]= 1;
756
zer[0]= 1; zer[1]= -1;
763
// Do a full binary search, rather than seeding it as Tony Fisher does
765
mag= exp(-theta / (2.0 * qfact));
767
for (cnt= 60; cnt > 0; cnt--) {
768
th1= 0.5 * (th0 + th2);
772
// Evaluate response of filter for Z= val
773
memcpy(tmp1, val, 2*sizeof(double));
774
memcpy(tmp2, val, 2*sizeof(double));
775
memcpy(tmp3, val, 2*sizeof(double));
776
memcpy(tmp4, val, 2*sizeof(double));
780
csub(tmp3, pol); cconj(pol);
781
csub(tmp4, pol); cconj(pol);
785
if (fabs(tmp1[1] / tmp1[0]) < 1e-10) break;
787
//printf("%-24.16g%-24.16g -> %-24.16g%-24.16g\n", th0, th2, tmp1[0], tmp1[1]);
789
if (tmp1[1] > 0.0) th2= th1;
793
if (cnt <= 0) fprintf(stderr, "Resonator binary search failed to converge");
797
// Setup poles/zeros for a bandstop resonator
801
bandstop_res(double freq, double qfact) {
802
bandpass_res(freq, qfact);
803
zertyp[0]= 2; zertyp[1]= 0;
804
cexpj(zer, TWOPI * freq);
808
// Setup poles/zeros for an allpass resonator
812
allpass_res(double freq, double qfact) {
813
bandpass_res(freq, qfact);
814
zertyp[0]= 2; zertyp[1]= 0;
815
memcpy(zer, pol, 2*sizeof(double));
816
cmulr(zer, 1.0 / (zer[0]*zer[0] + zer[1]*zer[1]));
820
// Setup poles/zeros for a proportional-integral filter
824
prop_integral(double freq) {
830
zer[0]= -TWOPI * freq;