You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

313 lines
8.7 KiB

#include "heart_wave_sample_service.h"
#include "app_event.h"
#include "app_event_distribute.h"
#include "basic/FIR.h"
#include "basic/HC_Chen_detect.h"
#include "basic/So_Chen_detect.h"
#include "basic/adaptive_algorithm.h"
#include "basic/Pan_Tompkins_detect.h"
#include "board/board_ecg_sensor.h"
#include "nrfx_timer.h"
static uint16_t m_capture_buffer_a[128];
static uint16_t m_capture_buffer_b[128];
static uint16_t* m_capture_buffer;
static uint16_t m_capture_buffer_index = 0;
volatile static float m_sensor_display_data = 0; // 0->100
static uint32_t m_start_capture_tp;
static uint32_t m_frame_index = 0;
static one_frame_data_t m_sensor_little_frame_cache[LITTLE_DATA_BLOCK_FRAME_NUM];
static uint32_t m_little_frame_index;
static bool m_prestart_flag;
static nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(HEART_WAVE_SAMPLE_TMR_INSTANCE);
typedef struct {
int heartSignalCnt;
int heart_rate;
uint32_t last_qrs_point;
uint32_t time_cnt;
uint32_t origin_time_cnt;
uint32_t index;
float index_f;
} QRS_t;
QRS_t m_qrs;
void QRS_reset() {
m_qrs.heartSignalCnt = 0;
m_qrs.heart_rate = 0;
m_qrs.time_cnt = 0;
m_qrs.index = 0;
m_qrs.index_f = 0;
FIR_reset_buffer();
}
void QRS_process(float value) {
bool isPeak = false;
#if 1
float result = value;
SignalPoint sp;
sp.value = result;
sp.index = m_qrs.time_cnt;
SignalPoint peak = So_Chen_detect(sp, SAMPLING_RATE * 0.25f, 4, 16);
if (peak.index != -1) {
isPeak = true;
}
#endif
#if 0
isPeak = HC_Chen_detect(value);
#endif
#if 0
static const float CV_LIMIT = 50.0f;
static const float THRESHOLD_FACTOR = 3.0f;
double mean = CalculateMean(value);
double rms = CalculateRootMeanSquare(value);
double cv = CalculateCoefficientOfVariation(value);
double threshold;
if (cv > CV_LIMIT) {
threshold = rms;
} else {
threshold = rms * (cv / 100.0f) * THRESHOLD_FACTOR;
}
bool is_peak;
SignalPoint result;
result = PeakDetect(value, m_qrs.time_cnt, threshold, &is_peak);
if (result.index != -1) {
if (is_peak) {
isPeak = true;
}
}
#endif
#if 0
double result = value;
double bandpass;
double integral;
double square;
bandpass = result;
result = Derivative(result);
result = Squar(result);
square = result;
result = MovingWindowIntegral(result);
integral = result;
SignalPoint peak = ThresholdCalculate(m_qrs.time_cnt,value,bandpass,square,integral);
if(peak.index != -1){
isPeak = true;
}
#endif
// if (isPeak) {
// uint32_t time_diff = m_qrs.time_cnt - m_qrs.last_qrs_point;
// m_qrs.last_qrs_point = m_qrs.time_cnt;
// m_qrs.heartSignalCnt++;
// // m_qrs.heart_rate = m_qrs.heartSignalCnt;
// if (m_qrs.last_qrs_point != 0) {
// m_qrs.heart_rate = 60 * (1 / (time_diff * 1.0 / SAMPLING_RATE));
// }
// }
m_qrs.time_cnt++;
}
static const void compute_heart_rate(float sample_data) {
ZASSERT(SAMPLE_RATE == 500);
m_qrs.index_f = m_frame_index / 500.0 * 360;
if ((m_qrs.index_f - m_qrs.index) > 1) {
m_qrs.index = m_qrs.index_f;
float val = sample_data;
QRS_process(FIR_filter(val));
}
}
static void swap_buffer() {
if (m_capture_buffer == NULL) {
m_capture_buffer = m_capture_buffer_a;
m_capture_buffer_index = 0;
return;
}
if (m_capture_buffer == m_capture_buffer_a) {
m_capture_buffer = m_capture_buffer_b;
} else {
m_capture_buffer = m_capture_buffer_a;
}
m_capture_buffer_index = 0;
return;
}
static float amp_val(uint16_t val, uint16_t valcener, float amp) {
float valf = (float)val - valcener;
valf = valf * amp;
valf += valcener;
if (valf >= 100) {
valf = 100;
}
if (valf <= 0) {
valf = 0;
}
return valf;
}
typedef struct {
float value;
float efectiveFactor;
} filter_t;
filter_t m_filter = {0, 0.8};
static float Filter(filter_t* filter, float newInput) {
float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor);
filter->value = newv;
return newv;
}
/*******************************************************************************
* 小包数据上报 *
*******************************************************************************/
static inline void prvf_little_block_cache_push_one_frame(uint16_t data) {
if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) {
return;
}
m_sensor_little_frame_cache[m_little_frame_index].data = data;
m_little_frame_index++;
}
static inline bool prvf_light_block_cache_is_full(void) {
if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) {
return true;
}
return false;
}
static inline void prvf_light_block_cache_clear(void) { m_little_frame_index = 0; }
static inline void prvf_light_block_trigger_event() {
static app_event_t event;
event.eventType = kevent_capture_little_data_block_event;
for (uint32_t i = 0; i < LITTLE_DATA_BLOCK_FRAME_NUM; i++) {
event.val.little_data_block.data[i].data = m_sensor_little_frame_cache[i].data;
}
event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM;
// ZLOGI("%d", event.val.little_data_block.frameIndex);
AppEvent_pushEvent(&event);
}
void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { //
uint16_t val = BoardEcgSensor_plod_get_ecg_val(); // 12bit
float val_af100 = (float)val / 4096.0f * 100;
if (m_prestart_flag) {
compute_heart_rate(val_af100);
return;
} else {
compute_heart_rate(val_af100);
}
/*******************************************************************************
* 显示数据计算并赋值 *
*******************************************************************************/
m_frame_index++;
val_af100 = amp_val(val_af100, 45, 3.5f);
val_af100 = Filter(&m_filter, val_af100);
m_sensor_display_data = val_af100;
/*******************************************************************************
* 采样数据缓存 *
*******************************************************************************/
if (m_capture_buffer == NULL) {
swap_buffer();
}
if (m_capture_buffer_index < 128) {
m_capture_buffer[m_capture_buffer_index++] = val;
}
if (m_capture_buffer_index == 128) {
app_event_t evt;
evt.eventType = kevent_capture_256data_event;
evt.val.capture_data_cache = (uint8_t*)m_capture_buffer;
swap_buffer();
AppEvent_pushEvent(&evt);
}
/*******************************************************************************
* 实时采样数据事件上报 *
*******************************************************************************/
/**
* @brief 缓存数据,并触发小数据块事件
*/
prvf_little_block_cache_push_one_frame(val);
if (prvf_light_block_cache_is_full()) {
prvf_light_block_trigger_event();
prvf_light_block_cache_clear();
}
}
void hwss_init(void) {
static bool m_timer_inited = false;
if (!m_timer_inited) {
/**
* @brief 初始化定时器
*/
static nrfx_timer_config_t timer_cfg = {
.frequency = NRF_TIMER_FREQ_500kHz,
.mode = NRF_TIMER_MODE_TIMER,
.bit_width = NRF_TIMER_BIT_WIDTH_24,
.p_context = NULL,
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
};
// nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler);
ZERROR_CHECK(nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler));
uint32_t timer_ticks = nrfx_timer_ms_to_ticks(&m_timer, 2); //
ZASSERT(SAMPLE_RATE == 500);
nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, timer_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
m_timer_inited = true;
}
}
void hwss_uninit(void) { nrfx_timer_disable(&m_timer); }
void hwss_pre_start_capture(void) {
m_start_capture_tp = znordic_getpower_on_s();
swap_buffer();
m_frame_index = 0;
QRS_reset();
prvf_light_block_cache_clear();
nrfx_timer_enable(&m_timer);
m_prestart_flag = true;
}
void hwss_start_capture(void) { m_prestart_flag = false; }
void hwss_stop_capture(void) {
nrfx_timer_disable(&m_timer);
m_frame_index = 0;
prvf_light_block_cache_clear();
}
float hwss_read_val(void) {
__disable_irq();
float val = m_sensor_display_data;
__enable_irq();
return val;
}
float hwss_read_heart_rate(void) { //
return m_qrs.heart_rate;
}
int hwss_has_captured_time_ms() { return (znordic_getpower_on_s() - m_start_capture_tp) * 1000; }