-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
low_pass_filter.h
414 lines (376 loc) · 13.8 KB
/
low_pass_filter.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/*
* Copyright (C) 2013 Gautier Hattenberger
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/** @file filters/low_pass_filter.h
* @brief Simple first order low pass filter with bilinear transform
*
*/
#ifndef LOW_PASS_FILTER_H
#define LOW_PASS_FILTER_H
#include "std.h"
#define INT32_FILT_FRAC 8
/** First order low pass filter structure.
*
* using bilinear z transform
*/
struct FirstOrderLowPass {
float time_const;
float last_in;
float last_out;
};
/** Init first order low pass filter.
*
* Laplace transform in continious time:
* 1
* H(s) = ---------
* 1 + tau*s
*
* @param filter first order low pass filter structure
* @param tau time constant of the first order low pass filter
* @param sample_time sampling period of the signal
* @param value initial value of the filter
*/
static inline void init_first_order_low_pass(struct FirstOrderLowPass * filter, float tau, float sample_time, float value) {
filter->last_in = value;
filter->last_out = value;
filter->time_const = 2.*tau/sample_time;
}
/** Update first order low pass filter state with a new value.
*
* @param filter first order low pass filter structure
* @param value new input value of the filter
* @return new filtered value
*/
static inline float update_first_order_low_pass(struct FirstOrderLowPass * filter, float value) {
float out = (value + filter->last_in + (filter->time_const - 1.) * filter->last_out) / (1. + filter->time_const);
filter->last_in = value;
filter->last_out = out;
return out;
}
/** Get current value of the first order low pass filter.
*
* @param filter first order low pass filter structure
* @return current value of the filter
*/
static inline float get_first_order_low_pass(struct FirstOrderLowPass * filter) {
return filter->last_out;
}
/** Second order low pass filter structure.
*
* using biquad filter with bilinear z transform
*
* http://en.wikipedia.org/wiki/Digital_biquad_filter
* http://www.earlevel.com/main/2003/03/02/the-bilinear-z-transform
*
* Laplace continious form:
*
* 1
* H(s) = -------------------
* s^2/w^2 + s/w*Q + 1
*
*
* Polynomial discrete form:
*
* b0 + b1 z^-1 + b2 z^-2
* H(z) = ----------------------
* a0 + a1 z^-1 + a2 z^-2
*
* with:
* a0 = 1
* a1 = 2*(K^2 - 1) / (K^2 + K/Q + 1)
* a2 = (K^2 - K/Q + 1) / (K^2 + K/Q + 1)
* b0 = K^2 / (K^2 + K/Q + 1)
* b1 = 2*b0
* b2 = b0
* K = tan(pi*Fc/Fs) ~ pi*Fc/Fs = Ts/(2*tau)
* Fc: cutting frequency
* Fs: sampling frequency
* Ts: sampling period
* tau: time constant
*/
struct SecondOrderLowPass {
float a[2]; ///< denominator gains
float b[2]; ///< numerator gains
float i[2]; ///< input history
float o[2]; ///< output history
};
/** Init second order low pass filter.
*
* @param filter second order low pass filter structure
* @param tau time constant of the second order low pass filter
* @param Q Q value of the second order low pass filter
* @param sample_time sampling period of the signal
* @param value initial value of the filter
*/
static inline void init_second_order_low_pass(struct SecondOrderLowPass * filter, float tau, float Q, float sample_time, float value) {
float K = sample_time / (2*tau);
float poly = K*K + K/Q + 1.;
filter->a[0] = 2.*(K*K - 1.) / poly;
filter->a[1] = (K*K - K/Q + 1.) / poly;
filter->b[0] = K*K / poly;
filter->b[1] = 2*filter->b[0];
filter->i[0] = filter->i[1] = filter->o[0] = filter->o[1] = value;
}
/** Update second order low pass filter state with a new value.
*
* @param filter second order low pass filter structure
* @param value new input value of the filter
* @return new filtered value
*/
static inline float update_second_order_low_pass(struct SecondOrderLowPass * filter, float value) {
float out = filter->b[0] * value
+ filter->b[1] * filter->i[0]
+ filter->b[0] * filter->i[1]
- filter->a[0] * filter->o[0]
- filter->a[1] * filter->o[1];
filter->i[1] = filter->i[0];
filter->i[0] = value;
filter->o[1] = filter->o[0];
filter->o[0] = out;
return out;
}
/** Get current value of the second order low pass filter.
*
* @param filter second order low pass filter structure
* @return current value of the filter
*/
static inline float get_second_order_low_pass(struct SecondOrderLowPass * filter) {
return filter->o[0];
}
struct SecondOrderLowPass_int {
int32_t a[2]; ///< denominator gains
int32_t b[2]; ///< numerator gains
int32_t i[2]; ///< input history
int32_t o[2]; ///< output history
int32_t loop_gain; ///< loop gain
};
/** Init second order low pass filter(fixed point version).
*
* @param filter second order low pass filter structure
* @param tau time constant of the second order low pass filter , 1/(2*pi*cut_off_3db)
* @param Q Q value of the second order low pass filter
* @param sample_time sampling period of the signal
* @param value initial value of the filter
*/
static inline void init_second_order_low_pass_int(struct SecondOrderLowPass_int* filter, float cut_off, float Q, float sample_time, int32_t value) {
struct SecondOrderLowPass filter_temp;
float tau = 7 / (44*cut_off);
float K = sample_time / (2*tau);
float poly = K*K + K/Q + 1.;
float loop_gain_f;
filter_temp.a[0] = 2.*(K*K - 1.) / poly;
filter_temp.a[1] = (K*K - K/Q + 1.) / poly;
filter_temp.b[0] = K*K / poly;
filter_temp.b[1] = 2*filter_temp.b[0];
loop_gain_f = 1/filter_temp.b[0];
filter->a[0] = BFP_OF_REAL((filter_temp.a[0] * loop_gain_f), INT32_FILT_FRAC);
filter->a[1] = BFP_OF_REAL((filter_temp.a[1] * loop_gain_f), INT32_FILT_FRAC);
filter->b[0] = BFP_OF_REAL(1, INT32_FILT_FRAC);
filter->b[1] = 2*filter->b[0];
filter->i[0] = filter->i[1] = filter->o[0] = filter->o[1] = value;
filter->loop_gain = BFP_OF_REAL(loop_gain_f, INT32_FILT_FRAC);
}
/** Update second order low pass filter state with a new value(fixed point version).
*
* @param filter second order low pass filter structure
* @param value new input value of the filter
* @return new filtered value
*/
static inline int32_t update_second_order_low_pass_int(struct SecondOrderLowPass_int* filter, int32_t value) {
int32_t out = filter->b[0] * value
+ filter->b[1] * filter->i[0]
+ filter->b[0] * filter->i[1]
- filter->a[0] * filter->o[0]
- filter->a[1] * filter->o[1];
filter->i[1] = filter->i[0];
filter->i[0] = value;
filter->o[1] = filter->o[0];
filter->o[0] = out / (filter->loop_gain);
return filter->o[0];
}
/** Get current value of the second order low pass filter(fixed point version).
*
* @param filter second order low pass filter structure
* @return current value of the filter
*/
static inline int32_t get_second_order_low_pass_int(struct SecondOrderLowPass_int * filter) {
return filter->o[0];
}
/** Second order Butterworth low pass filter.
*/
typedef struct SecondOrderLowPass Butterworth2LowPass;
/** Init a second order Butterworth filter.
*
* based on the generic second order filter
* with Q = 0.7071 = 1/sqrt(2)
*
* http://en.wikipedia.org/wiki/Butterworth_filter
*
* @param filter second order Butterworth low pass filter structure
* @param tau time constant of the second order low pass filter
* @param sample_time sampling period of the signal
* @param value initial value of the filter
*/
static inline void init_butterworth_2_low_pass(Butterworth2LowPass * filter, float tau, float sample_time, float value) {
init_second_order_low_pass((struct SecondOrderLowPass*)filter, tau, 0.7071, sample_time, value);
}
/** Update second order Butterworth low pass filter state with a new value.
*
* @param filter second order Butterworth low pass filter structure
* @param value new input value of the filter
* @return new filtered value
*/
static inline float update_butterworth_2_low_pass(Butterworth2LowPass * filter, float value) {
return update_second_order_low_pass((struct SecondOrderLowPass*)filter, value);
}
/** Get current value of the second order Butterworth low pass filter.
*
* @param filter second order Butterworth low pass filter structure
* @return current value of the filter
*/
static inline float get_butterworth_2_low_pass(Butterworth2LowPass * filter) {
return filter->o[0];
}
/** Second order Butterworth low pass filter(fixed point version).
*/
typedef struct SecondOrderLowPass_int Butterworth2LowPass_int;
/** Init a second order Butterworth filter.
*
* based on the generic second order filter
* with Q = 0.7071 = 1/sqrt(2)
*
* http://en.wikipedia.org/wiki/Butterworth_filter
*
* @param filter second order Butterworth low pass filter structure
* @param tau time constant of the second order low pass filter
* @param sample_time sampling period of the signal
* @param value initial value of the filter
*/
static inline void init_butterworth_2_low_pass_int(Butterworth2LowPass_int* filter, float cut_off, float sample_time, int32_t value) {
init_second_order_low_pass_int((struct SecondOrderLowPass_int*)filter, cut_off, 0.7071, sample_time, value);
}
/** Update second order Butterworth low pass filter state with a new value(fixed point version).
*
* @param filter second order Butterworth low pass filter structure
* @param value new input value of the filter
* @return new filtered value
*/
static inline int32_t update_butterworth_2_low_pass_int(Butterworth2LowPass_int* filter, int32_t value) {
return update_second_order_low_pass_int((struct SecondOrderLowPass_int*)filter, value);
}
/** Get current value of the second order Butterworth low pass filter(fixed point version).
*
* @param filter second order Butterworth low pass filter structure
* @return current value of the filter
*/
static inline int32_t get_butterworth_2_low_pass_int(Butterworth2LowPass_int* filter) {
return filter->o[0];
}
/** Fourth order Butterworth low pass filter.
*
* using two cascaded second order filters
*/
typedef struct {
struct SecondOrderLowPass lp1;
struct SecondOrderLowPass lp2;
} Butterworth4LowPass;
/** Init a fourth order Butterworth filter.
*
* based on two generic second order filters
* with Q1 = 1.30651
* and Q2 = 0.541184
*
* http://en.wikipedia.org/wiki/Butterworth_filter
*
* @param filter fourth order Butterworth low pass filter structure
* @param tau time constant of the fourth order low pass filter
* @param sample_time sampling period of the signal
* @param value initial value of the filter
*/
static inline void init_butterworth_4_low_pass(Butterworth4LowPass * filter, float tau, float sample_time, float value) {
init_second_order_low_pass(&filter->lp1, tau, 1.30651, sample_time, value);
init_second_order_low_pass(&filter->lp2, tau, 0.51184, sample_time, value);
}
/** Update fourth order Butterworth low pass filter state with a new value.
*
* using two cascaded second order filters
*
* @param filter fourth order Butterworth low pass filter structure
* @param value new input value of the filter
* @return new filtered value
*/
static inline float update_butterworth_4_low_pass(Butterworth4LowPass * filter, float value) {
float tmp = update_second_order_low_pass(&filter->lp1, value);
return update_second_order_low_pass(&filter->lp2, tmp);
}
/** Get current value of the fourth order Butterworth low pass filter.
*
* @param filter fourth order Butterworth low pass filter structure
* @return current value of the filter
*/
static inline float get_butterworth_4_low_pass(Butterworth4LowPass * filter) {
return filter->lp2.o[0];
}
/** Fourth order Butterworth low pass filter(fixed point version).
*
* using two cascaded second order filters
*/
typedef struct {
struct SecondOrderLowPass_int lp1;
struct SecondOrderLowPass_int lp2;
} Butterworth4LowPass_int;
/** Init a fourth order Butterworth filter(fixed point version).
*
* based on two generic second order filters
* with Q1 = 1.30651
* and Q2 = 0.541184
*
* http://en.wikipedia.org/wiki/Butterworth_filter
*
* @param filter fourth order Butterworth low pass filter structure
* @param tau time constant of the fourth order low pass filter
* @param sample_time sampling period of the signal
* @param value initial value of the filter
*/
static inline void init_butterworth_4_low_pass_int(Butterworth4LowPass_int * filter, float cut_off, float sample_time, int32_t value) {
init_second_order_low_pass_int(&filter->lp1, cut_off, 1.30651, sample_time, value);
init_second_order_low_pass_int(&filter->lp2, cut_off, 0.51184, sample_time, value);
}
/** Update fourth order Butterworth low pass filter state with a new value(fixed point version).
*
* using two cascaded second order filters
*
* @param filter fourth order Butterworth low pass filter structure
* @param value new input value of the filter
* @return new filtered value
*/
static inline int32_t update_butterworth_4_low_pass_int(Butterworth4LowPass_int * filter, int32_t value) {
int32_t tmp = update_second_order_low_pass_int(&filter->lp1, value);
return update_second_order_low_pass_int(&filter->lp2, tmp);
}
/** Get current value of the fourth order Butterworth low pass filter(fixed point version).
*
* @param filter fourth order Butterworth low pass filter structure
* @return current value of the filter
*/
static inline int32_t get_butterworth_4_low_pass_int(Butterworth4LowPass_int * filter) {
return filter->lp2.o[0];
}
#endif