Measuring plethysmogram with BH1792GLC (Rohm Semiconductor) and calculating pulse rate

Dependencies:   USBDevice mbed

Committer:
t_tatsuoka
Date:
Mon Feb 05 20:22:14 2018 +0000
Revision:
0:18d735a66926
Child:
1:90f70c146a26
Ver. 1.0.0 ??

Who changed what in which revision?

UserRevisionLine numberNew contents of line
t_tatsuoka 0:18d735a66926 1 /**
t_tatsuoka 0:18d735a66926 2 * @file PulseRate.cpp
t_tatsuoka 0:18d735a66926 3 * @brief Measuring plethysmogram and calc pulse rate
t_tatsuoka 0:18d735a66926 4 * @date 2018.02.03
t_tatsuoka 0:18d735a66926 5 * @version 1.1.0
t_tatsuoka 0:18d735a66926 6 */
t_tatsuoka 0:18d735a66926 7 #include "PulseRate.h"
t_tatsuoka 0:18d735a66926 8
t_tatsuoka 0:18d735a66926 9 #ifdef _OP_MODE_INT_AD
t_tatsuoka 0:18d735a66926 10 /** Constructor
t_tatsuoka 0:18d735a66926 11 * @param sensor Pin for A/D converter
t_tatsuoka 0:18d735a66926 12 * @param sync_led Pin for synchronous LED
t_tatsuoka 0:18d735a66926 13 * @param beep Pin for piezo sounder
t_tatsuoka 0:18d735a66926 14 */
t_tatsuoka 0:18d735a66926 15 PulseRate::PulseRate(PinName sensor, PinName sync_led, PinName beep) :
t_tatsuoka 0:18d735a66926 16 _sensor(sensor), _sync_led(sync_led), _beep(beep)
t_tatsuoka 0:18d735a66926 17 {
t_tatsuoka 0:18d735a66926 18 init();
t_tatsuoka 0:18d735a66926 19 }
t_tatsuoka 0:18d735a66926 20 #elif defined _OP_MODE_BH1792GLC
t_tatsuoka 0:18d735a66926 21 /** Constructor
t_tatsuoka 0:18d735a66926 22 * @param bh_sda Pin for SDA on BH1792GLC
t_tatsuoka 0:18d735a66926 23 * @param bh_scl Pin for SCL on BH1792GLC
t_tatsuoka 0:18d735a66926 24 * @param bh_int Pin for INT on BH1792GLC
t_tatsuoka 0:18d735a66926 25 * @param sync_led Pin for synchronous LED
t_tatsuoka 0:18d735a66926 26 * @param beep Pin for piezo sounder
t_tatsuoka 0:18d735a66926 27 */
t_tatsuoka 0:18d735a66926 28 PulseRate::PulseRate(PinName bh_sda, PinName bh_scl, PinName bh_int, PinName sync_led, PinName beep) :
t_tatsuoka 0:18d735a66926 29 _bh(bh_sda, bh_scl, bh_int), _sync_led(sync_led), _beep(beep)
t_tatsuoka 0:18d735a66926 30 {
t_tatsuoka 0:18d735a66926 31 init();
t_tatsuoka 0:18d735a66926 32 }
t_tatsuoka 0:18d735a66926 33 #endif
t_tatsuoka 0:18d735a66926 34
t_tatsuoka 0:18d735a66926 35 /** Initialize
t_tatsuoka 0:18d735a66926 36 */
t_tatsuoka 0:18d735a66926 37 void PulseRate::init()
t_tatsuoka 0:18d735a66926 38 {
t_tatsuoka 0:18d735a66926 39 _sync_led = LED_OFF;
t_tatsuoka 0:18d735a66926 40 _val = 0;
t_tatsuoka 0:18d735a66926 41 _wave_flag = false;
t_tatsuoka 0:18d735a66926 42 _pr_flag = false;
t_tatsuoka 0:18d735a66926 43 _sampling_num = 0;
t_tatsuoka 0:18d735a66926 44 _mv_idx = 0;
t_tatsuoka 0:18d735a66926 45 _beep.period(1.0/BEEP_FREQ);
t_tatsuoka 0:18d735a66926 46 }
t_tatsuoka 0:18d735a66926 47
t_tatsuoka 0:18d735a66926 48 /** Start interval timer
t_tatsuoka 0:18d735a66926 49 */
t_tatsuoka 0:18d735a66926 50 void PulseRate::start_sampling()
t_tatsuoka 0:18d735a66926 51 {
t_tatsuoka 0:18d735a66926 52 _sampling.attach(callback(this, &PulseRate::interval_timer), SAMPLING_RATE);
t_tatsuoka 0:18d735a66926 53 }
t_tatsuoka 0:18d735a66926 54
t_tatsuoka 0:18d735a66926 55 /** Get waveform data
t_tatsuoka 0:18d735a66926 56 * @param &num Sampling number
t_tatsuoka 0:18d735a66926 57 * @param &wave_val Waveform value
t_tatsuoka 0:18d735a66926 58 * @retval true Ready for data
t_tatsuoka 0:18d735a66926 59 * @retval false Not ready
t_tatsuoka 0:18d735a66926 60 */
t_tatsuoka 0:18d735a66926 61 bool PulseRate::get_wave(uint32_t &num, int32_t &wave_val)
t_tatsuoka 0:18d735a66926 62 {
t_tatsuoka 0:18d735a66926 63 if(_wave_flag) {
t_tatsuoka 0:18d735a66926 64 _wave_flag = false;
t_tatsuoka 0:18d735a66926 65 num = _sampling_num;
t_tatsuoka 0:18d735a66926 66 wave_val = _val;
t_tatsuoka 0:18d735a66926 67 return true;
t_tatsuoka 0:18d735a66926 68 } else {
t_tatsuoka 0:18d735a66926 69 return false;
t_tatsuoka 0:18d735a66926 70 }
t_tatsuoka 0:18d735a66926 71 }
t_tatsuoka 0:18d735a66926 72
t_tatsuoka 0:18d735a66926 73 /** Gat pulse rate
t_tatsuoka 0:18d735a66926 74 * @param &pr Pulse rate
t_tatsuoka 0:18d735a66926 75 * @retval true Ready for data
t_tatsuoka 0:18d735a66926 76 * @retval false Not ready
t_tatsuoka 0:18d735a66926 77 */
t_tatsuoka 0:18d735a66926 78 bool PulseRate::get_pr_val(uint32_t &pr)
t_tatsuoka 0:18d735a66926 79 {
t_tatsuoka 0:18d735a66926 80 if(_pr_flag) {
t_tatsuoka 0:18d735a66926 81 _pr_flag = false;
t_tatsuoka 0:18d735a66926 82 pr = _pr;
t_tatsuoka 0:18d735a66926 83 return true;
t_tatsuoka 0:18d735a66926 84 } else {
t_tatsuoka 0:18d735a66926 85 return false;
t_tatsuoka 0:18d735a66926 86 }
t_tatsuoka 0:18d735a66926 87 }
t_tatsuoka 0:18d735a66926 88
t_tatsuoka 0:18d735a66926 89 /** Interval timer
t_tatsuoka 0:18d735a66926 90 */
t_tatsuoka 0:18d735a66926 91 void PulseRate::interval_timer()
t_tatsuoka 0:18d735a66926 92 {
t_tatsuoka 0:18d735a66926 93
t_tatsuoka 0:18d735a66926 94 /* Pulse waveform */
t_tatsuoka 0:18d735a66926 95 #ifdef _OP_MODE_INT_AD
t_tatsuoka 0:18d735a66926 96 _val = ((int32_t)(_sensor.read_u16()) - AD_OFFSET); /* Get AD value */
t_tatsuoka 0:18d735a66926 97 #elif defined _OP_MODE_BH1792GLC
t_tatsuoka 0:18d735a66926 98 if(_bh.get_val(_val)) {
t_tatsuoka 0:18d735a66926 99 //printf("Value is set 0.\r\n");
t_tatsuoka 0:18d735a66926 100 _val = 0;
t_tatsuoka 0:18d735a66926 101 }
t_tatsuoka 0:18d735a66926 102 _val = -_val;
t_tatsuoka 0:18d735a66926 103 #endif
t_tatsuoka 0:18d735a66926 104
t_tatsuoka 0:18d735a66926 105 _val = hpf(_val); /* High pass filter (Comment out if not necessary) */
t_tatsuoka 0:18d735a66926 106 _sampling_num = (_sampling_num + 1) % SPL_NUM; /* Update sampling number */
t_tatsuoka 0:18d735a66926 107 _wave_flag = true; /* Set ready flag for pulse waveform */
t_tatsuoka 0:18d735a66926 108
t_tatsuoka 0:18d735a66926 109 /* Pulse rate */
t_tatsuoka 0:18d735a66926 110 if(detect_peak(_val)) { /* If detecting pulse */
t_tatsuoka 0:18d735a66926 111 calc_pr(); /* Calculate pulse rate including flag set */
t_tatsuoka 0:18d735a66926 112 }
t_tatsuoka 0:18d735a66926 113
t_tatsuoka 0:18d735a66926 114 /* Control LED and Beep */
t_tatsuoka 0:18d735a66926 115 if(_pr_flag) {
t_tatsuoka 0:18d735a66926 116 _sync_led = LED_ON;
t_tatsuoka 0:18d735a66926 117 _beep.write(BEEP_LOUD);
t_tatsuoka 0:18d735a66926 118 } else {
t_tatsuoka 0:18d735a66926 119 _sync_led = LED_OFF;
t_tatsuoka 0:18d735a66926 120 _beep.write(0);
t_tatsuoka 0:18d735a66926 121 }
t_tatsuoka 0:18d735a66926 122 }
t_tatsuoka 0:18d735a66926 123
t_tatsuoka 0:18d735a66926 124 /** Fixed point high pass filter
t_tatsuoka 0:18d735a66926 125 * @param val Input value
t_tatsuoka 0:18d735a66926 126 * @return Output value
t_tatsuoka 0:18d735a66926 127 *
t_tatsuoka 0:18d735a66926 128 * A/D value of mbed is Q6 format.
t_tatsuoka 0:18d735a66926 129 * Please shift in advance if necessary.
t_tatsuoka 0:18d735a66926 130 */
t_tatsuoka 0:18d735a66926 131 int32_t PulseRate::hpf(int32_t val)
t_tatsuoka 0:18d735a66926 132 {
t_tatsuoka 0:18d735a66926 133 int32_t reg, ret_val;
t_tatsuoka 0:18d735a66926 134 int64_t temp_val;
t_tatsuoka 0:18d735a66926 135
t_tatsuoka 0:18d735a66926 136 temp_val = (int64_t)COEF_AH * (int64_t)_reg_hpf;
t_tatsuoka 0:18d735a66926 137 reg = val + (int32_t)(temp_val >> 30);
t_tatsuoka 0:18d735a66926 138 ret_val = reg - _reg_hpf;
t_tatsuoka 0:18d735a66926 139 temp_val = (int64_t)COEF_BH * (int64_t)ret_val;
t_tatsuoka 0:18d735a66926 140 ret_val = (int32_t)(temp_val >> 30);
t_tatsuoka 0:18d735a66926 141 _reg_hpf = reg;
t_tatsuoka 0:18d735a66926 142 return ret_val;
t_tatsuoka 0:18d735a66926 143 }
t_tatsuoka 0:18d735a66926 144
t_tatsuoka 0:18d735a66926 145 /** Detect pulse peak
t_tatsuoka 0:18d735a66926 146 * @param &val Waveform data value
t_tatsuoka 0:18d735a66926 147 * @retval true Detected pulse peak
t_tatsuoka 0:18d735a66926 148 * @retval false No detection
t_tatsuoka 0:18d735a66926 149 */
t_tatsuoka 0:18d735a66926 150 bool PulseRate::detect_peak(int32_t val)
t_tatsuoka 0:18d735a66926 151 {
t_tatsuoka 0:18d735a66926 152 int i;
t_tatsuoka 0:18d735a66926 153 bool retVal = false;
t_tatsuoka 0:18d735a66926 154
t_tatsuoka 0:18d735a66926 155 /* Calculate differential of input value */
t_tatsuoka 0:18d735a66926 156 _mv_buf[_mv_idx] = val - _prev_val;
t_tatsuoka 0:18d735a66926 157 _prev_val = val;
t_tatsuoka 0:18d735a66926 158 _mv_idx = (_mv_idx + 1) % MV_LENGTH;
t_tatsuoka 0:18d735a66926 159
t_tatsuoka 0:18d735a66926 160 /* Calculate moving averaging */
t_tatsuoka 0:18d735a66926 161 _detect_val = 0;
t_tatsuoka 0:18d735a66926 162 for(i=0; i<MV_LENGTH; i++) {
t_tatsuoka 0:18d735a66926 163 _detect_val += _mv_buf[i];
t_tatsuoka 0:18d735a66926 164 }
t_tatsuoka 0:18d735a66926 165 _detect_val = _detect_val / MV_LENGTH;
t_tatsuoka 0:18d735a66926 166
t_tatsuoka 0:18d735a66926 167 /* Calculate exponential decline for threshold line */
t_tatsuoka 0:18d735a66926 168 _threshold_val = (int32_t)((double)_prev_th_val * TH_COEF);
t_tatsuoka 0:18d735a66926 169
t_tatsuoka 0:18d735a66926 170 if(_detect_val >= _threshold_val) {
t_tatsuoka 0:18d735a66926 171 /* If exceeding threshold */
t_tatsuoka 0:18d735a66926 172 if(_prev_dt_val < _prev_th_val) {
t_tatsuoka 0:18d735a66926 173 /* If previous value is under threshold and over ignore value */
t_tatsuoka 0:18d735a66926 174 if((_detect_val > PEAK_MIN) && (_pr_counter >= PR_INT_MIN)) {
t_tatsuoka 0:18d735a66926 175 /* Detecting peak!!! */
t_tatsuoka 0:18d735a66926 176 retVal = true;
t_tatsuoka 0:18d735a66926 177 }
t_tatsuoka 0:18d735a66926 178 }
t_tatsuoka 0:18d735a66926 179 /* Previous threshold value is set to input value */
t_tatsuoka 0:18d735a66926 180 _prev_th_val = _detect_val;
t_tatsuoka 0:18d735a66926 181 } else {
t_tatsuoka 0:18d735a66926 182 /* Previous threshold value is set to decline value */
t_tatsuoka 0:18d735a66926 183 _prev_th_val = _threshold_val;
t_tatsuoka 0:18d735a66926 184 }
t_tatsuoka 0:18d735a66926 185 /* Update previous input value */
t_tatsuoka 0:18d735a66926 186 _prev_dt_val = _detect_val;
t_tatsuoka 0:18d735a66926 187
t_tatsuoka 0:18d735a66926 188 /* Increment pulse rate counter */
t_tatsuoka 0:18d735a66926 189 _pr_counter++;
t_tatsuoka 0:18d735a66926 190
t_tatsuoka 0:18d735a66926 191 return retVal;
t_tatsuoka 0:18d735a66926 192 }
t_tatsuoka 0:18d735a66926 193
t_tatsuoka 0:18d735a66926 194 /** Calculate pulse rate
t_tatsuoka 0:18d735a66926 195 */
t_tatsuoka 0:18d735a66926 196 void PulseRate::calc_pr()
t_tatsuoka 0:18d735a66926 197 {
t_tatsuoka 0:18d735a66926 198 int i;
t_tatsuoka 0:18d735a66926 199
t_tatsuoka 0:18d735a66926 200 /* If pulse rate counter is within maximum value */
t_tatsuoka 0:18d735a66926 201 if(_pr_counter <= PR_INT_MAX) {
t_tatsuoka 0:18d735a66926 202 /* Calculate moving averaging */
t_tatsuoka 0:18d735a66926 203 _pr_buf[_pr_idx] = _pr_counter;
t_tatsuoka 0:18d735a66926 204 _pr_idx = (_pr_idx + 1) % PR_LENGTH;
t_tatsuoka 0:18d735a66926 205 _pr = 0;
t_tatsuoka 0:18d735a66926 206 for(i=0; i<PR_LENGTH; i++) {
t_tatsuoka 0:18d735a66926 207 _pr += _pr_buf[i];
t_tatsuoka 0:18d735a66926 208 }
t_tatsuoka 0:18d735a66926 209 /* Set pulse rate value */
t_tatsuoka 0:18d735a66926 210 _pr = PR_1MIN_SPL * PR_LENGTH / _pr;
t_tatsuoka 0:18d735a66926 211 } else {
t_tatsuoka 0:18d735a66926 212 /* Pulse rate is set to invalid value */
t_tatsuoka 0:18d735a66926 213 _pr = 0;
t_tatsuoka 0:18d735a66926 214 }
t_tatsuoka 0:18d735a66926 215 _pr_counter = 0;
t_tatsuoka 0:18d735a66926 216
t_tatsuoka 0:18d735a66926 217 /* Set pulse rate flag */
t_tatsuoka 0:18d735a66926 218 _pr_flag = true;
t_tatsuoka 0:18d735a66926 219 }