Skip to content

Commit 2368421

Browse files
pjpeibkleiner
authored andcommitted
Added LULU filtering as an option
Fixed not initializing window size Update LICENSE Restored licence after thinking about it Update src/flight/filter.c Thanks for the suggestion! Co-authored-by: Hugo Chiang <[email protected]> Update src/flight/filter.c Co-authored-by: Hugo Chiang <[email protected]> Implemented changes as requested by Hanfer lulu: use union, add coeff function, optimize for constant substitution
1 parent dbe9027 commit 2368421

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

src/flight/filter.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,92 @@ float filter_lp_pt3_step(filter_lp_pt3 *filter, filter_state_t *state, float in)
9090
return state->delay_element[0];
9191
}
9292

93+
void filter_lp_lulu_coeff(filter_lp_lulu *filter, float hz) {
94+
if (filter->hz == hz && filter->sample_period_us == state.looptime_autodetect) {
95+
return;
96+
}
97+
filter->hz = hz;
98+
filter->sample_period_us = state.looptime_autodetect;
99+
100+
// The window value is half the wavelength of the wave that it filters. So if the wavelength of the cutoff frequency is 2 samples, the N value should be 1. If the wavelength is 4, N should be 2. Etc.
101+
float cutoff_wave_length = 1.0f / hz / 4.0f;
102+
float loop_wave_length = state.looptime_autodetect * 1e-6f;
103+
uint8_t window_half_length = cutoff_wave_length / loop_wave_length;
104+
105+
filter->num_samples = constrain(window_half_length, 1, 12);
106+
filter->window_size = filter->num_samples * 2 + 1;
107+
}
108+
109+
void filter_lp_lulu_init(filter_lp_lulu *filter, filter_state_t *state, uint8_t count, float hz) {
110+
filter_lp_lulu_coeff(filter, hz);
111+
filter_init_state(state, count);
112+
}
113+
114+
static float fix_road(float *series, float *series_b, uint8_t index, uint8_t filter_n, uint8_t window_size) {
115+
for (uint32_t N = 1; N <= filter_n; N++) {
116+
const uint32_t index_neg = (index + window_size - 2 * N) % window_size;
117+
118+
float prev_val = series[index_neg];
119+
float prev_val_b = series_b[index_neg];
120+
121+
uint32_t cur_index = (index_neg + 1) % window_size;
122+
uint32_t index_pos = (cur_index + N) % window_size;
123+
for (uint32_t i = window_size - 2 * N; i < window_size - N; i++) {
124+
const float cur_val = series[cur_index];
125+
const float next_val = series[index_pos];
126+
if (prev_val < cur_val && cur_val > next_val) {
127+
series[cur_index] = max(prev_val, next_val);
128+
}
129+
prev_val = cur_val;
130+
131+
const float cur_val_b = series_b[cur_index];
132+
const float next_val_b = series_b[index_pos];
133+
if (prev_val_b < cur_val_b && cur_val_b > next_val_b) {
134+
series_b[cur_index] = max(prev_val_b, next_val_b);
135+
}
136+
prev_val_b = cur_val_b;
137+
138+
cur_index = (cur_index + 1) % window_size;
139+
index_pos = (index_pos + 1) % window_size;
140+
}
141+
142+
prev_val = series[index_neg];
143+
prev_val_b = series_b[index_neg];
144+
145+
cur_index = (index_neg + 1) % window_size;
146+
index_pos = (cur_index + N) % window_size;
147+
for (uint32_t i = window_size - 2 * N; i < window_size - N; i++) {
148+
const float cur_val = series[cur_index];
149+
const float next_val = series[index_pos];
150+
if (prev_val > cur_val && cur_val < next_val) {
151+
series[cur_index] = min(prev_val, next_val);
152+
}
153+
prev_val = cur_val;
154+
155+
const float cur_val_b = series_b[cur_index];
156+
const float next_val_b = series_b[index_pos];
157+
if (prev_val_b > cur_val_b && cur_val_b < next_val_b) {
158+
series_b[cur_index] = min(prev_val_b, next_val_b);
159+
}
160+
prev_val_b = cur_val_b;
161+
162+
cur_index = (cur_index + 1) % window_size;
163+
index_pos = (index_pos + 1) % window_size;
164+
}
165+
}
166+
167+
const uint8_t final_index = (index + window_size - filter_n) % window_size;
168+
return (series[final_index] - series_b[final_index]) / 2;
169+
}
170+
171+
float filter_lp_lulu_step(filter_lp_lulu *filter, filter_state_t *state, float in) {
172+
const uint8_t window_index = state->window_buf_index;
173+
state->window_buf_index = (window_index + 1) % filter->window_size;
174+
state->interim[window_index] = in;
175+
state->interim_b[window_index] = -in;
176+
return fix_road(state->interim, state->interim_b, window_index, filter->num_samples, filter->window_size);
177+
}
178+
93179
void filter_biquad_notch_init(filter_biquad_notch_t *filter, filter_biquad_state_t *state, uint8_t count, float hz) {
94180
memset(filter, 0, sizeof(filter_biquad_notch_t));
95181
filter_biquad_notch_coeff(filter, hz);
@@ -190,6 +276,8 @@ void filter_init(filter_type_t type, filter_t *filter, filter_state_t *state, ui
190276
case FILTER_LP_PT3:
191277
filter_lp_pt3_init(&filter->lp_pt3, state, count, hz);
192278
break;
279+
case FILTER_LP_LULU:
280+
filter_lp_lulu_init(&filter->lp_lulu, state, count, hz);
193281
default:
194282
// no filter, do nothing
195283
break;
@@ -207,6 +295,9 @@ void filter_coeff(filter_type_t type, filter_t *filter, float hz) {
207295
case FILTER_LP_PT3:
208296
filter_lp_pt3_coeff(&filter->lp_pt3, hz);
209297
break;
298+
case FILTER_LP_LULU:
299+
filter_lp_lulu_coeff(&filter->lp_lulu, hz);
300+
break;
210301
default:
211302
// no filter, do nothing
212303
break;
@@ -221,6 +312,8 @@ float filter_step(filter_type_t type, filter_t *filter, filter_state_t *state, f
221312
return filter_lp_pt2_step(&filter->lp_pt2, state, in);
222313
case FILTER_LP_PT3:
223314
return filter_lp_pt3_step(&filter->lp_pt3, state, in);
315+
case FILTER_LP_LULU:
316+
return filter_lp_lulu_step(&filter->lp_lulu, state, in);
224317
default:
225318
// no filter at all
226319
return in;

src/flight/filter.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,20 @@ typedef enum {
99
FILTER_LP_PT1,
1010
FILTER_LP_PT2,
1111
FILTER_LP_PT3,
12+
FILTER_LP_LULU,
1213

1314
FILTER_MAX
1415
} __attribute__((__packed__)) filter_type_t;
1516

16-
typedef struct {
17-
float delay_element[3];
17+
typedef union {
18+
struct {
19+
float delay_element[3];
20+
};
21+
struct {
22+
float interim[32];
23+
float interim_b[32];
24+
uint8_t window_buf_index;
25+
};
1826
} filter_state_t;
1927

2028
typedef struct {
@@ -45,6 +53,15 @@ typedef struct {
4553
float alpha;
4654
} filter_lp_pt3;
4755

56+
// Max N = 15
57+
typedef struct {
58+
float hz;
59+
uint32_t sample_period_us;
60+
61+
uint8_t window_size;
62+
uint8_t num_samples;
63+
} filter_lp_lulu;
64+
4865
typedef struct {
4966
float hz;
5067
uint32_t sample_period_us;
@@ -60,6 +77,7 @@ typedef union {
6077
filter_lp_pt1 lp_pt1;
6178
filter_lp_pt2 lp_pt2;
6279
filter_lp_pt3 lp_pt3;
80+
filter_lp_lulu lp_lulu;
6381
} filter_t;
6482

6583
typedef struct {
@@ -99,6 +117,10 @@ void filter_lp_pt3_init(filter_lp_pt3 *filter, filter_state_t *state, uint8_t co
99117
void filter_lp_pt3_coeff(filter_lp_pt3 *filter, float hz);
100118
float filter_lp_pt3_step(filter_lp_pt3 *filter, filter_state_t *state, float in);
101119

120+
void filter_lp_lulu_init(filter_lp_lulu *filter, filter_state_t *state, uint8_t count, float hz);
121+
void filter_lp_lulu_coeff(filter_lp_lulu *filter, float hz);
122+
float filter_lp_lulu_step(filter_lp_lulu *filter, filter_state_t *state, float in);
123+
102124
void filter_biquad_notch_init(filter_biquad_notch_t *filter, filter_biquad_state_t *state, uint8_t count, float hz);
103125
void filter_biquad_notch_coeff(filter_biquad_notch_t *filter, float hz);
104126
float filter_biquad_notch_step(filter_biquad_notch_t *filter, filter_biquad_state_t *state, float in);

src/osd/render.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ static const char *filter_type_labels[] = {
101101
" PT1",
102102
" PT2",
103103
" PT3",
104+
" LULU",
104105
};
105106

106107
#pragma GCC diagnostic ignored "-Wmissing-braces"

0 commit comments

Comments
 (0)