Tetsuro Tatsuoka
/
BH1792GLC_Eval
Measuring plethysmogram with BH1792GLC (Rohm Semiconductor) and calculating pulse rate
PulseRate.cpp
- Committer:
- t_tatsuoka
- Date:
- 2018-02-05
- Revision:
- 0:18d735a66926
- Child:
- 1:90f70c146a26
File content as of revision 0:18d735a66926:
/** * @file PulseRate.cpp * @brief Measuring plethysmogram and calc pulse rate * @date 2018.02.03 * @version 1.1.0 */ #include "PulseRate.h" #ifdef _OP_MODE_INT_AD /** Constructor * @param sensor Pin for A/D converter * @param sync_led Pin for synchronous LED * @param beep Pin for piezo sounder */ PulseRate::PulseRate(PinName sensor, PinName sync_led, PinName beep) : _sensor(sensor), _sync_led(sync_led), _beep(beep) { init(); } #elif defined _OP_MODE_BH1792GLC /** Constructor * @param bh_sda Pin for SDA on BH1792GLC * @param bh_scl Pin for SCL on BH1792GLC * @param bh_int Pin for INT on BH1792GLC * @param sync_led Pin for synchronous LED * @param beep Pin for piezo sounder */ PulseRate::PulseRate(PinName bh_sda, PinName bh_scl, PinName bh_int, PinName sync_led, PinName beep) : _bh(bh_sda, bh_scl, bh_int), _sync_led(sync_led), _beep(beep) { init(); } #endif /** Initialize */ void PulseRate::init() { _sync_led = LED_OFF; _val = 0; _wave_flag = false; _pr_flag = false; _sampling_num = 0; _mv_idx = 0; _beep.period(1.0/BEEP_FREQ); } /** Start interval timer */ void PulseRate::start_sampling() { _sampling.attach(callback(this, &PulseRate::interval_timer), SAMPLING_RATE); } /** Get waveform data * @param &num Sampling number * @param &wave_val Waveform value * @retval true Ready for data * @retval false Not ready */ bool PulseRate::get_wave(uint32_t &num, int32_t &wave_val) { if(_wave_flag) { _wave_flag = false; num = _sampling_num; wave_val = _val; return true; } else { return false; } } /** Gat pulse rate * @param &pr Pulse rate * @retval true Ready for data * @retval false Not ready */ bool PulseRate::get_pr_val(uint32_t &pr) { if(_pr_flag) { _pr_flag = false; pr = _pr; return true; } else { return false; } } /** Interval timer */ void PulseRate::interval_timer() { /* Pulse waveform */ #ifdef _OP_MODE_INT_AD _val = ((int32_t)(_sensor.read_u16()) - AD_OFFSET); /* Get AD value */ #elif defined _OP_MODE_BH1792GLC if(_bh.get_val(_val)) { //printf("Value is set 0.\r\n"); _val = 0; } _val = -_val; #endif _val = hpf(_val); /* High pass filter (Comment out if not necessary) */ _sampling_num = (_sampling_num + 1) % SPL_NUM; /* Update sampling number */ _wave_flag = true; /* Set ready flag for pulse waveform */ /* Pulse rate */ if(detect_peak(_val)) { /* If detecting pulse */ calc_pr(); /* Calculate pulse rate including flag set */ } /* Control LED and Beep */ if(_pr_flag) { _sync_led = LED_ON; _beep.write(BEEP_LOUD); } else { _sync_led = LED_OFF; _beep.write(0); } } /** Fixed point high pass filter * @param val Input value * @return Output value * * A/D value of mbed is Q6 format. * Please shift in advance if necessary. */ int32_t PulseRate::hpf(int32_t val) { int32_t reg, ret_val; int64_t temp_val; temp_val = (int64_t)COEF_AH * (int64_t)_reg_hpf; reg = val + (int32_t)(temp_val >> 30); ret_val = reg - _reg_hpf; temp_val = (int64_t)COEF_BH * (int64_t)ret_val; ret_val = (int32_t)(temp_val >> 30); _reg_hpf = reg; return ret_val; } /** Detect pulse peak * @param &val Waveform data value * @retval true Detected pulse peak * @retval false No detection */ bool PulseRate::detect_peak(int32_t val) { int i; bool retVal = false; /* Calculate differential of input value */ _mv_buf[_mv_idx] = val - _prev_val; _prev_val = val; _mv_idx = (_mv_idx + 1) % MV_LENGTH; /* Calculate moving averaging */ _detect_val = 0; for(i=0; i<MV_LENGTH; i++) { _detect_val += _mv_buf[i]; } _detect_val = _detect_val / MV_LENGTH; /* Calculate exponential decline for threshold line */ _threshold_val = (int32_t)((double)_prev_th_val * TH_COEF); if(_detect_val >= _threshold_val) { /* If exceeding threshold */ if(_prev_dt_val < _prev_th_val) { /* If previous value is under threshold and over ignore value */ if((_detect_val > PEAK_MIN) && (_pr_counter >= PR_INT_MIN)) { /* Detecting peak!!! */ retVal = true; } } /* Previous threshold value is set to input value */ _prev_th_val = _detect_val; } else { /* Previous threshold value is set to decline value */ _prev_th_val = _threshold_val; } /* Update previous input value */ _prev_dt_val = _detect_val; /* Increment pulse rate counter */ _pr_counter++; return retVal; } /** Calculate pulse rate */ void PulseRate::calc_pr() { int i; /* If pulse rate counter is within maximum value */ if(_pr_counter <= PR_INT_MAX) { /* Calculate moving averaging */ _pr_buf[_pr_idx] = _pr_counter; _pr_idx = (_pr_idx + 1) % PR_LENGTH; _pr = 0; for(i=0; i<PR_LENGTH; i++) { _pr += _pr_buf[i]; } /* Set pulse rate value */ _pr = PR_1MIN_SPL * PR_LENGTH / _pr; } else { /* Pulse rate is set to invalid value */ _pr = 0; } _pr_counter = 0; /* Set pulse rate flag */ _pr_flag = true; }