1 package org.lsst.ccs.utilities.dsp;
2
3
4
5
6
7
8 public class FilterFactory {
9
10 public enum FilterType {
11 LOW_PASS, BAND_PASS, HIGH_PASS
12 };
13
14 public static FIRFilter getHighPassFIR(double rate, double attenuation,
15 double f1) {
16 return getFIRFilter(rate, attenuation, f1, -1, FilterType.HIGH_PASS);
17 }
18
19 public static FIRFilter getBandPassFIR(double rate, double attenuation,
20 double f1, double f2) {
21 return getFIRFilter(rate, attenuation, f1, f2, FilterType.BAND_PASS);
22 }
23
24 public static FIRFilter getLowPassFIR(double rate, double attenuation,
25 double f2) {
26 return getFIRFilter(rate, attenuation, -1, f2, FilterType.LOW_PASS);
27 }
28
29 public static FIRFilter getFIRFilter(double rate, double attenuation,
30 double f1, double f2, FilterType type) {
31 FilterSpecs spec = new FilterSpecs();
32 spec.setFN(rate / 2).setAttenuation(attenuation).setLowFrequency(f1)
33 .setHighFrequency(f2).setType(type);
34 if (f1 > 0) {
35 spec.setTransitionBandwidth(f1 / 5);
36 } else {
37 spec.setTransitionBandwidth(f2 / 5);
38 }
39 return getFIRFilter(spec);
40 }
41
42 public static FIRFilter getFIRFilter(FilterSpecs spec) {
43 if (spec.order < 1) {
44 spec.order = estimatedFIROrder(spec);
45 }
46
47 double alpha = 0;
48 if (spec.getAttenuation() >= 50.0) {
49 alpha = 0.1102 * (spec.getAttenuation() - 8.7);
50 } else if (spec.getAttenuation() > 21.0) {
51 alpha = 0.5842
52 * Math.exp(0.4 * Math.log(spec.getAttenuation() - 21.0))
53 + 0.07886 * (spec.getAttenuation() - 21.0);
54 }
55 if (spec.getAttenuation() <= 21.0) {
56 alpha = 0.0;
57 }
58
59 double I0alpha = I0(alpha);
60 int m = spec.order / 2;
61 double[] win = new double[m + 1];
62 for (int n = 1; n <= m; n++) {
63 win[n] = I0(alpha * Math.sqrt(1.0 - sqr((double) n / m))) / I0alpha;
64 }
65 double w0 = 0.0;
66 double w1 = 0.0;
67 switch (spec.type) {
68 case LOW_PASS:
69 w0 = 0.0;
70 w1 = Math.PI
71 * (spec.getHighFrequency() + 0.5 * spec
72 .getTransitionBandwidth()) / spec.fN;
73 break;
74 case HIGH_PASS:
75 w0 = Math.PI;
76 w1 = Math.PI
77 * (1.0 - (spec.getLowFrequency() - 0.5 * spec
78 .getTransitionBandwidth())
79 / spec.fN);
80 break;
81 case BAND_PASS:
82 w0 = 0.5 * Math.PI
83 * (spec.getLowFrequency() + spec.getHighFrequency())
84 / spec.fN;
85 w1 = 0.5
86 * Math.PI
87 * (spec.getHighFrequency() - spec.getLowFrequency() + spec
88 .getTransitionBandwidth()) / spec.fN;
89 break;
90 }
91
92 double[] a = new double[spec.order + 1];
93 a[0] = w1 / Math.PI;
94 for (int n = 1; n <= m; n++) {
95 a[n] = Math.sin(n * w1) * Math.cos(n * w0) * win[n] / (n * Math.PI);
96 }
97
98 for (int n = m + 1; n <= spec.order; n++) {
99 a[n] = a[n - m];
100 }
101 for (int n = 0; n <= m - 1; n++) {
102 a[n] = a[spec.order - n];
103 }
104 a[m] = w1 / Math.PI;
105
106
107 double g = 0;
108 for (int i = 1; i < spec.order + 1; i++) {
109 g += a[i];
110 }
111 for (int i = 1; i < spec.order + 1; i++) {
112 a[i] /= g;
113 }
114
115 return new FIRFilter(a);
116 }
117
118 private static int estimatedFIROrder(FilterSpecs spec) {
119 int o = 2 * (int) ((spec.getAttenuation() - 7.95)
120 / (14.36 * spec.getTransitionBandwidth() / spec.getFN()) + 1.0);
121 return o;
122 }
123
124 private static final double sqr(double x) {
125 return x * x;
126 }
127
128
129
130
131 private static double I0(double x) {
132 double eps = 1.0e-6;
133 double fact = 1.0;
134 double x2 = 0.5 * x;
135 double p = x2;
136 double t = p * p;
137 double s = 1.0 + t;
138 for (int k = 2; t > eps; k++) {
139 p *= x2;
140 fact *= k;
141 t = sqr(p / fact);
142 s += t;
143 }
144 return s;
145 }
146
147 public static final class FilterSpecs {
148 FilterType type = FilterType.LOW_PASS;
149
150 int order = -1;
151
152 double lowFrequency = 0.0f;
153
154 double highFrequency = 10000.0f;
155
156 double transitionBandwidth = 5000.0f;
157
158 double attenuation = 60.0f;
159
160 double fN = 150;
161
162 public double getAttenuation() {
163 return attenuation;
164 }
165
166 public FilterSpecs setAttenuation(double attenuation) {
167 this.attenuation = attenuation;
168 return this;
169 }
170
171 public double getFN() {
172 return fN;
173 }
174
175 public FilterSpecs setFN(double fn) {
176 fN = fn;
177 return this;
178 }
179
180 public double getHighFrequency() {
181 return highFrequency;
182 }
183
184 public FilterSpecs setHighFrequency(double highFrequency) {
185 this.highFrequency = highFrequency;
186 return this;
187 }
188
189 public double getLowFrequency() {
190 return lowFrequency;
191 }
192
193 public FilterSpecs setLowFrequency(double lowFrequency) {
194 this.lowFrequency = lowFrequency;
195 return this;
196 }
197
198 public int getOrder() {
199 return order;
200 }
201
202 public FilterSpecs setOrder(int order) {
203 this.order = order;
204 return this;
205 }
206
207 public double getTransitionBandwidth() {
208 return transitionBandwidth;
209 }
210
211 public FilterSpecs setTransitionBandwidth(double transitionBandwidth) {
212 this.transitionBandwidth = transitionBandwidth;
213 return this;
214 }
215
216 public FilterType getType() {
217 return type;
218 }
219
220 public FilterSpecs setType(FilterType type) {
221 this.type = type;
222 return this;
223 }
224
225 }
226
227 public static void main(String[] args) {
228 FIRFilter f = getHighPassFIR(300, 30, 60);
229 f.print();
230 double[] sig = new double[1000];
231 double[] sigf = new double[1000];
232 for (int i = 0; i < 1000; i++) {
233 sig[i] = Math.cos(2 * Math.PI * 10 * (i / 300.))
234 + Math.cos(2 * Math.PI * 140 * (i / 300));
235 sigf[i] = f.apply(sig[i]);
236 }
237 for (int i = 0; i < 980; i++) {
238 System.out.println(sig[i] + " " + sigf[i + 20] + " "
239 + Math.cos(2 * Math.PI * 10 * (i / 300.)));
240 }
241
242 }
243
244 }