dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lpfilter.c
Go to the documentation of this file.
1 
15 /*
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, see <http://www.gnu.org/licenses/>
28  */
29 
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <math.h>
34 #include "pios.h"
35 #include "lpfilter.h"
36 
37 #define MAX_FILTER_WIDTH 16
38 
39 static const float lpfilter_butterworth_factors[16] = {
40  // 2nd order
41  1.4142f,
42 
43  // 3rd order
44  1.0f,
45 
46  // 4th order
47  0.7654f, 1.8478f,
48 
49  // 5th order
50  0.6180f, 1.6180f,
51 
52  // 6th order
53  0.5176f, 1.4142f, 1.9319f,
54 
55  // 7th order
56  0.4450f, 1.2470f, 1.8019f,
57 
58  // 8th order
59  0.3902f, 1.1111f, 1.6629f, 1.9616f
60 };
61 
63  float x1, x2, y1, y2;
64 };
65 
67  float b0, a1, a2;
69 };
70 
72  float alpha;
73  float *prev;
74 };
75 
77 
79  struct lpfilter_biquad *biquad[4];
80  uint8_t order;
81  uint8_t width;
82 
83 };
84 
85 void lpfilter_construct_single_biquad(struct lpfilter_biquad *b, float cutoff, float dT, float q, uint8_t width)
86 {
87  float f = 1.0f / tanf((float)M_PI*cutoff*dT);
88 
89  // Skipping calculation of b1 and b2, since this only going to do Butterworth.
90  // These terms are optimized away in the actual filtering calculation.
91  b->b0 = 1.0f / (1.0f + q*f + f*f);
92  b->a1 = 2.0f * (f*f - 1.0f) * b->b0;
93  b->a2 = -(1.0f - q*f + f*f) * b->b0;
94 
95  b->s = PIOS_malloc_no_dma(sizeof(struct lpfilter_biquad_state)*width);
96  if(!b->s)
97  PIOS_Assert(0);
98 
99  memset((void*)b->s, 0, sizeof(struct lpfilter_biquad_state)*width);
100 }
101 
102 void lpfilter_construct_biquads(lpfilter_state_t filt, float cutoff, float dT, int o, uint8_t width)
103 {
104  // Amount of biquad filters needed.
105  int len = o >> 1;
106 
107  // Calculate the address of coefficients in the look-up table.
108  // There's probably a proper mathematical way for this. Let's just count
109  // everything.
110  int addr = 0;
111  for(int i = 2; i < o; i++)
112  {
113  addr += i >> 1;
114  }
115 
116  // Create all necessary biquads and allocate, too, if not yet done so.
117  for(int i = 0; i < len; i++)
118  {
119  if(!filt->biquad[i]) {
120  filt->biquad[i] = PIOS_malloc_no_dma(sizeof(struct lpfilter_biquad));
121  if(!filt->biquad[i])
122  PIOS_Assert(0);
123  }
124  lpfilter_construct_single_biquad(filt->biquad[i], cutoff, dT, lpfilter_butterworth_factors[addr+i], width);
125  }
126 }
127 
128 void lpfilter_create(lpfilter_state_t *filter_ptr, float cutoff, float dT, uint8_t order, uint8_t width)
129 {
130  if(!filter_ptr) {
131  // Whyyyyyyy?
132  PIOS_Assert(0);
133  }
134 
135  if(!*filter_ptr) {
136  *filter_ptr = PIOS_malloc_no_dma(sizeof(struct lpfilter_state));
137  if(!*filter_ptr)
138  PIOS_Assert(0);
139  memset(*filter_ptr, 0, sizeof(struct lpfilter_state));
140  }
141 
142  lpfilter_state_t filter = *filter_ptr;
143 
144  if((filter->width != 0 && filter->width != width) || (width > MAX_FILTER_WIDTH)) {
145  // We can't free memory, so if some caller keeps tossing varying
146  // filter widths while updating an already allocated filter, go fail.
147  PIOS_Assert(0);
148  }
149 
150  // Clamp order count. If zero, this bypasses the filter.
151  if(order == 0) {
152  filter->order = 0;
153  return;
154  } else if(order > 8) order = 8;
155 
156  if(order & 0x1) {
157  // Filter is odd, allocate the first order filter.
158  if(!filter->first_order) {
159  filter->first_order = PIOS_malloc_no_dma(sizeof(struct lpfilter_first_order));
160  if(!filter->first_order)
161  PIOS_Assert(0);
162 
163  filter->first_order->prev = PIOS_malloc_no_dma(sizeof(float)*width);
164  if(!filter->first_order->prev)
165  PIOS_Assert(0);
166  }
167 
168  filter->first_order->alpha = expf(-2.0f * (float)(M_PI) * cutoff * dT);
169  memset((void*)filter->first_order->prev, 0, sizeof(float)*width);
170  }
171 
172  filter->order = order;
173  filter->width = width;
174  lpfilter_construct_biquads(filter, cutoff, dT, order, width);
175 }
176 
177 float lpfilter_run_single(lpfilter_state_t filter, uint8_t axis, float sample)
178 {
179  if(!filter)
180  return sample;
181 
182  if(axis >= filter->width) {
183  PIOS_Assert(0);
184  }
185 
186  int order = filter->order;
187 
188  // Order at zero means bypass.
189  if(!order)
190  return sample;
191 
192  if(order & 0x1) {
193  // Odd order filter
194  filter->first_order->prev[axis] *= filter->first_order->alpha;
195  filter->first_order->prev[axis] += (1 - filter->first_order->alpha) * sample;
196  sample = filter->first_order->prev[axis];
197  }
198 
199  // Run all generated biquads.
200  order >>= 1;
201  for(int i = 0; i < order; i++)
202  {
203  struct lpfilter_biquad *b = filter->biquad[i];
204  struct lpfilter_biquad_state *s = &b->s[axis];
205 
206  float y = b->b0 * (sample + 2.0f * s->x1 + s->x2) + b->a1 * s->y1 + b->a2 * s->y2;
207 
208  s->y2 = s->y1;
209  s->y1 = y;
210 
211  s->x2 = s->x1;
212  s->x1 = sample;
213 
214  sample = y;
215  }
216 
217  return sample;
218 }
219 
220 void lpfilter_run(lpfilter_state_t filter, float *sample)
221 {
222  if(!filter) return;
223  int order = filter->order;
224 
225  // Order at zero means bypass.
226  if(order == 0) return;
227 
228  if(order & 0x1) {
229  // Odd order filter
230  for(int i = 0; i < filter->width; i++)
231  {
232  filter->first_order->prev[i] *= filter->first_order->alpha;
233  filter->first_order->prev[i] += (1 - filter->first_order->alpha) * sample[i];
234  sample[i] = filter->first_order->prev[i];
235  }
236  }
237 
238  // Run all generated biquads.
239  order >>= 1;
240  for(int i = 0; i < order; i++)
241  {
242  struct lpfilter_biquad *b = filter->biquad[i];
243 
244  for(int j = 0; j < filter->width; j++)
245  {
246  struct lpfilter_biquad_state *s = &b->s[j];
247 
248  float y = b->b0 * (sample[j] + 2.0f * s->x1 + s->x2) + b->a1 * s->y1 + b->a2 * s->y2;
249 
250  s->y2 = s->y1;
251  s->y1 = y;
252 
253  s->x2 = s->x1;
254  s->x1 = sample[j];
255 
256  sample[j] = y;
257  }
258  }
259 }
#define MAX_FILTER_WIDTH
Definition: lpfilter.c:37
Main PiOS header to include all the compiled in PiOS options.
volatile int j
Definition: loadabletest.c:12
struct lpfilter_biquad * biquad[4]
Definition: lpfilter.c:79
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
void lpfilter_run(lpfilter_state_t filter, float *sample)
Definition: lpfilter.c:220
void lpfilter_construct_single_biquad(struct lpfilter_biquad *b, float cutoff, float dT, float q, uint8_t width)
Definition: lpfilter.c:85
static const float lpfilter_butterworth_factors[16]
Definition: lpfilter.c:39
uint8_t order
Definition: lpfilter.c:80
float lpfilter_run_single(lpfilter_state_t filter, uint8_t axis, float sample)
Definition: lpfilter.c:177
void lpfilter_create(lpfilter_state_t *filter_ptr, float cutoff, float dT, uint8_t order, uint8_t width)
Definition: lpfilter.c:128
uint8_t i
Definition: msp_messages.h:97
void lpfilter_construct_biquads(lpfilter_state_t filt, float cutoff, float dT, int o, uint8_t width)
Definition: lpfilter.c:102
tuple f
Definition: px_mkfw.py:81
struct lpfilter_first_order * first_order
Definition: lpfilter.c:78
uint8_t width
Definition: lpfilter.c:81
#define PIOS_Assert(test)
Definition: pios_debug.h:52
struct lpfilter_biquad_state * s
Definition: lpfilter.c:68