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

Dependencies:   USBDevice mbed

Committer:
t_tatsuoka
Date:
Mon Feb 05 21:28:19 2018 +0000
Revision:
1:90f70c146a26
Parent:
0:18d735a66926
Ver. 1.0.1 ???beep?????????????????????????

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