Filter for EMG signals The signal will be filtered using a notch, highpass and lowpass filter. The filtered signal will be compared to a preset threshold and according to the strength of the signal the program will perform an action. In this case it will assign a colour to a led.

Dependencies:   HIDScope MODSERIAL mbed

Fork of EMGfilter24 by Steven Spoolder

Committer:
Iknowright
Date:
Thu Oct 27 14:55:11 2016 +0000
Revision:
4:fcada70891c5
Parent:
3:faed8b7f6542
Child:
5:51a28834cd5b
Filter for emg signals.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Iknowright 0:41226c0fd285 1 #include "mbed.h"
Iknowright 0:41226c0fd285 2 #include "BiQuad.h"
Iknowright 0:41226c0fd285 3 #include "HIDScope.h"
Iknowright 0:41226c0fd285 4 #include "MODSERIAL.h"
Nickname 3:faed8b7f6542 5 #include <math.h>
Iknowright 0:41226c0fd285 6
Nickname 1:6081dc1ecd1f 7 MODSERIAL pc(USBTX, USBRX);
Iknowright 4:fcada70891c5 8 Ticker sampleTicker;//Ticker that measures the EMG signal every 0,002 seconds and filters it
Iknowright 4:fcada70891c5 9 Ticker goTicker; //Ticker that checks if the signal threshold is reached each time a new filtered EMG signal comes in and determines if the motors are going to rotate
Iknowright 4:fcada70891c5 10 AnalogIn emgl(A1);//Labels are attached to the olimex shields the left tricep should obviously be connected to the should with an L label on it
Iknowright 4:fcada70891c5 11 AnalogIn emgr(A0);
Nickname 3:faed8b7f6542 12 DigitalOut ledG(LED_GREEN);
Nickname 3:faed8b7f6542 13 DigitalOut ledB(LED_BLUE);
Nickname 3:faed8b7f6542 14 DigitalOut ledR(LED_RED);
Iknowright 4:fcada70891c5 15 HIDScope scope(2); //scope has two ports for the two EMG signals
Iknowright 4:fcada70891c5 16
Iknowright 4:fcada70891c5 17 /*coefficients of each filter
Iknowright 4:fcada70891c5 18 lno = left tricep notch filter
Iknowright 4:fcada70891c5 19 lhf = left tricep high pass filter
Iknowright 4:fcada70891c5 20 llf = left tricep lowpass filter
Iknowright 4:fcada70891c5 21 same goes for rno etc.
Iknowright 4:fcada70891c5 22 */
Iknowright 4:fcada70891c5 23 double lno_b0 = 0.9911;
Iknowright 4:fcada70891c5 24 double lno_b1 = -1.6036;
Iknowright 4:fcada70891c5 25 double lno_b2 = 0.9911;
Iknowright 4:fcada70891c5 26 double lno_a1 = -1.603;
Iknowright 4:fcada70891c5 27 double lno_a2 = 0.9822;
Iknowright 4:fcada70891c5 28
Iknowright 4:fcada70891c5 29 double rno_b0 = 0.9911;
Iknowright 4:fcada70891c5 30 double rno_b1 = -1.6036;
Iknowright 4:fcada70891c5 31 double rno_b2 = 0.9911;
Iknowright 4:fcada70891c5 32 double rno_a1 = -1.603;
Iknowright 4:fcada70891c5 33 double rno_a2 = 0.9822;
Nickname 3:faed8b7f6542 34
Iknowright 4:fcada70891c5 35
Iknowright 4:fcada70891c5 36 double lhf_b0 = 0.9355;
Iknowright 4:fcada70891c5 37 double lhf_b1 = -1.8711;
Iknowright 4:fcada70891c5 38 double lhf_b2 = 0.9355;
Iknowright 4:fcada70891c5 39 double lhf_a1 = -1.8669;
Iknowright 4:fcada70891c5 40 double lhf_a2 = 0.8752;
Nickname 1:6081dc1ecd1f 41
Iknowright 4:fcada70891c5 42 double rhf_b0 = 0.9355;
Iknowright 4:fcada70891c5 43 double rhf_b1 = -1.8711;
Iknowright 4:fcada70891c5 44 double rhf_b2 = 0.9355;
Iknowright 4:fcada70891c5 45 double rhf_a1 = -1.8669;
Iknowright 4:fcada70891c5 46 double rhf_a2 = 0.8752;
Iknowright 4:fcada70891c5 47
Iknowright 4:fcada70891c5 48
Iknowright 4:fcada70891c5 49 double llf_b0 = 8.7656e-5;
Iknowright 4:fcada70891c5 50 double llf_b1 = 1.17531e-4;
Iknowright 4:fcada70891c5 51 double llf_b2 = 8.7656e-5;
Iknowright 4:fcada70891c5 52 double llf_a1 = -1.9733;
Iknowright 4:fcada70891c5 53 double llf_a2 = 0.9737;
Iknowright 0:41226c0fd285 54
Iknowright 4:fcada70891c5 55 double rlf_b0 = 8.7656e-5;
Iknowright 4:fcada70891c5 56 double rlf_b1 = 1.17531e-4;
Iknowright 4:fcada70891c5 57 double rlf_b2 = 8.7656e-5;
Iknowright 4:fcada70891c5 58 double rlf_a1 = -1.9733;
Iknowright 4:fcada70891c5 59 double rlf_a2 = 0.9737;
Iknowright 4:fcada70891c5 60
Iknowright 4:fcada70891c5 61
Iknowright 4:fcada70891c5 62 //starting values of the biquads of the corresponding filters
Iknowright 4:fcada70891c5 63 double lno_v1 = 0, lno_v2 = 0;
Iknowright 4:fcada70891c5 64 double lhf_v1 = 0, lhf_v2 = 0;
Iknowright 4:fcada70891c5 65 double llf_v1 = 0, llf_v2 = 0;
Iknowright 4:fcada70891c5 66
Iknowright 4:fcada70891c5 67 double rno_v1 = 0, rno_v2 = 0;
Iknowright 4:fcada70891c5 68 double rhf_v1 = 0, rhf_v2 = 0;
Iknowright 4:fcada70891c5 69 double rlf_v1 = 0, rlf_v2 = 0;
Nickname 1:6081dc1ecd1f 70
Iknowright 4:fcada70891c5 71 /* declaration of the outputs of each biquad.
Iknowright 4:fcada70891c5 72 the output of the previous biquad is the input for the next biquad.
Iknowright 4:fcada70891c5 73 so lno_y goes into lhf_y etc.
Iknowright 4:fcada70891c5 74 */
Iknowright 4:fcada70891c5 75 double lno_y;
Iknowright 4:fcada70891c5 76 double lhf_y;
Iknowright 4:fcada70891c5 77 double llf_y;
Iknowright 4:fcada70891c5 78 double lrect_y;
Iknowright 4:fcada70891c5 79 double rno_y;
Iknowright 4:fcada70891c5 80 double rhf_y;
Iknowright 4:fcada70891c5 81 double rlf_y;
Iknowright 4:fcada70891c5 82 double rrect_y;
Iknowright 0:41226c0fd285 83
Iknowright 4:fcada70891c5 84 // set the threshold value for the filtered signal
Iknowright 4:fcada70891c5 85 //if the signal exceeds this value the motors will start to rotate
Iknowright 4:fcada70891c5 86 const double threshold_value = 0.05;
Iknowright 4:fcada70891c5 87
Iknowright 4:fcada70891c5 88 /* declaration of each biquad
Iknowright 4:fcada70891c5 89 The coefficients will be filled in later on in void scopeSend
Iknowright 4:fcada70891c5 90 As said before the input of each biquad is the output of the previous one
Iknowright 4:fcada70891c5 91 The input of the first biquad is the raw EMG signal and the output of the last biquad is the filtered signal.
Iknowright 4:fcada70891c5 92 This is done for both left and right so this makes two chains of 3 biquads */
Iknowright 4:fcada70891c5 93
Iknowright 4:fcada70891c5 94 double biquad_lno(double u, double&v1 , double&v2 , const double a1 , const double a2 , const double b0 ,
Nickname 3:faed8b7f6542 95 const double b1 , const double b2 )
Nickname 1:6081dc1ecd1f 96 {
Nickname 3:faed8b7f6542 97 double v = u - a1*v1 - a2*v2;
Nickname 3:faed8b7f6542 98 double y = b0*v + b1*v1 + b2*v2;
Nickname 3:faed8b7f6542 99 v2 = v1;
Nickname 3:faed8b7f6542 100 v1 = v;
Nickname 3:faed8b7f6542 101 return y;
Nickname 3:faed8b7f6542 102 }
Nickname 3:faed8b7f6542 103
Iknowright 4:fcada70891c5 104 double biquad_lhf(double u, double&v1 , double&v2 , const double a1 , const double a2 , const double b0 ,
Nickname 3:faed8b7f6542 105 const double b1 , const double b2 )
Nickname 3:faed8b7f6542 106 {
Nickname 3:faed8b7f6542 107 double v = u - a1*v1 - a2*v2;
Nickname 3:faed8b7f6542 108 double y = b0*v + b1*v1 + b2*v2;
Nickname 3:faed8b7f6542 109 v2 = v1;
Nickname 3:faed8b7f6542 110 v1 = v;
Nickname 3:faed8b7f6542 111 return y;
Nickname 1:6081dc1ecd1f 112 }
Iknowright 0:41226c0fd285 113
Iknowright 4:fcada70891c5 114 double biquad_llf(double u, double&v1 , double&v2 , const double a1 , const double a2 , const double b0 ,
Iknowright 4:fcada70891c5 115 const double b1 , const double b2 )
Iknowright 4:fcada70891c5 116 {
Iknowright 4:fcada70891c5 117 double v = u - a1*v1 - a2*v2;
Iknowright 4:fcada70891c5 118 double y = b0*v + b1*v1 + b2*v2;
Iknowright 4:fcada70891c5 119 v2 = v1;
Iknowright 4:fcada70891c5 120 v1 = v;
Iknowright 4:fcada70891c5 121 return y;
Iknowright 4:fcada70891c5 122 }
Iknowright 4:fcada70891c5 123 double biquad_rno(double u, double&v1 , double&v2 , const double a1 , const double a2 , const double b0 ,
Iknowright 4:fcada70891c5 124 const double b1 , const double b2 )
Iknowright 4:fcada70891c5 125 {
Iknowright 4:fcada70891c5 126 double v = u - a1*v1 - a2*v2;
Iknowright 4:fcada70891c5 127 double y = b0*v + b1*v1 + b2*v2;
Iknowright 4:fcada70891c5 128 v2 = v1;
Iknowright 4:fcada70891c5 129 v1 = v;
Iknowright 4:fcada70891c5 130 return y;
Iknowright 4:fcada70891c5 131 }
Iknowright 4:fcada70891c5 132
Iknowright 4:fcada70891c5 133 double biquad_rhf(double u, double&v1 , double&v2 , const double a1 , const double a2 , const double b0 ,
Iknowright 4:fcada70891c5 134 const double b1 , const double b2 )
Iknowright 4:fcada70891c5 135 {
Iknowright 4:fcada70891c5 136 double v = u - a1*v1 - a2*v2;
Iknowright 4:fcada70891c5 137 double y = b0*v + b1*v1 + b2*v2;
Iknowright 4:fcada70891c5 138 v2 = v1;
Iknowright 4:fcada70891c5 139 v1 = v;
Iknowright 4:fcada70891c5 140 return y;
Iknowright 4:fcada70891c5 141 }
Iknowright 4:fcada70891c5 142
Iknowright 4:fcada70891c5 143 double biquad_rlf(double u, double&v1 , double&v2 , const double a1 , const double a2 , const double b0 ,
Nickname 3:faed8b7f6542 144 const double b1 , const double b2 )
Nickname 3:faed8b7f6542 145 {
Nickname 3:faed8b7f6542 146 double v = u - a1*v1 - a2*v2;
Nickname 3:faed8b7f6542 147 double y = b0*v + b1*v1 + b2*v2;
Nickname 3:faed8b7f6542 148 v2 = v1;
Nickname 3:faed8b7f6542 149 v1 = v;
Nickname 3:faed8b7f6542 150 return y;
Nickname 3:faed8b7f6542 151 }
Nickname 3:faed8b7f6542 152
Iknowright 4:fcada70891c5 153 /* function that calculates the filtered EMG signal from the raw EMG signal.
Iknowright 4:fcada70891c5 154 So 2 chains of 3 biquads each are calculating the left and the right filtered EMG signal.
Iknowright 4:fcada70891c5 155 After this is calculated, the signals are sent to HIDscope (scope.send) to see what they look like.
Iknowright 4:fcada70891c5 156 The filtered left signal (llf_y) is shown in channel 1, the filtered right signal (rlf_y)is shown in channel 0 (scope.set)*/
Nickname 3:faed8b7f6542 157 void scopeSend(void){
Iknowright 4:fcada70891c5 158 lno_y = biquad_lno(emgl.read(), lno_v1, lno_v2, lno_a1, lno_a2, lno_b0, lno_b1, lno_b2);
Iknowright 4:fcada70891c5 159 lhf_y = biquad_lhf(lno_y, lhf_v1, lhf_v2, lhf_a1, lhf_a2, lhf_b0, lhf_b1, lhf_b2);
Iknowright 4:fcada70891c5 160 lrect_y = fabs(lhf_y);
Iknowright 4:fcada70891c5 161 llf_y = biquad_llf(lrect_y, llf_v1, llf_v2, llf_a1, llf_a2, llf_b0, llf_b1, llf_b2)/0.2;
Iknowright 4:fcada70891c5 162 rno_y = biquad_rno(emgr.read(), rno_v1, rno_v2, rno_a1, rno_a2, rno_b0, rno_b1, rno_b2);
Iknowright 4:fcada70891c5 163 rhf_y = biquad_rhf(rno_y, rhf_v1, rhf_v2, rhf_a1, rhf_a2, rhf_b0, rhf_b1, rhf_b2);
Iknowright 4:fcada70891c5 164 rrect_y = fabs(rhf_y);
Iknowright 4:fcada70891c5 165 rlf_y = biquad_rlf(rrect_y, rlf_v1, rlf_v2, rlf_a1, rlf_a2, rlf_b0, rlf_b1, rlf_b2)/0.2;
Iknowright 4:fcada70891c5 166 scope.set(1, llf_y);
Iknowright 4:fcada70891c5 167 scope.set(0, rlf_y);
Nickname 3:faed8b7f6542 168 scope.send();
Nickname 3:faed8b7f6542 169
Nickname 3:faed8b7f6542 170 }
Iknowright 4:fcada70891c5 171
Iknowright 4:fcada70891c5 172 //function that compares the filtered EMG signal to the set threshold and determines what colour the led should be
Iknowright 4:fcada70891c5 173 //This led is for feedback purposes only and should obviously be replaced by the motors
Iknowright 4:fcada70891c5 174 void threshold(){
Iknowright 4:fcada70891c5 175 //If the right signal exceeds the threshold, the led should turn blue
Iknowright 4:fcada70891c5 176 if (rlf_y > threshold_value){
Iknowright 4:fcada70891c5 177 ledB = 0;
Iknowright 4:fcada70891c5 178 ledR = 1;
Iknowright 4:fcada70891c5 179 ledG = 1;
Nickname 3:faed8b7f6542 180 }
Iknowright 4:fcada70891c5 181 //If the left signal exceeds the threshold, the led should turn red
Iknowright 4:fcada70891c5 182 else if (llf_y > threshold_value){
Iknowright 4:fcada70891c5 183 ledB = 1;
Iknowright 4:fcada70891c5 184 ledR = 0;
Iknowright 4:fcada70891c5 185 ledG = 1;
Nickname 3:faed8b7f6542 186 }
Iknowright 4:fcada70891c5 187 // If both signals exceed the threshold, the led should turn green
Iknowright 4:fcada70891c5 188 else if (rlf_y&&llf_y > threshold_value){
Iknowright 4:fcada70891c5 189 ledB = 1;
Iknowright 4:fcada70891c5 190 ledR = 1;
Iknowright 4:fcada70891c5 191 ledG = 0;
Iknowright 4:fcada70891c5 192 }
Iknowright 4:fcada70891c5 193 //If no signal exceeds the threshold, the led should be off
Iknowright 4:fcada70891c5 194 else {
Iknowright 4:fcada70891c5 195 ledB=1;
Iknowright 4:fcada70891c5 196 ledG=1;
Iknowright 4:fcada70891c5 197 ledR=1;
Nickname 3:faed8b7f6542 198 }
Iknowright 4:fcada70891c5 199 }
Iknowright 4:fcada70891c5 200
Iknowright 0:41226c0fd285 201
Iknowright 0:41226c0fd285 202 int main(){
Iknowright 4:fcada70891c5 203
Iknowright 4:fcada70891c5 204
Nickname 1:6081dc1ecd1f 205
Iknowright 4:fcada70891c5 206 /*Attach the 'sample' function to the timer 'sample_timer'.
Iknowright 4:fcada70891c5 207 this ensures that 'sample' is executed every... 0.002 seconds = 500 Hz
Iknowright 4:fcada70891c5 208 emgSampleTicker.attach(&sample, 0.002);
Iknowright 4:fcada70891c5 209 empty loop, sample() is executed periodically
Iknowright 4:fcada70891c5 210 The same goes for the goTicker. It checks if the threshold is reached at the same rate new a new EMG signal comes in*/
Nickname 3:faed8b7f6542 211 sampleTicker.attach(scopeSend,0.002);
Nickname 3:faed8b7f6542 212 goTicker.attach(threshold,0.002);
Nickname 1:6081dc1ecd1f 213
Nickname 3:faed8b7f6542 214 while(1) {
Iknowright 4:fcada70891c5 215
Iknowright 4:fcada70891c5 216 }
Nickname 3:faed8b7f6542 217 }