Kim Bruil
/
EMG_Input
EMG input library biorobortics 31-10-2016
Fork of EMG by
filt.h@29:98406a20a42b, 2016-10-31 (annotated)
- Committer:
- kbruil
- Date:
- Mon Oct 31 12:30:20 2016 +0000
- Revision:
- 29:98406a20a42b
- Parent:
- 22:c01f61be07e0
Code project biorobotics 31-10-2016;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kbruil | 22:c01f61be07e0 | 1 | /* |
kbruil | 22:c01f61be07e0 | 2 | * FIR filter class, by Mike Perkins |
kbruil | 22:c01f61be07e0 | 3 | * |
kbruil | 22:c01f61be07e0 | 4 | * a simple C++ class for linear phase FIR filtering |
kbruil | 22:c01f61be07e0 | 5 | * |
kbruil | 22:c01f61be07e0 | 6 | * For background, see the post http://www.cardinalpeak.com/blog?p=1841 |
kbruil | 22:c01f61be07e0 | 7 | * |
kbruil | 22:c01f61be07e0 | 8 | * Copyright (c) 2013, Cardinal Peak, LLC. http://www.cardinalpeak.com |
kbruil | 22:c01f61be07e0 | 9 | * |
kbruil | 22:c01f61be07e0 | 10 | * Redistribution and use in source and binary forms, with or without |
kbruil | 22:c01f61be07e0 | 11 | * modification, are permitted provided that the following conditions |
kbruil | 22:c01f61be07e0 | 12 | * are met: |
kbruil | 22:c01f61be07e0 | 13 | * |
kbruil | 22:c01f61be07e0 | 14 | * 1) Redistributions of source code must retain the above copyright |
kbruil | 22:c01f61be07e0 | 15 | * notice, this list of conditions and the following disclaimer. |
kbruil | 22:c01f61be07e0 | 16 | * |
kbruil | 22:c01f61be07e0 | 17 | * 2) Redistributions in binary form must reproduce the above |
kbruil | 22:c01f61be07e0 | 18 | * copyright notice, this list of conditions and the following |
kbruil | 22:c01f61be07e0 | 19 | * disclaimer in the documentation and/or other materials provided |
kbruil | 22:c01f61be07e0 | 20 | * with the distribution. |
kbruil | 22:c01f61be07e0 | 21 | * |
kbruil | 22:c01f61be07e0 | 22 | * 3) Neither the name of Cardinal Peak nor the names of its |
kbruil | 22:c01f61be07e0 | 23 | * contributors may be used to endorse or promote products derived |
kbruil | 22:c01f61be07e0 | 24 | * from this software without specific prior written permission. |
kbruil | 22:c01f61be07e0 | 25 | * |
kbruil | 22:c01f61be07e0 | 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
kbruil | 22:c01f61be07e0 | 27 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
kbruil | 22:c01f61be07e0 | 28 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
kbruil | 22:c01f61be07e0 | 29 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
kbruil | 22:c01f61be07e0 | 30 | * CARDINAL PEAK, LLC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
kbruil | 22:c01f61be07e0 | 31 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
kbruil | 22:c01f61be07e0 | 32 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
kbruil | 22:c01f61be07e0 | 33 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
kbruil | 22:c01f61be07e0 | 34 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
kbruil | 22:c01f61be07e0 | 35 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
kbruil | 22:c01f61be07e0 | 36 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
kbruil | 22:c01f61be07e0 | 37 | * SUCH DAMAGE. |
kbruil | 22:c01f61be07e0 | 38 | */ |
kbruil | 22:c01f61be07e0 | 39 | |
kbruil | 22:c01f61be07e0 | 40 | /* |
kbruil | 22:c01f61be07e0 | 41 | * |
kbruil | 22:c01f61be07e0 | 42 | * PURPOSE: |
kbruil | 22:c01f61be07e0 | 43 | * This object designs digital filters and filters digital data streams |
kbruil | 22:c01f61be07e0 | 44 | * |
kbruil | 22:c01f61be07e0 | 45 | * USAGE: |
kbruil | 22:c01f61be07e0 | 46 | * Invoke an object of type Filter. Two constructors are available. |
kbruil | 22:c01f61be07e0 | 47 | * One is used for LPF and HPF filters, one is used for BPFs. |
kbruil | 22:c01f61be07e0 | 48 | * The arguments to the constructors are as follows: |
kbruil | 22:c01f61be07e0 | 49 | * |
kbruil | 22:c01f61be07e0 | 50 | * // For LPF or HPF only |
kbruil | 22:c01f61be07e0 | 51 | * Filter(filterType filt_t, int num_taps, double Fs, double Fx); |
kbruil | 22:c01f61be07e0 | 52 | * // For BPF only |
kbruil | 22:c01f61be07e0 | 53 | * Filter(filterType filt_t, int num_taps, double Fs, double Fl, double Fu); |
kbruil | 22:c01f61be07e0 | 54 | * |
kbruil | 22:c01f61be07e0 | 55 | * filt_t: is LPF, HPF or BPF |
kbruil | 22:c01f61be07e0 | 56 | * num_taps: is the number of taps you want the filter to use |
kbruil | 22:c01f61be07e0 | 57 | * Fs: is the sampling frequency of the digital data being filtered |
kbruil | 22:c01f61be07e0 | 58 | * Fx: is the "transition" frequency for LPF and HPF filters |
kbruil | 22:c01f61be07e0 | 59 | * Fl, Fu: are the upper and lower transition frequencies for BPF filters |
kbruil | 22:c01f61be07e0 | 60 | * |
kbruil | 22:c01f61be07e0 | 61 | * Once the filter is created, you can start filtering data. Here |
kbruil | 22:c01f61be07e0 | 62 | * is an example for 51 tap lowpass filtering of an audio stream sampled at |
kbruil | 22:c01f61be07e0 | 63 | * 44.1Khz (the CD sampling rate), where the goal is to create a signal |
kbruil | 22:c01f61be07e0 | 64 | * of "telephone" bandwidth (4Khz): |
kbruil | 22:c01f61be07e0 | 65 | * |
kbruil | 22:c01f61be07e0 | 66 | * Filter *my_filter; |
kbruil | 22:c01f61be07e0 | 67 | * |
kbruil | 22:c01f61be07e0 | 68 | * my_filter = new Filter(LPF, 51, 44.1, 4.0) |
kbruil | 22:c01f61be07e0 | 69 | * if( my_filter->get_error_flag() != 0 ) // abort in an appropriate manner |
kbruil | 22:c01f61be07e0 | 70 | * |
kbruil | 22:c01f61be07e0 | 71 | * while(data_to_be_filtered){ |
kbruil | 22:c01f61be07e0 | 72 | * next_sample = // Get the next sample from the data stream somehow |
kbruil | 22:c01f61be07e0 | 73 | * filtered_sample = my_filter->do_sample( next_sample ); |
kbruil | 22:c01f61be07e0 | 74 | * . |
kbruil | 22:c01f61be07e0 | 75 | * . |
kbruil | 22:c01f61be07e0 | 76 | * . |
kbruil | 22:c01f61be07e0 | 77 | * } |
kbruil | 22:c01f61be07e0 | 78 | * delete my_filter; |
kbruil | 22:c01f61be07e0 | 79 | * |
kbruil | 22:c01f61be07e0 | 80 | * Several helper functions are provided: |
kbruil | 22:c01f61be07e0 | 81 | * init(): The filter can be re-initialized with a call to this function |
kbruil | 22:c01f61be07e0 | 82 | * get_taps(double *taps): returns the filter taps in the array "taps" |
kbruil | 22:c01f61be07e0 | 83 | * write_taps_to_file(char *filename): writes the filter taps to a file |
kbruil | 22:c01f61be07e0 | 84 | * write_freqres_to_file(char *filename): output frequency response to a file |
kbruil | 22:c01f61be07e0 | 85 | * |
kbruil | 22:c01f61be07e0 | 86 | * Finally, a get_error_flag() function is provided. Recommended usage |
kbruil | 22:c01f61be07e0 | 87 | * is to check the get_error_flag() return value for a non-zero |
kbruil | 22:c01f61be07e0 | 88 | * value after the new Filter object is created. If it is non-zero, print |
kbruil | 22:c01f61be07e0 | 89 | * out the non-zero value and look at the following table to see the |
kbruil | 22:c01f61be07e0 | 90 | * error: |
kbruil | 22:c01f61be07e0 | 91 | * -1: Fs <= 0 |
kbruil | 22:c01f61be07e0 | 92 | * -2: Fx <= 0 or Fx >= Fs/2 |
kbruil | 22:c01f61be07e0 | 93 | * -3: num_taps <= 0 or num_taps >= MAX_NUM_FILTER_TAPS |
kbruil | 22:c01f61be07e0 | 94 | * -4: memory allocation for the needed arrays failed |
kbruil | 22:c01f61be07e0 | 95 | * -5: an invalid filterType was passed into a constructor |
kbruil | 22:c01f61be07e0 | 96 | * -10: Fs <= 0 (BPF case) |
kbruil | 22:c01f61be07e0 | 97 | * -11: Fl >= Fu |
kbruil | 22:c01f61be07e0 | 98 | * -12: Fl <= 0 || Fl >= Fs/2 |
kbruil | 22:c01f61be07e0 | 99 | * -13: Fu <= 0 || Fu >= Fs/2 |
kbruil | 22:c01f61be07e0 | 100 | * -14: num_taps <= 0 or num_taps >= MAX_NUM_FILTER_TAPS (BPF case) |
kbruil | 22:c01f61be07e0 | 101 | * -15: memory allocation for the needed arrays failed (BPF case) |
kbruil | 22:c01f61be07e0 | 102 | * -16: an invalid filterType was passed into a constructor (BPF case) |
kbruil | 22:c01f61be07e0 | 103 | * |
kbruil | 22:c01f61be07e0 | 104 | * Note that if a non-zero error code value occurs, every call to do_sample() |
kbruil | 22:c01f61be07e0 | 105 | * will return the value 0. write_taps_fo_file() will fail and return a -1 (it |
kbruil | 22:c01f61be07e0 | 106 | * also returns a -1 if it fails to open the tap file passed into it). |
kbruil | 22:c01f61be07e0 | 107 | * get_taps() will have no effect on the array passed in if the error_flag |
kbruil | 22:c01f61be07e0 | 108 | * is non-zero. write_freqres_to_file( ) returns different error codes |
kbruil | 22:c01f61be07e0 | 109 | * depending on the nature of the error...see the function itself for details. |
kbruil | 22:c01f61be07e0 | 110 | * |
kbruil | 22:c01f61be07e0 | 111 | * The filters are designed using the "Fourier Series Method". This |
kbruil | 22:c01f61be07e0 | 112 | * means that the coefficients of a Fourier Series approximation to the |
kbruil | 22:c01f61be07e0 | 113 | * frequency response of an ideal filter (LPF, HPF, BPF) are used as |
kbruil | 22:c01f61be07e0 | 114 | * the filter taps. The resulting filters have some ripple in the passband |
kbruil | 22:c01f61be07e0 | 115 | * due to the Gibbs phenomenon; the filters are linear phase. |
kbruil | 22:c01f61be07e0 | 116 | */ |
kbruil | 22:c01f61be07e0 | 117 | |
kbruil | 22:c01f61be07e0 | 118 | #ifndef _FILTER_H |
kbruil | 22:c01f61be07e0 | 119 | #define _FILTER_H |
kbruil | 22:c01f61be07e0 | 120 | |
kbruil | 22:c01f61be07e0 | 121 | #define MAX_NUM_FILTER_TAPS 1000 |
kbruil | 22:c01f61be07e0 | 122 | |
kbruil | 22:c01f61be07e0 | 123 | #include <stdio.h> |
kbruil | 22:c01f61be07e0 | 124 | #include <math.h> |
kbruil | 22:c01f61be07e0 | 125 | #include <stdlib.h> |
kbruil | 22:c01f61be07e0 | 126 | //#include <unistd.h> |
kbruil | 22:c01f61be07e0 | 127 | #include <string.h> |
kbruil | 22:c01f61be07e0 | 128 | #include <inttypes.h> |
kbruil | 22:c01f61be07e0 | 129 | |
kbruil | 22:c01f61be07e0 | 130 | #ifndef M_PI |
kbruil | 22:c01f61be07e0 | 131 | #define M_PI 3.14159265358979323846 |
kbruil | 22:c01f61be07e0 | 132 | #endif |
kbruil | 22:c01f61be07e0 | 133 | |
kbruil | 22:c01f61be07e0 | 134 | enum filterType {LPF, HPF, BPF}; |
kbruil | 22:c01f61be07e0 | 135 | |
kbruil | 22:c01f61be07e0 | 136 | class Filter{ |
kbruil | 22:c01f61be07e0 | 137 | private: |
kbruil | 22:c01f61be07e0 | 138 | filterType m_filt_t; |
kbruil | 22:c01f61be07e0 | 139 | int m_num_taps; |
kbruil | 22:c01f61be07e0 | 140 | int m_error_flag; |
kbruil | 22:c01f61be07e0 | 141 | double m_Fs; |
kbruil | 22:c01f61be07e0 | 142 | double m_Fx; |
kbruil | 22:c01f61be07e0 | 143 | double m_lambda; |
kbruil | 22:c01f61be07e0 | 144 | double *m_taps; |
kbruil | 22:c01f61be07e0 | 145 | double *m_sr; |
kbruil | 22:c01f61be07e0 | 146 | void designLPF(); |
kbruil | 22:c01f61be07e0 | 147 | void designHPF(); |
kbruil | 22:c01f61be07e0 | 148 | |
kbruil | 22:c01f61be07e0 | 149 | // Only needed for the bandpass filter case |
kbruil | 22:c01f61be07e0 | 150 | double m_Fu, m_phi; |
kbruil | 22:c01f61be07e0 | 151 | void designBPF(); |
kbruil | 22:c01f61be07e0 | 152 | |
kbruil | 22:c01f61be07e0 | 153 | public: |
kbruil | 22:c01f61be07e0 | 154 | Filter(filterType filt_t, int num_taps, double Fs, double Fx); |
kbruil | 22:c01f61be07e0 | 155 | Filter(filterType filt_t, int num_taps, double Fs, double Fl, double Fu); |
kbruil | 22:c01f61be07e0 | 156 | ~Filter( ); |
kbruil | 22:c01f61be07e0 | 157 | void init(); |
kbruil | 22:c01f61be07e0 | 158 | double do_sample(double data_sample); |
kbruil | 22:c01f61be07e0 | 159 | int get_error_flag(){return m_error_flag;}; |
kbruil | 22:c01f61be07e0 | 160 | void get_taps( double *taps ); |
kbruil | 22:c01f61be07e0 | 161 | int write_taps_to_file( char* filename ); |
kbruil | 22:c01f61be07e0 | 162 | int write_freqres_to_file( char* filename ); |
kbruil | 22:c01f61be07e0 | 163 | }; |
kbruil | 22:c01f61be07e0 | 164 | |
kbruil | 22:c01f61be07e0 | 165 | #endif |