@@ -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+
93179void 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 ;
0 commit comments