SigPack - the C++ signal processing library
 
Loading...
Searching...
No Matches
filter.h
Go to the documentation of this file.
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4#ifndef SP_FILTER_H
5#define SP_FILTER_H
6
7namespace sp
8{
13
21template <class T1, class T2, class T3> class FIR_filt
22{
23 private:
24 // Ordinary FIR filter
25 arma::uword M;
26 arma::uword cur_p;
27 arma::Mat<T1> buf;
28 arma::Mat<T2> b;
29 // Adaptive LMS FIR filter
30 double mu;
31 arma::uword L;
32 arma::uword blk_ctr;
33 T2 c;
34 arma::Mat<T1> P;
35 arma::Mat<T1> Q;
36 arma::Mat<T1> R;
37 arma::Mat<T1> K;
38 double lmd;
39 arma::Mat<T1> X_tpz;
40 arma::uword do_adapt;
41 public:
46 {
47 }
48
53 {
54 }
55
59 void clear( void )
60 {
61 buf.zeros();
62 cur_p = 0;
63 }
64
70 void set_coeffs( const arma::Mat<T2>& _b )
71 {
72 M = _b.n_elem;
73 buf.set_size( M, 1 );
74 this->clear();
75 b.set_size( M, 1 );
76 b = _b;
77 }
78
84 void set_coeffs( const arma::Col<T2>& _b_col )
85 {
86 arma::Mat<T2> b_mat = arma::conv_to<arma::Mat<T2>>::from( _b_col );
87 set_coeffs( b_mat );
88 }
89
94 arma::Col<T2> get_coeffs()
95 {
96 return arma::conv_to<arma::Col<T2>>::from( b );
97 }
98
104 void update_coeffs( const arma::Mat<T2>& _b )
105 {
106 b = _b;
107 }
108
114 T3 operator()( const T1& in )
115 {
116 T3 out = 0;
117 arma::uword p = 0;
118 buf[cur_p] = in; // Insert new sample
119 for( arma::uword m = cur_p; m < M; m++ )
120 out += b[p++] * buf[m]; // Calc upper part
121 for( arma::uword m = 0; m < cur_p; m++ )
122 out += b[p++] * buf[m]; // ... and lower
123
124 // Move insertion point
125 if( cur_p == 0 )
126 cur_p = M - 1;
127 else
128 cur_p--;
129
130 return out;
131 }
132
138 arma::Mat<T3> filter( const arma::Mat<T1>& in )
139 {
140 arma::uword sz = in.n_elem;
141 arma::Mat<T3> out( sz, 1 );
142 for( arma::uword n = 0; n < sz; n++ )
143 out[n] = this->operator()( in[n] );
144 return out;
145 }
146
147 arma::Col<T3> filter( const arma::Col<T1>& in )
148 {
149 arma::Mat<T1> in_col = arma::conv_to<arma::Mat<T1>>::from( in );
150 return arma::conv_to<arma::Col<T3>>::from( filter( in_col ) );
151 }
152
159 void setup_lms( const arma::uword _N, const double _mu, const arma::uword _L = 1 )
160 {
161 M = _N;
162 mu = _mu;
163 L = _L;
164 buf.set_size( M, 1 );
165 buf.zeros();
166 b.set_size( M, 1 );
167 b.zeros();
168 K.set_size( M, 1 );
169 K.zeros();
170 cur_p = 0;
171 blk_ctr = 0;
172 do_adapt = 1;
173 }
174
183 void lms_adapt( const T3 _err )
184 {
185 if( do_adapt )
186 {
187 // Reshape buf
188 arma::Mat<T1> buf_tmp( M, 1 );
189 for( arma::uword m = 0; m < M; m++ )
190 {
191 buf_tmp( m ) = buf( ( cur_p + m + 1 ) % M );
192 }
193
194 // Accumulate
195 K += _err * buf_tmp;
196
197 // Block update
198 if( blk_ctr++ % L == 0 )
199 {
200 b += 2 * mu * K / double( L );
201 K.zeros();
202 }
203 }
204 }
205
213 void setup_nlms( const arma::uword _N, const double _mu, const T2 _c, const arma::uword _L = 1 )
214 {
215 M = _N;
216 mu = _mu;
217 L = _L;
218 c = _c;
219 buf.set_size( M, 1 );
220 buf.zeros();
221 b.set_size( M, 1 );
222 b.zeros();
223 K.set_size( M, 1 );
224 K.zeros();
225 cur_p = 0;
226 blk_ctr = 0;
227 do_adapt = 1;
228 }
229
239 void nlms_adapt( const T3 _err )
240 {
241 if( do_adapt )
242 {
243 // Reshape buf
244 arma::Mat<T1> buf_tmp( M, 1 );
245 for( arma::uword m = 0; m < M; m++ )
246 {
247 buf_tmp( m ) = buf( ( cur_p + m + 1 ) % M );
248 }
249
250 // Accumulate
251 T1 S = c + arma::as_scalar( buf_tmp.t() * buf_tmp );
252 K += _err * buf_tmp / S;
253
254 // Block update
255 if( blk_ctr++ % L == 0 )
256 {
257 b += 2 * mu * K / double( L );
258 K.zeros();
259 }
260 }
261 }
262
270 void setup_newt( const arma::uword _N, const double _mu, const T2 _c, const arma::uword _L = 1 )
271 {
272 M = _N;
273 mu = _mu;
274 L = _L;
275 c = _c;
276 buf.set_size( M, 1 );
277 buf.zeros();
278 b.set_size( M, 1 );
279 b.zeros();
280 K.set_size( M, 1 );
281 K.zeros();
282 X_tpz.set_size( M, L );
283 X_tpz.zeros();
284 cur_p = 0;
285 blk_ctr = 0;
286 do_adapt = 1;
287 }
288
299 void newt_adapt( const T3 _err )
300 {
301 if( do_adapt )
302 {
303 // Reshape buf
304 arma::Mat<T1> buf_tmp( M, 1 );
305 for( arma::uword m = 0; m < M; m++ )
306 {
307 buf_tmp( m ) = buf( ( cur_p + m + 1 ) % M );
308 }
309
310 // Accumulate in buf
311 K += _err * buf_tmp;
312 X_tpz.col( blk_ctr % L ) = buf_tmp;
313
314 // Block update
315 if( blk_ctr++ % L == 0 )
316 {
317 // Correlation matrix estimate
318 arma::Mat<T1> Rxx = X_tpz * X_tpz.t() / L;
319 arma::Mat<T1> I;
320 I.eye( M, M );
321 b += mu * pinv( Rxx + c * I ) * K / L;
322 K.zeros();
323 }
324 }
325 }
326
333 void setup_rls( const arma::uword _N, const double _lmd, const double _P0 )
334 {
335 M = _N;
336 lmd = _lmd;
337 L = 1;
338 P.eye( M, M );
339 P = _P0 * P;
340 K.set_size( M, 1 );
341 K.zeros();
342 buf.set_size( M, 1 );
343 buf.zeros();
344 b.set_size( M, 1 );
345 b.zeros();
346 cur_p = 0;
347 do_adapt = 1;
348 }
349
360 void rls_adapt( const T3 _err )
361 {
362 if( do_adapt )
363 {
364 // Reshape buf
365 arma::Mat<T1> buf_tmp( M, 1 );
366 for( arma::uword m = 0; m < M; m++ )
367 {
368 buf_tmp( m ) = buf( ( cur_p + m + 1 ) % M );
369 }
370
371 // Update P
372 T1 S = lmd + arma::as_scalar( buf_tmp.t() * P * buf_tmp );
373 K = P * buf_tmp / S;
374 P = ( P - K * buf_tmp.t() * P ) / lmd;
375
376 // Update coeffs
377 b = b + K * _err;
378 }
379 }
380
388 void setup_kalman( const arma::uword _N, const double _P0, const double _Q0, const double _R0 )
389 {
390 M = _N;
391 L = 1;
392 P.eye( M, M );
393 P = _P0 * P;
394 Q.eye( M, M );
395 Q = _Q0 * Q;
396 R.ones( 1, 1 );
397 R = _R0 * R;
398 K.set_size( M, 1 );
399 K.zeros();
400 buf.set_size( M, 1 );
401 buf.zeros();
402 b.set_size( M, 1 );
403 b.zeros();
404 cur_p = 0;
405 do_adapt = 1;
406 }
407
417 void kalman_adapt( const T3 _err )
418 {
419 if( do_adapt )
420 {
421 // Reshape buf
422 arma::Mat<T1> buf_tmp( M, 1 );
423 for( arma::uword m = 0; m < M; m++ )
424 {
425 buf_tmp( m ) = buf( ( cur_p + m + 1 ) % M );
426 }
427
428 // Innovation/error covariance
429 T1 S = arma::as_scalar( R + buf_tmp.t() * P * buf_tmp );
430
431 // Kalman gain
432 K = P * buf_tmp / S;
433
434 // Update coeffs/state
435 b = b + K * _err;
436
437 // Update estimate covariance
438 P = P - K * buf_tmp.t() * P + Q;
439 }
440 }
441
446 double get_step_size( void )
447 {
448 return mu;
449 }
450
455 arma::Mat<T1> get_P( void )
456 {
457 return P;
458 }
459
464 arma::Mat<T1> get_K( void )
465 {
466 return K;
467 }
468
473 void set_step_size( const double _mu )
474 {
475 mu = _mu;
476 }
477
481 void adapt_enable( void )
482 {
483 do_adapt = 1;
484 }
485
489 void adapt_disble( void )
490 {
491 do_adapt = 0;
492 }
493};
494
503template <class T1, class T2, class T3> class IIR_filt
504{
505 private:
506 arma::uword M;
507 arma::uword N;
508 arma::uword b_cur_p;
509 arma::uword a_cur_p;
510 arma::Col<T2> b;
511 arma::Col<T2> a;
512 arma::Col<T1> b_buf;
513 arma::Col<T1> a_buf;
514 public:
519 {
520 }
521
526 {
527 }
528
532 void clear( void )
533 {
534 b_buf.zeros();
535 a_buf.zeros();
536 b_cur_p = 0;
537 a_cur_p = 0;
538 }
539
546 void set_coeffs( const arma::Col<T2>& _b, const arma::Col<T2>& _a )
547 {
548 M = _b.size();
549 N = _a.size();
550 b_buf.set_size( M );
551 a_buf.set_size( N );
552 this->clear();
553 b = _b / _a[0];
554 a = _a / _a[0];
555 }
556
563 void update_coeffs( const arma::Col<T2>& _b, const arma::Col<T2>& _a )
564 {
565 b = _b / _a[0];
566 a = _a / _a[0];
567 }
568
574 T3 operator()( const T1& in )
575 {
576 T3 out = 0;
577 arma::uword p = 0;
578
579 // MA part
580 b_buf[b_cur_p] = in; // Insert new sample
581 for( arma::uword m = b_cur_p; m < M; m++ )
582 out += b[p++] * b_buf[m]; // Calc upper part
583 for( arma::uword m = 0; m < b_cur_p; m++ )
584 out += b[p++] * b_buf[m]; // ... and lower
585
586 // Move insertion point
587 if( b_cur_p == 0 )
588 b_cur_p = M - 1;
589 else
590 b_cur_p--;
591
592 // AR part
593 p = 1;
594 for( arma::uword n = a_cur_p + 1; n < N; n++ )
595 out -= a[p++] * a_buf[n]; // Calc upper part
596 for( arma::uword n = 0; n < a_cur_p; n++ )
597 out -= a[p++] * a_buf[n]; // ... and lower
598
599 a_buf[a_cur_p] = out; // Insert output
600
601 // Move insertion point
602 if( a_cur_p == 0 )
603 a_cur_p = N - 1;
604 else
605 a_cur_p--;
606
607 return out;
608 }
609
615 arma::Col<T3> filter( const arma::Col<T1>& in )
616 {
617 arma::uword sz = in.size();
618 arma::Col<T3> out( sz );
619 for( arma::uword n = 0; n < sz; n++ )
620 out[n] = this->operator()( in[n] );
621 return out;
622 }
623};
624
628
637arma_inline arma::vec fir1( const arma::uword M, const double f0 )
638{
639 arma::vec b( M + 1 ), h( M + 1 );
640 h = hamming( M + 1 );
641 for( arma::uword m = 0; m < M + 1; m++ )
642 {
643 b[m] = f0 * h[m] * sinc( f0 * ( m - M / 2.0 ) );
644 }
645 return b / arma::sum( b );
646}
647
656arma_inline arma::vec fir1_hp( const arma::uword M, const double f0 )
657{
658 if( M % 2 != 0 )
659 err_handler( "Filter order must be even" );
660 arma::vec b( M + 1 ), h( M + 1 );
661 h = hamming( M + 1 );
662 for( arma::uword m = 0; m < M + 1; m++ )
663 {
664 b[m] = h[m] * ( sinc( m - M / 2.0 ) - f0 * sinc( f0 * ( m - M / 2.0 ) ) );
665 }
666
667 // Scale
668 std::complex<double> i( 0, 1 );
669 double nrm;
670 arma::vec fv = arma::regspace( 0, double( M ) );
671 nrm = abs( arma::sum( exp( -i * fv * PI ) % b ) );
672
673 return b / nrm;
674}
675
685arma_inline arma::vec fir1_bp( const arma::uword M, const double f0, const double f1 )
686{
687 if( f1 <= f0 )
688 err_handler( "Frequencies must be [0 < f0 < f1 < 1]" );
689
690 arma::vec b( M + 1 ), h( M + 1 );
691 h = hamming( M + 1 );
692 for( arma::uword m = 0; m < M + 1; m++ )
693 {
694 b[m] = h[m] * ( f1 * sinc( f1 * ( m - M / 2.0 ) ) - f0 * sinc( f0 * ( m - M / 2.0 ) ) );
695 }
696
697 // Scale
698 double fc = ( f0 + f1 ) / 2;
699 std::complex<double> i( 0, 1 );
700 double nrm;
701 arma::vec fv = arma::regspace( 0, double( M ) );
702 nrm = abs( arma::sum( exp( -i * fv * PI * fc ) % b ) );
703
704 return b / nrm;
705}
706
716arma_inline arma::vec fir1_bs( const arma::uword M, const double f0, const double f1 )
717{
718 if( M % 2 != 0 )
719 err_handler( "Filter order must be even" );
720 if( f1 <= f0 )
721 err_handler( "Frequencies must be [0 < f0 < f1 < 1]" );
722
723 arma::vec b( M + 1 ), h( M + 1 );
724 h = hamming( M + 1 );
725 for( arma::uword m = 0; m < M + 1; m++ )
726 {
727 b[m] = h[m] * ( sinc( m - M / 2.0 ) - f1 * sinc( f1 * ( m - M / 2.0 ) ) + f0 * sinc( f0 * ( m - M / 2.0 ) ) );
728 }
729
730 return b / arma::sum( b );
731}
732
742arma_inline arma::vec fd_filter( const arma::uword M, double fd )
743{
744 arma::vec h( M );
745 arma::vec w = blackmanharris( M );
746 if( M % 2 == 1 )
747 fd = fd - 0.5; // Offset for odd nr of taps
748 for( arma::uword m = 0; m < M; m++ )
749 {
750 h( m ) = w( m ) * sinc( m - M / 2.0 - fd );
751 }
752 h = h / arma::sum( h ); // Normalize gain
753
754 return h;
755}
756
764arma_inline arma::cx_vec freq( const arma::vec b, const arma::vec a, const arma::uword K = 512 )
765{
766 arma::cx_vec h( K );
767 arma::uword M = b.size();
768 arma::uword N = a.size();
769 std::complex<double> b_tmp, a_tmp, i( 0, 1 );
770 for( arma::uword k = 0; k < K; k++ )
771 {
772 b_tmp = std::complex<double>( b( 0 ), 0 );
773 for( arma::uword m = 1; m < M; m++ )
774 b_tmp += b( m ) * ( cos( m * PI * k / K ) - i * sin( m * PI * k / K ) );
775 a_tmp = std::complex<double>( a( 0 ), 0 );
776 for( arma::uword n = 1; n < N; n++ )
777 a_tmp += a( n ) * ( cos( n * PI * k / K ) - i * sin( n * PI * k / K ) );
778 h( k ) = b_tmp / a_tmp;
779 }
780 return h;
781}
782
790arma_inline arma::vec freqz( const arma::vec b, const arma::vec a, const arma::uword K = 512 )
791{
792 arma::cx_vec f = freq( b, a, K );
793 return abs( f );
794}
795
803arma_inline arma::vec phasez( const arma::vec b, const arma::vec a, const arma::uword K = 512 )
804{
805 arma::cx_vec f = freq( b, a, K );
806 return angle( f );
807}
808
810
811} // namespace sp
812#endif
FIR/MA filter class.
Definition filter.h:22
arma::Mat< T1 > get_P(void)
Get P.
Definition filter.h:455
arma::Mat< T1 > R
Adaptive filter Measurement noise.
Definition filter.h:36
void setup_newt(const arma::uword _N, const double _mu, const T2 _c, const arma::uword _L=1)
LMS-Newton Filter function setup. (Affine Projection Algorithm)
Definition filter.h:270
arma::Col< T3 > filter(const arma::Col< T1 > &in)
Definition filter.h:147
void adapt_enable(void)
Start adapt.
Definition filter.h:481
void kalman_adapt(const T3 _err)
Kalman Filter update function.
Definition filter.h:417
void clear(void)
Clears the internal states and pointer.
Definition filter.h:59
double get_step_size(void)
Get step size.
Definition filter.h:446
arma::Mat< T3 > filter(const arma::Mat< T1 > &in)
Filter function.
Definition filter.h:138
double lmd
Adaptive filter RLS forgetting factor.
Definition filter.h:38
arma::uword L
Adaptive filter block length.
Definition filter.h:31
void setup_lms(const arma::uword _N, const double _mu, const arma::uword _L=1)
LMS Filter function setup.
Definition filter.h:159
double mu
Adaptive filter step size.
Definition filter.h:30
~FIR_filt()
Destructor.
Definition filter.h:52
arma::Mat< T1 > K
Adaptive filter gain vector.
Definition filter.h:37
void nlms_adapt(const T3 _err)
NLMS Filter update function.
Definition filter.h:239
void newt_adapt(const T3 _err)
LMS-Newton Filter update function.
Definition filter.h:299
arma::Mat< T1 > buf
Signal buffer.
Definition filter.h:27
void update_coeffs(const arma::Mat< T2 > &_b)
Updates coefficients in FIR filter without clearing the internal states.
Definition filter.h:104
void adapt_disble(void)
Stop adapt.
Definition filter.h:489
arma::Mat< T1 > get_K(void)
Get K.
Definition filter.h:464
void lms_adapt(const T3 _err)
LMS Filter update function.
Definition filter.h:183
T2 c
Adaptive filter NLMS regulation const.
Definition filter.h:33
void rls_adapt(const T3 _err)
RLS Filter update function.
Definition filter.h:360
arma::Mat< T1 > P
Adaptive filter Inverse corr matrix (estimated accuracy)
Definition filter.h:34
arma::uword blk_ctr
Adaptive filter block length counter.
Definition filter.h:32
arma::uword do_adapt
Adaptive filter enable flag.
Definition filter.h:40
arma::uword M
Nr of filter taps.
Definition filter.h:25
arma::Mat< T1 > X_tpz
Adaptive filter Toeplitz for Corr matrix calc.
Definition filter.h:39
arma::Col< T2 > get_coeffs()
Get coefficients from FIR filter.
Definition filter.h:94
void set_coeffs(const arma::Col< T2 > &_b_col)
Sets coefficients in FIR filter (col format) The internal state and pointers are cleared.
Definition filter.h:84
FIR_filt()
Constructor.
Definition filter.h:45
arma::uword cur_p
Pointer to current sample in buffer.
Definition filter.h:26
void setup_rls(const arma::uword _N, const double _lmd, const double _P0)
RLS Filter function setup.
Definition filter.h:333
arma::Mat< T1 > Q
Adaptive filter Process noise.
Definition filter.h:35
void setup_nlms(const arma::uword _N, const double _mu, const T2 _c, const arma::uword _L=1)
NLMS Filter function setup.
Definition filter.h:213
T3 operator()(const T1 &in)
Filter operator.
Definition filter.h:114
void set_step_size(const double _mu)
Set step size.
Definition filter.h:473
void setup_kalman(const arma::uword _N, const double _P0, const double _Q0, const double _R0)
Kalman Filter function setup.
Definition filter.h:388
void set_coeffs(const arma::Mat< T2 > &_b)
Sets coefficients in FIR filter. The internal state and pointers are cleared.
Definition filter.h:70
arma::Mat< T2 > b
Filter coefficients.
Definition filter.h:28
IIR/ARMA filter class.
Definition filter.h:504
arma::Col< T2 > a
AR Filter coefficients.
Definition filter.h:511
arma::uword b_cur_p
Pointer to current sample in MA buffer.
Definition filter.h:508
arma::Col< T2 > b
MA Filter coefficients.
Definition filter.h:510
void update_coeffs(const arma::Col< T2 > &_b, const arma::Col< T2 > &_a)
Updates coefficients in filter without clearing the internal states.
Definition filter.h:563
void set_coeffs(const arma::Col< T2 > &_b, const arma::Col< T2 > &_a)
Sets coefficients in IIR filter. The internal state and pointers are cleared.
Definition filter.h:546
IIR_filt()
Constructor.
Definition filter.h:518
arma::Col< T3 > filter(const arma::Col< T1 > &in)
Filter function.
Definition filter.h:615
arma::Col< T1 > a_buf
AR Signal buffer.
Definition filter.h:513
arma::uword M
Nr of MA filter taps.
Definition filter.h:506
arma::Col< T1 > b_buf
MA Signal buffer.
Definition filter.h:512
T3 operator()(const T1 &in)
Filter operator.
Definition filter.h:574
arma::uword a_cur_p
Pointer to current sample in AR buffer.
Definition filter.h:509
arma::uword N
Nr of AR filter taps.
Definition filter.h:507
~IIR_filt()
Destructor.
Definition filter.h:525
void clear(void)
Clears the internal states and pointers.
Definition filter.h:532
arma_inline arma::vec fd_filter(const arma::uword M, double fd)
Fractional delay function. Fractional delay filter design using windowed sinc method....
Definition filter.h:742
arma_inline arma::vec fir1_bs(const arma::uword M, const double f0, const double f1)
FIR bandstop design function. FIR design using windows method (hamming window). NB!...
Definition filter.h:716
arma_inline arma::vec phasez(const arma::vec b, const arma::vec a, const arma::uword K=512)
Frequency phase response function. Calculates the frequency phase response.
Definition filter.h:803
arma_inline arma::vec fir1(const arma::uword M, const double f0)
FIR lowpass design function. FIR lowpassdesign using windows method (hamming window)....
Definition filter.h:637
arma_inline arma::vec fir1_hp(const arma::uword M, const double f0)
FIR highpass design function. FIR design using windows method (hamming window). NB!...
Definition filter.h:656
arma_inline arma::vec fir1_bp(const arma::uword M, const double f0, const double f1)
FIR bandpass design function. FIR design using windows method (hamming window). NB!...
Definition filter.h:685
arma_inline arma::cx_vec freq(const arma::vec b, const arma::vec a, const arma::uword K=512)
Frequency response function. Calculates the frequency response.
Definition filter.h:764
arma_inline arma::vec freqz(const arma::vec b, const arma::vec a, const arma::uword K=512)
Frequency magnitude response function. Calculates the frequency magnitude response.
Definition filter.h:790
const double PI
... or use arma::datum::pi
Definition base.h:14
double angle(const std::complex< T > &x)
Calculates angle in radians for complex input.
Definition base.h:67
arma_inline double sinc(double x)
A sinc, sin(x)/x, function.
Definition base.h:21
#define err_handler(msg)
Definition base.h:212
arma_inline arma::vec hamming(const arma::uword N)
Hamming window.
Definition window.h:43
arma_inline arma::vec blackmanharris(const arma::uword N)
Blackman-Harris window. Symmetric BH4 window.
Definition window.h:88
Definition base.h:8