Project Paint / Mbed 2 deprecated EMG-Processing

Dependencies:   biquadFilter mbed

Committer:
Jankoekenpan
Date:
Thu Nov 03 10:01:14 2016 +0000
Revision:
5:dd261ba7b047
Parent:
calibrate.cpp@4:4de31fc4f912
working test version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ofosakar 0:44d3f99b08c1 1 #include "mbed.h"
ofosakar 0:44d3f99b08c1 2 #include "BiQuad.h"
ofosakar 2:8b790c03a760 3 // BUTTON USED IN CALIBRATION
ofosakar 1:984b6b6812c7 4 DigitalIn calibrating(SW2);
ofosakar 2:8b790c03a760 5 // BUTTON TO START CALIBRATING
ofosakar 1:984b6b6812c7 6 InterruptIn calibrateButton(SW3);
ofosakar 2:8b790c03a760 7 // THE TWO EMG SIGNALS
ofosakar 2:8b790c03a760 8 AnalogIn emg1(A0);
ofosakar 2:8b790c03a760 9 AnalogIn emg2(A1);
ofosakar 0:44d3f99b08c1 10 Serial pc(USBTX, USBRX);
ofosakar 0:44d3f99b08c1 11
ofosakar 2:8b790c03a760 12 // LEDS
ofosakar 0:44d3f99b08c1 13 DigitalOut led_red(LED_RED);
ofosakar 0:44d3f99b08c1 14 DigitalOut led_green(LED_GREEN);
ofosakar 1:984b6b6812c7 15 DigitalOut led_blue(LED_BLUE);
ofosakar 1:984b6b6812c7 16
ofosakar 2:8b790c03a760 17 // EMG BIQUAD 1
ofosakar 2:8b790c03a760 18 BiQuadChain bqc1;
Jankoekenpan 5:dd261ba7b047 19 //Notch iir filter.
Jankoekenpan 5:dd261ba7b047 20 //Notch: 50 +- 2 Hz
Jankoekenpan 5:dd261ba7b047 21 BiQuad bq11(9.93756e-01, -1.89024e+00, 9.93756e-01, -1.89024e+00, 9.87512e-01 );
ofosakar 0:44d3f99b08c1 22
ofosakar 0:44d3f99b08c1 23
ofosakar 2:8b790c03a760 24 // EMG BIQUAD 2
ofosakar 2:8b790c03a760 25 BiQuadChain bqc2;
Jankoekenpan 5:dd261ba7b047 26 //Notch iir filter.
Jankoekenpan 5:dd261ba7b047 27 //Notch: 50 +- 2 Hz
ofosakar 2:8b790c03a760 28 BiQuad bq12( 9.93756e-01, -1.89024e+00, 9.93756e-01, -1.89024e+00, 9.87512e-01 );
ofosakar 0:44d3f99b08c1 29
ofosakar 2:8b790c03a760 30 // ARRAYS USED IN CALIBRATING THE EMG SIGNALS
ofosakar 0:44d3f99b08c1 31 const int calibrateNumEmgCache = 100;
ofosakar 0:44d3f99b08c1 32 float calibrateEmgCache1[calibrateNumEmgCache]; //sorted from new to old;
ofosakar 0:44d3f99b08c1 33 float calibrateEmgCache2[calibrateNumEmgCache]; //sorted from new to old;
ofosakar 0:44d3f99b08c1 34
ofosakar 2:8b790c03a760 35 // ARRAYS USED IN CALCULATION OF THE MOVAG
Jankoekenpan 4:4de31fc4f912 36 // Values in these arrays contain samples that are already notched and rectified.
ofosakar 2:8b790c03a760 37 const int numEmgCache = 50;
ofosakar 2:8b790c03a760 38 float emgCache1[numEmgCache]; //sorted from new to old;
ofosakar 2:8b790c03a760 39 float emgCache2[numEmgCache]; //sorted from new to old;
ofosakar 2:8b790c03a760 40
ofosakar 2:8b790c03a760 41
ofosakar 2:8b790c03a760 42 // THRESHOLDS FOR THE DECISION: BY DEFAULT 0.2,
ofosakar 2:8b790c03a760 43 // BUT SHOULD BE CHANGED IN THE CALIBRATION PHASE AT THE BEGINNING
ofosakar 1:984b6b6812c7 44 volatile float threshold1 = 0.2;
ofosakar 1:984b6b6812c7 45 volatile float threshold2 = 0.2;
ofosakar 0:44d3f99b08c1 46
ofosakar 2:8b790c03a760 47 // NUMBERS
ofosakar 2:8b790c03a760 48 int decided1[numEmgCache];
ofosakar 2:8b790c03a760 49 int decided2[numEmgCache];
ofosakar 2:8b790c03a760 50
ofosakar 2:8b790c03a760 51
ofosakar 2:8b790c03a760 52 Ticker ticker;
ofosakar 0:44d3f99b08c1 53 Ticker sampler;
ofosakar 0:44d3f99b08c1 54
ofosakar 0:44d3f99b08c1 55 float sample_frequency = 500.0f; //Hz
ofosakar 0:44d3f99b08c1 56 float Ts = 1.0f / sample_frequency;
ofosakar 2:8b790c03a760 57 // USED FOR COUNTING HOW MANY SIGNALS HAVE PASSED
ofosakar 2:8b790c03a760 58 volatile int count = 0;
ofosakar 0:44d3f99b08c1 59
ofosakar 3:082ba262d2ec 60 // FUNC TO SEND THE DATA TO THE MOTOR
ofosakar 3:082ba262d2ec 61 void (*motorFunc)(bool, bool);
ofosakar 3:082ba262d2ec 62
ofosakar 3:082ba262d2ec 63
ofosakar 2:8b790c03a760 64 ////////////////////////////////////
ofosakar 2:8b790c03a760 65 ///////// HELPER FUNCTIONS /////////
ofosakar 2:8b790c03a760 66 ////////////////////////////////////
ofosakar 2:8b790c03a760 67 void resetLeds() {
ofosakar 2:8b790c03a760 68 led_red = true;
ofosakar 2:8b790c03a760 69 led_green = true;
ofosakar 2:8b790c03a760 70 led_blue = true;
ofosakar 2:8b790c03a760 71 }
ofosakar 0:44d3f99b08c1 72
ofosakar 2:8b790c03a760 73 void addFirst(float newValue, float array[], int size) {
ofosakar 2:8b790c03a760 74 for (int i = size - 2; i >= 0; i--) {
ofosakar 2:8b790c03a760 75 array[i+1] = array[i];
ofosakar 2:8b790c03a760 76 }
ofosakar 2:8b790c03a760 77 array[0] = newValue;
ofosakar 0:44d3f99b08c1 78 }
ofosakar 2:8b790c03a760 79 void addFirst(int newValue, int array[], int size) {
ofosakar 0:44d3f99b08c1 80 for (int i = size - 2; i >= 0; i--) {
ofosakar 0:44d3f99b08c1 81 array[i+1] = array[i];
ofosakar 0:44d3f99b08c1 82 }
ofosakar 0:44d3f99b08c1 83 array[0] = newValue;
ofosakar 2:8b790c03a760 84 }
ofosakar 2:8b790c03a760 85
ofosakar 2:8b790c03a760 86 //shifts the array by adding the new emg value up front.
ofosakar 2:8b790c03a760 87 //returns the new calculated average
ofosakar 2:8b790c03a760 88 float movingAverage(float newValue, float array[], int size) {
ofosakar 2:8b790c03a760 89 float sum = 0;
ofosakar 2:8b790c03a760 90 for (int i = size - 2; i >= 0; i--) {
ofosakar 2:8b790c03a760 91 array[i+1] = array[i];
ofosakar 2:8b790c03a760 92 sum += array[i];
ofosakar 2:8b790c03a760 93 }
ofosakar 2:8b790c03a760 94 array[0] = newValue;
ofosakar 2:8b790c03a760 95 sum += newValue;
ofosakar 2:8b790c03a760 96 return sum / size;
ofosakar 0:44d3f99b08c1 97 }
ofosakar 0:44d3f99b08c1 98
ofosakar 2:8b790c03a760 99 float sum(float array[], int size) {
ofosakar 2:8b790c03a760 100 float sum = 0;
ofosakar 0:44d3f99b08c1 101 for (int i = 0; i < size; i++) {
ofosakar 2:8b790c03a760 102 sum += array[i];
ofosakar 0:44d3f99b08c1 103 }
ofosakar 2:8b790c03a760 104 return sum;
ofosakar 2:8b790c03a760 105 }
ofosakar 2:8b790c03a760 106
ofosakar 2:8b790c03a760 107 float mean(float array[], int size) {
ofosakar 2:8b790c03a760 108 return sum(array, size) / size;
ofosakar 0:44d3f99b08c1 109 }
ofosakar 0:44d3f99b08c1 110
ofosakar 2:8b790c03a760 111 float meanSquare(float array[], int size) {
ofosakar 2:8b790c03a760 112 float naam[size];
ofosakar 2:8b790c03a760 113 for(int i = 0; i < size; i++) {
ofosakar 2:8b790c03a760 114 naam[i] = pow(array[i], 2);
ofosakar 2:8b790c03a760 115 }
ofosakar 2:8b790c03a760 116 return sum(naam, size) / size;
ofosakar 0:44d3f99b08c1 117 }
ofosakar 0:44d3f99b08c1 118
ofosakar 2:8b790c03a760 119 int decide(float value, float threshold) {
ofosakar 2:8b790c03a760 120 return value < threshold ? 0 : 1;
ofosakar 2:8b790c03a760 121 }
ofosakar 2:8b790c03a760 122
ofosakar 2:8b790c03a760 123 float rectifier(float value) {
ofosakar 2:8b790c03a760 124 return fabs(value - 0.5f)*2.0f;
ofosakar 2:8b790c03a760 125 }
ofosakar 3:082ba262d2ec 126
ofosakar 3:082ba262d2ec 127
ofosakar 3:082ba262d2ec 128 void sendToMotor(void (*func)(bool, bool), bool arg1, bool arg2) {
ofosakar 3:082ba262d2ec 129 func(arg1, arg2);
ofosakar 3:082ba262d2ec 130 }
ofosakar 2:8b790c03a760 131 ////////////////////////////////////
ofosakar 2:8b790c03a760 132 ///////// HELPER FUNCTIONS /////////
ofosakar 2:8b790c03a760 133 ////////////////////////////////////
ofosakar 2:8b790c03a760 134
ofosakar 0:44d3f99b08c1 135 void sample() {
ofosakar 2:8b790c03a760 136 float emgOne = emg1.read();
Jankoekenpan 5:dd261ba7b047 137 float notch1 = bqc1.step( emgOne );
ofosakar 0:44d3f99b08c1 138
ofosakar 2:8b790c03a760 139 float emgTwo = emg2.read();
Jankoekenpan 5:dd261ba7b047 140 float notch2 = bqc2.step( emgTwo );
ofosakar 0:44d3f99b08c1 141
ofosakar 2:8b790c03a760 142 float rect1 = rectifier(notch1);
ofosakar 2:8b790c03a760 143 float rect2 = rectifier(notch2);
ofosakar 0:44d3f99b08c1 144
ofosakar 2:8b790c03a760 145 float filtered1 = movingAverage( rect1, calibrateEmgCache1, calibrateNumEmgCache);
ofosakar 2:8b790c03a760 146 float filtered2 = movingAverage( rect2, calibrateEmgCache2, calibrateNumEmgCache);
ofosakar 0:44d3f99b08c1 147 }
ofosakar 0:44d3f99b08c1 148
ofosakar 1:984b6b6812c7 149 void calibrate() {
ofosakar 1:984b6b6812c7 150 while(calibrating) {
ofosakar 1:984b6b6812c7 151 led_red = false;
ofosakar 1:984b6b6812c7 152 wait(0.5);
ofosakar 1:984b6b6812c7 153 led_red = true;
ofosakar 1:984b6b6812c7 154 wait(0.5);
ofosakar 1:984b6b6812c7 155 }
ofosakar 1:984b6b6812c7 156
ofosakar 1:984b6b6812c7 157 // Button pressed for rest measurement
ofosakar 1:984b6b6812c7 158 led_red = true;
ofosakar 1:984b6b6812c7 159 sampler.attach(&sample, Ts);
ofosakar 1:984b6b6812c7 160 led_blue = false;
ofosakar 1:984b6b6812c7 161 wait(10);
ofosakar 1:984b6b6812c7 162 // 10 seconds sampled
ofosakar 1:984b6b6812c7 163 led_blue = true;
ofosakar 1:984b6b6812c7 164 sampler.detach();
ofosakar 2:8b790c03a760 165 float restAvg1 = mean(calibrateEmgCache1, calibrateNumEmgCache);
ofosakar 2:8b790c03a760 166 float restAvg2 = mean(calibrateEmgCache2, calibrateNumEmgCache);
ofosakar 1:984b6b6812c7 167
ofosakar 1:984b6b6812c7 168 int i =0;
ofosakar 1:984b6b6812c7 169 while(i<3) {
ofosakar 1:984b6b6812c7 170 led_green = false;
ofosakar 1:984b6b6812c7 171 wait(0.5);
ofosakar 1:984b6b6812c7 172 led_green = true;
ofosakar 1:984b6b6812c7 173 wait(0.5);
ofosakar 1:984b6b6812c7 174 i++;
ofosakar 1:984b6b6812c7 175 }
ofosakar 1:984b6b6812c7 176 led_green = true;
ofosakar 1:984b6b6812c7 177
ofosakar 1:984b6b6812c7 178 while(calibrating) {
ofosakar 1:984b6b6812c7 179 led_red = false;
ofosakar 1:984b6b6812c7 180 wait(0.5);
ofosakar 1:984b6b6812c7 181 led_red = true;
ofosakar 1:984b6b6812c7 182 wait(0.5);
ofosakar 1:984b6b6812c7 183 }
ofosakar 1:984b6b6812c7 184 // Button pressed for contracted measurement
ofosakar 1:984b6b6812c7 185 led_red = true;
ofosakar 1:984b6b6812c7 186 sampler.attach(&sample, Ts);
ofosakar 1:984b6b6812c7 187 led_blue = false;
ofosakar 1:984b6b6812c7 188 wait(10);
ofosakar 1:984b6b6812c7 189
ofosakar 1:984b6b6812c7 190 // 10 seconds sampled
ofosakar 1:984b6b6812c7 191 led_blue = true;
ofosakar 1:984b6b6812c7 192 sampler.detach();
ofosakar 1:984b6b6812c7 193
ofosakar 1:984b6b6812c7 194 i =0;
ofosakar 1:984b6b6812c7 195 while(i<3) {
ofosakar 1:984b6b6812c7 196 led_green = false;
ofosakar 1:984b6b6812c7 197 wait(0.5);
ofosakar 1:984b6b6812c7 198 led_green = true;
ofosakar 1:984b6b6812c7 199 wait(0.5);
ofosakar 1:984b6b6812c7 200 i++;
ofosakar 1:984b6b6812c7 201 }
ofosakar 1:984b6b6812c7 202
ofosakar 2:8b790c03a760 203 float contAvg1 = mean(calibrateEmgCache1, calibrateNumEmgCache);
ofosakar 2:8b790c03a760 204 float contAvg2 = mean(calibrateEmgCache2, calibrateNumEmgCache);
ofosakar 1:984b6b6812c7 205
ofosakar 1:984b6b6812c7 206 threshold1 = (contAvg1 + restAvg1)/2;
ofosakar 1:984b6b6812c7 207 threshold2 = (contAvg2 + restAvg2)/2;
ofosakar 1:984b6b6812c7 208 pc.printf("threshold1: %f\tthreshold2:%f\n\r", threshold1, threshold2);
ofosakar 1:984b6b6812c7 209
ofosakar 1:984b6b6812c7 210 }
ofosakar 2:8b790c03a760 211
ofosakar 2:8b790c03a760 212 void processEMG() {
ofosakar 2:8b790c03a760 213 float emgOne = emg1.read();
ofosakar 2:8b790c03a760 214 float emgTwo = emg2.read();
ofosakar 2:8b790c03a760 215 float notch1 = bqc1.step( emgOne );
ofosakar 2:8b790c03a760 216 float notch2 = bqc2.step( emgTwo );
ofosakar 2:8b790c03a760 217
ofosakar 2:8b790c03a760 218 float rect1 = rectifier(notch1);
ofosakar 2:8b790c03a760 219 float rect2 = rectifier(notch2);
ofosakar 2:8b790c03a760 220
ofosakar 2:8b790c03a760 221 float filtered1 = movingAverage( rect1, emgCache1, numEmgCache);
ofosakar 2:8b790c03a760 222 float filtered2 = movingAverage( rect2, emgCache2, numEmgCache);
ofosakar 2:8b790c03a760 223
Jankoekenpan 4:4de31fc4f912 224 int decide1 = decide(mean(emgCache1, numEmgCache ), threshold1);
Jankoekenpan 4:4de31fc4f912 225 int decide2 = decide(mean(emgCache2, numEmgCache ), threshold2);
ofosakar 2:8b790c03a760 226 addFirst(decide1, decided1, numEmgCache);
Jankoekenpan 5:dd261ba7b047 227 addFirst(decide2, decided2, numEmgCache);
ofosakar 2:8b790c03a760 228
Jankoekenpan 4:4de31fc4f912 229 if (count >= 49) {
ofosakar 2:8b790c03a760 230 int counter1=0;
ofosakar 2:8b790c03a760 231 int counter2=0;
ofosakar 2:8b790c03a760 232 for(int i = 0; i < numEmgCache; ++i){
ofosakar 2:8b790c03a760 233 if(decided1[i] == 0)
ofosakar 2:8b790c03a760 234 ++counter1;
ofosakar 2:8b790c03a760 235 if(decided2[i] == 0)
ofosakar 2:8b790c03a760 236 ++counter2;
ofosakar 2:8b790c03a760 237 }
ofosakar 2:8b790c03a760 238 int avgDecide1 = counter1 > std::ceil(numEmgCache/2.0) ? 0: 1;
ofosakar 2:8b790c03a760 239 int avgDecide2 = counter2 > std::ceil(numEmgCache/2.0) ? 0: 1;
ofosakar 3:082ba262d2ec 240 sendToMotor(motorFunc,avgDecide1, avgDecide2);
Jankoekenpan 5:dd261ba7b047 241
ofosakar 2:8b790c03a760 242 count =0;
ofosakar 2:8b790c03a760 243 } else {
ofosakar 2:8b790c03a760 244 count++;
ofosakar 2:8b790c03a760 245 }
ofosakar 2:8b790c03a760 246 }
ofosakar 2:8b790c03a760 247
ofosakar 3:082ba262d2ec 248 void consumeBools(bool x, bool y) {
Jankoekenpan 5:dd261ba7b047 249 pc.printf("%d\t%d\r\n", x, y);
ofosakar 3:082ba262d2ec 250 }
ofosakar 1:984b6b6812c7 251 int main()
ofosakar 1:984b6b6812c7 252 {
ofosakar 1:984b6b6812c7 253 pc.baud(115200);
ofosakar 2:8b790c03a760 254
ofosakar 2:8b790c03a760 255 // initial state
ofosakar 2:8b790c03a760 256 resetLeds();
Jankoekenpan 5:dd261ba7b047 257
Jankoekenpan 5:dd261ba7b047 258 // initialize notch filters
Jankoekenpan 5:dd261ba7b047 259 bqc1.add( &bq11 );
Jankoekenpan 5:dd261ba7b047 260 bqc2.add( &bq12 );
Jankoekenpan 5:dd261ba7b047 261
Jankoekenpan 5:dd261ba7b047 262
ofosakar 1:984b6b6812c7 263 calibrateButton.fall(&calibrate);
ofosakar 3:082ba262d2ec 264 // TODO CHANGE THIS TO THE DESIERD FUNCTION (THAT JAN MADE)
ofosakar 3:082ba262d2ec 265 motorFunc = &consumeBools;
Jankoekenpan 5:dd261ba7b047 266
ofosakar 1:984b6b6812c7 267
Jankoekenpan 5:dd261ba7b047 268 // call the calibrating function once at the start
Jankoekenpan 5:dd261ba7b047 269 // this function blocks until the calibration phase is over
Jankoekenpan 5:dd261ba7b047 270 calibrate();
ofosakar 2:8b790c03a760 271
ofosakar 2:8b790c03a760 272 // 500 HZ Ticker
Jankoekenpan 5:dd261ba7b047 273 ticker.attach(&processEMG, Ts);
ofosakar 2:8b790c03a760 274 while (true);
ofosakar 2:8b790c03a760 275 }