I've got some basic filter code setup (but not yet tested).
Dependencies: BLE_API Queue mbed nRF51822
Fork of BLE_HeartRate by
Revision 61:1de72bdab0ef, committed 2015-05-17
- Comitter:
- roysandberg
- Date:
- Sun May 17 00:27:16 2015 +0000
- Parent:
- 60:79da561d849b
- Child:
- 62:8e2fbe131b53
- Commit message:
- Initial release;
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/filter.cpp Sun May 17 00:27:16 2015 +0000 @@ -0,0 +1,70 @@ +// Bandpass the 1000Hz sampling rate to only allow signals that could be heart rate frequencies +// https://www.keil.com/pack/doc/CMSIS/DSP/html/arm_fir_example_f32_8c-example.html + +#define TEST_LENGTH_SAMPLES 320 +#define BLOCK_SIZE 32 +#define NUM_TAPS 51 +#define PER_MINUTE 60 + +#define MIN_HEARTRATE (30.0/PER_MINUTE) +#define MAX_HEARTRATE (120.0/PER_MINUTE) + +int blockSize = BLOCK_SIZE; +int numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE; + +static float testOutput[TEST_LENGTH_SAMPLES]; +static float firStateF32[BLOCK_SIZE + NUM_TAPS - 1]; + +// TODO: USE CORRECT FREQUENCY FOR HEART RATE. +// 51-tap FIR filter @1000Hz sampling rate, 30Hz-120Hz pass, 50dB attenuation: http://www.arc.id.au/FilterDesign.html +float firCoeffs32[NUM_TAPS] = {0.000707, +0.000317, +-0.000103, +0.000151, +0.001621, +0.004056, +0.006124, +0.005903, +0.002063, +-0.004881, +-0.012196, +-0.016049, +-0.013847, +-0.006569, +0.000551, +-0.000000, +-0.013828, +-0.040240, +-0.070297, +-0.089104, +-0.082037, +-0.042270, +0.024193, +0.098977, +0.157748, +0.180000, +0.157748, +0.098977, +0.024193, +-0.042270, +-0.082037, +-0.089104, +-0.070297, +-0.040240, +-0.013828, +-0.000000, +0.000551, +-0.006569, +-0.013847, +-0.016049, +-0.012196, +-0.004881, +0.002063, +0.005903, +0.006124, +0.004056, +0.001621, +0.000151, +-0.000103, +0.000317, +0.000707}; \ No newline at end of file
--- a/main.cpp Mon May 11 07:04:53 2015 +0000 +++ b/main.cpp Sun May 17 00:27:16 2015 +0000 @@ -25,12 +25,17 @@ * interval.*/ #define UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL 0 +extern void setup_sampler(void (*function)(uint32_t)); + BLEDevice ble; DigitalOut led1(LED1); +volatile uint8_t hrmCounter = 100; // init HRM to 100bps + const static char DEVICE_NAME[] = "HRM1"; static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE, - GattService::UUID_DEVICE_INFORMATION_SERVICE}; + GattService::UUID_DEVICE_INFORMATION_SERVICE + }; static volatile bool triggerSensorPolling = false; void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) @@ -38,26 +43,37 @@ ble.startAdvertising(); // restart advertising } -void periodicCallback(void) +//void periodicCallback(void) +//{ +// led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ +// +// /* Note that the periodicCallback() executes in interrupt context, so it is safer to do +// * heavy-weight sensor polling from the main thread. */ +// triggerSensorPolling = true; +//} + +void sampler_callback(uint32_t value) { - led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ - - /* Note that the periodicCallback() executes in interrupt context, so it is safer to do - * heavy-weight sensor polling from the main thread. */ + hrmCounter = (uint8_t) (value); +// led1 = !led1; triggerSensorPolling = true; } int main(void) { led1 = 1; - Ticker ticker; - ticker.attach(periodicCallback, 1); // blink LED every second + // Ticker ticker; + //ticker.attach(periodicCallback, 0.1); // blink LED every second + + printf("Executing code...\n"); + + setup_sampler(&sampler_callback); ble.init(); ble.onDisconnection(disconnectionCallback); /* Setup primary service. */ - uint8_t hrmCounter = 100; // init HRM to 100bps + //uint8_t hrmCounter = 100; // init HRM to 100bps HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER); /* Setup auxiliary service. */ @@ -78,15 +94,18 @@ if (triggerSensorPolling && ble.getGapState().connected) { triggerSensorPolling = false; - // Do blocking calls or whatever is necessary for sensor polling. - // In our case, we simply update the HRM measurement. - hrmCounter++; - - // 100 <= HRM bps <=175 - if (hrmCounter == 175) { - hrmCounter = 100; - } - + led1 = !led1; + + printf("v=%d\n", hrmCounter); +// // Do blocking calls or whatever is necessary for sensor polling. +// // In our case, we simply update the HRM measurement. +// hrmCounter++; +// +// // 100 <= HRM bps <=175 +// if (hrmCounter == 175) { +// hrmCounter = 100; +// } + // update bps hrService.updateHeartRate(hrmCounter); } else {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sampler.cpp Sun May 17 00:27:16 2015 +0000 @@ -0,0 +1,36 @@ +#include "mbed.h" + +// Use a ticker (interrupt routine) to sample the ADC at a fast rate (is 200Khz the max?), and generate an average value +// Use another ticker to grab the average value at 1Khz, which is the maximum useful sampling rate for HRV data collection + + +// These need to divide evenly into each other +#define SAMPLING_RATE_HZ 4000 +#define READ_OUT_RATE_HZ 50 + +#define SAMPLES_PER_READOUT (SAMPLING_RATE_HZ/READ_OUT_RATE_HZ) + +AnalogIn ECG(P0_1); +Ticker sampling_rate; +int NumReadings=0; +uint32_t ReadingTotal=0; +void (*SamplingFunction)(uint32_t); + + +void ADC_read() +{ + NumReadings++; + ReadingTotal += ECG.read_u16(); + if (NumReadings == SAMPLES_PER_READOUT) + { + SamplingFunction(ReadingTotal/NumReadings); + ReadingTotal = 0; + NumReadings = 0; + } +} + +void setup_sampler(void (*function)(uint32_t)) +{ + SamplingFunction = function; + sampling_rate.attach(&ADC_read, 1.0/SAMPLING_RATE_HZ); +}