View Javadoc

1   package org.lsst.ccs.utilities.dsp;
2   
3   /**
4    * 
5    * @author aubourg
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  		// estimate Kaiser window parameter (alpha):
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  		// window function values
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  		// filter coefficients (NB not normalised to unit maximum gain)
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  		// shift impulse response to make filter causal
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 		// Normalize
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 		// System.out.println("Filter designed") ;
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 	 * Calculate the zero order Bessel function of the first kind
130 	 */
131 	private static double I0(double x) {
132 		double eps = 1.0e-6; // accuracy parameter
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; // estimated by design()
151 
152 		double lowFrequency = 0.0f; // low frequency
153 
154 		double highFrequency = 10000.0f; // high frequency
155 
156 		double transitionBandwidth = 5000.0f; // transition bandwidth
157 
158 		double attenuation = 60.0f;
159 
160 		double fN = 150; // Nyquist, rate/2
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 }