18 changed files with 16117 additions and 262 deletions
-
3.vscode/settings.json
-
5README.md
-
186app/app.uvoptx
-
20app/app.uvprojx
-
17app/src/algo/baseline_filtering.c
-
1app/src/algo/baseline_filtering.h
-
5app/src/algo/fix_delay_fifo.h
-
224app/src/algo/iflytop_simple_filter.c
-
96app/src/algo/iflytop_simple_filter.h
-
57app/src/algo/iflytop_simple_filter_ext.c
-
31app/src/algo/iflytop_simple_filter_ext.h
-
109app/src/basic/filters.c
-
53app/src/basic/filters.h
-
2app/src/basic/version.h
-
2app/src/board/board.h
-
10app/src/heart_wave_sample_service.c
-
15558release/V30/three_lead_ecg.hex
-
BINrelease/V30/three_lead_ecg.zip
@ -0,0 +1,224 @@ |
|||
|
|||
#include "iflytop_simple_filter.h" |
|||
|
|||
#include <math.h> |
|||
#include <stdint.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#define PI 3.141592653 |
|||
|
|||
/******************************************************************************************************** |
|||
* LOW PASS FILTER |
|||
********************************************************************************************************/ |
|||
|
|||
void LPFilter_Init(LPFilter_t *filter, float cutoffFreqHz, float sampleTimeS, bool enable) { |
|||
float RC = 0.0; |
|||
RC = 1.0 / (2 * PI * cutoffFreqHz); |
|||
filter->coef[0] = sampleTimeS / (sampleTimeS + RC); |
|||
filter->coef[1] = RC / (sampleTimeS + RC); |
|||
|
|||
filter->v_out[0] = 0.0; |
|||
filter->v_out[1] = 0.0; |
|||
|
|||
filter->enable = enable; |
|||
} |
|||
|
|||
float LPFilter_Update(LPFilter_t *filter, float v_in) { |
|||
if (filter->enable == false) return v_in; |
|||
|
|||
filter->v_out[1] = filter->v_out[0]; |
|||
filter->v_out[0] = (filter->coef[0] * v_in) + (filter->coef[1] * filter->v_out[1]); |
|||
|
|||
return (filter->v_out[0]); |
|||
} |
|||
|
|||
/******************************************************************************************************** |
|||
* HIGH PASS FILTER |
|||
********************************************************************************************************/ |
|||
void HPFilter_Init(HPFilter_t *filter, float cutoffFreqHz, float sampleTimeS, bool enable) { |
|||
float RC = 0.0; |
|||
RC = 1.0 / (2 * PI * cutoffFreqHz); |
|||
|
|||
filter->coef = RC / (sampleTimeS + RC); |
|||
|
|||
filter->v_in[0] = 0.0; |
|||
filter->v_in[1] = 0.0; |
|||
|
|||
filter->v_out[0] = 0.0; |
|||
filter->v_out[1] = 0.0; |
|||
|
|||
filter->enable = enable; |
|||
} |
|||
|
|||
float HPFilter_Update(HPFilter_t *filter, float v_in) { |
|||
if (filter->enable == false) return v_in; |
|||
|
|||
filter->v_in[1] = filter->v_in[0]; |
|||
filter->v_in[0] = v_in; |
|||
|
|||
filter->v_out[1] = filter->v_out[0]; |
|||
|
|||
filter->v_out[0] = filter->coef * (filter->v_in[0] - filter->v_in[1] + filter->v_out[1]); |
|||
|
|||
return (filter->v_out[0]); |
|||
} |
|||
|
|||
/******************************************************************************************************** |
|||
* BAND PASS FILTER |
|||
********************************************************************************************************/ |
|||
|
|||
void PBFilter_Init(PBFilter_t *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS, bool enable) { |
|||
LPFilter_Init(&filter->lpf, LPF_cutoffFreqHz, sampleTimeS, enable); |
|||
HPFilter_Init(&filter->hpf, HPF_cutoffFreqHz, sampleTimeS, enable); |
|||
filter->out_in = 0.0; |
|||
filter->enable = enable; |
|||
} |
|||
|
|||
float PBFilter_Update(PBFilter_t *filter, float v_in) { |
|||
if (filter->enable == false) return v_in; |
|||
|
|||
filter->out_in = HPFilter_Update(&filter->hpf, v_in); |
|||
|
|||
filter->out_in = LPFilter_Update(&filter->lpf, filter->out_in); |
|||
|
|||
return (filter->out_in); |
|||
} |
|||
|
|||
/******************************************************************************************************** |
|||
* NOTCH FILTER |
|||
********************************************************************************************************/ |
|||
|
|||
void NOTCHFilter_Init(NOTCHFilter_t *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS, bool enable) { |
|||
// filter frequency to angular (rad/s) |
|||
float w0_rps = 2.0 * PI * centerFreqHz; |
|||
float ww_rps = 2.0 * PI * notchWidthHz; |
|||
|
|||
// pre warp center frequency |
|||
float w0_pw_rps = (2.0f / sampleTimeS) * tanf(0.5f * w0_rps * sampleTimeS); |
|||
|
|||
// computing filter coefficients |
|||
|
|||
filter->alpha = 4.0f + w0_rps * w0_pw_rps * sampleTimeS * sampleTimeS; |
|||
filter->beta = 2.0f * ww_rps * sampleTimeS; |
|||
|
|||
// clearing input and output buffers |
|||
|
|||
for (uint8_t n = 0; n < 3; n++) { |
|||
filter->vin[n] = 0; |
|||
filter->vout[n] = 0; |
|||
} |
|||
filter->enable = enable; |
|||
} |
|||
|
|||
float NOTCHFilter_Update(NOTCHFilter_t *filter, float vin) { |
|||
if (filter->enable == false) return vin; |
|||
|
|||
// shifting samples |
|||
filter->vin[2] = filter->vin[1]; |
|||
filter->vin[1] = filter->vin[0]; |
|||
|
|||
filter->vout[2] = filter->vout[1]; |
|||
filter->vout[1] = filter->vout[0]; |
|||
|
|||
filter->vin[0] = vin; |
|||
|
|||
// compute new output |
|||
filter->vout[0] = (filter->alpha * filter->vin[0] + 2.0f * (filter->alpha - 8.0f) * filter->vin[1] + filter->alpha * filter->vin[2] - |
|||
(2.0f * (filter->alpha - 8.0f) * filter->vout[1] + (filter->alpha - filter->beta) * filter->vout[2])) / |
|||
(filter->alpha + filter->beta); |
|||
|
|||
return (filter->vout[0]); |
|||
} |
|||
#if 0 |
|||
typedef struct { |
|||
float val[MEDIAN_FILTER_MAX_SIZE]; |
|||
int valStartPos; |
|||
int valEndPos; |
|||
int medianSize; |
|||
} median_filter_t; |
|||
#endif |
|||
|
|||
void median_filter_init(median_filter_t *filter, int medianSize) { |
|||
filter->medianSize = medianSize; |
|||
filter->numVal = 0; |
|||
for (int i = 0; i < MEDIAN_FILTER_MAX_SIZE; i++) { |
|||
filter->val[i] = 0; |
|||
} |
|||
} |
|||
float median_filter_update(median_filter_t *filter, float val) { |
|||
if (filter->numVal >= filter->medianSize) { |
|||
memmove(filter->val, filter->val + 1, (filter->medianSize - 1) * sizeof(float)); |
|||
filter->numVal--; |
|||
} |
|||
|
|||
filter->val[filter->numVal] = val; |
|||
filter->numVal++; |
|||
|
|||
for (int i = 0; i < filter->numVal; i++) { |
|||
filter->temp[i] = filter->val[i]; |
|||
} |
|||
|
|||
for (int i = 0; i < filter->numVal; i++) { |
|||
for (int j = i + 1; j < filter->numVal; j++) { |
|||
if (filter->temp[i] > filter->temp[j]) { |
|||
float temp = filter->temp[i]; |
|||
filter->temp[i] = filter->temp[j]; |
|||
filter->temp[j] = temp; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (filter->numVal % 2 == 0) { |
|||
return (filter->temp[filter->numVal / 2 - 1] + filter->temp[filter->numVal / 2]) / 2; |
|||
} else { |
|||
return filter->temp[filter->numVal / 2]; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
void BaselineDriftRemoval_Init(BaselineDriftRemoval_t *filter, int windows_size, bool enable) { |
|||
if (windows_size > MEDIAN_FILTER_SIZE) { |
|||
windows_size = MEDIAN_FILTER_SIZE; |
|||
} |
|||
|
|||
filter->windows_size = windows_size; |
|||
filter->datanum = 0; |
|||
filter->enable = enable; |
|||
for (int i = 0; i < windows_size; i++) { |
|||
filter->fifo[i] = 0; |
|||
} |
|||
} |
|||
float BaselineDriftRemoval_Update(BaselineDriftRemoval_t *filter, float vin) { |
|||
if (!filter->enable) return vin; |
|||
|
|||
// memmove(filter->fifo, filter->fifo + 1, (filter->windows_size - 1) * sizeof(float)); |
|||
filter->fifo[filter->windows_size - 1] = vin; |
|||
filter->datanum++; |
|||
if (filter->datanum > filter->windows_size) { |
|||
filter->datanum = filter->windows_size; |
|||
} |
|||
if (filter->datanum < filter->windows_size) { |
|||
return 0; |
|||
} |
|||
|
|||
// ÇóÖÐÖµ |
|||
// memcpy(filter->processcache, filter->fifo, filter->windows_size * sizeof(float)); |
|||
for (int i = 0; i < filter->windows_size; i++) { |
|||
for (int j = i + 1; j < filter->windows_size; j++) { |
|||
if (filter->processcache[i] > filter->processcache[j]) { |
|||
float temp = filter->processcache[i]; |
|||
filter->processcache[i] = filter->processcache[j]; |
|||
filter->processcache[j] = temp; |
|||
} |
|||
} |
|||
} |
|||
|
|||
float mid = filter->processcache[filter->windows_size / 2]; |
|||
float min_data_in_fifo = filter->fifo[filter->windows_size / 2]; |
|||
|
|||
return min_data_in_fifo - mid; |
|||
} |
|||
|
@ -0,0 +1,96 @@ |
|||
#pragma once |
|||
#include <stdbool.h> |
|||
|
|||
// #ifdef __cplusplus |
|||
// extern "C" { |
|||
// #endif |
|||
|
|||
/******************************************************************************************************** |
|||
* LOW PASS FILTER |
|||
********************************************************************************************************/ |
|||
typedef struct { |
|||
float coef[2]; |
|||
float v_out[2]; |
|||
bool enable; |
|||
} LPFilter_t; |
|||
|
|||
void LPFilter_Init(LPFilter_t *filter, float cutoffFreqHz, float sampleTimeS, bool enable); |
|||
float LPFilter_Update(LPFilter_t *filter, float v_in); |
|||
|
|||
/******************************************************************************************************** |
|||
* HIGH PASS FILTER |
|||
********************************************************************************************************/ |
|||
typedef struct { |
|||
float coef; |
|||
float v_out[2]; |
|||
float v_in[2]; |
|||
bool enable; |
|||
|
|||
} HPFilter_t; |
|||
|
|||
void HPFilter_Init(HPFilter_t *filter, float cutoffFreqHz, float sampleTimeS, bool enable); |
|||
float HPFilter_Update(HPFilter_t *filter, float v_in); |
|||
|
|||
/******************************************************************************************************** |
|||
* BAND PASS FILTER |
|||
********************************************************************************************************/ |
|||
|
|||
typedef struct { |
|||
LPFilter_t lpf; |
|||
HPFilter_t hpf; |
|||
float out_in; |
|||
bool enable; |
|||
|
|||
} PBFilter_t; |
|||
|
|||
void PBFilter_Init(PBFilter_t *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS, bool enable); |
|||
float PBFilter_Update(PBFilter_t *filter, float v_in); |
|||
|
|||
/******************************************************************************************************** |
|||
* NOTCH FILTER |
|||
********************************************************************************************************/ |
|||
|
|||
typedef struct { |
|||
float alpha; |
|||
float beta; |
|||
|
|||
float vin[3]; |
|||
float vout[3]; |
|||
bool enable; |
|||
|
|||
} NOTCHFilter_t; |
|||
|
|||
void NOTCHFilter_Init(NOTCHFilter_t *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS, bool enable); |
|||
float NOTCHFilter_Update(NOTCHFilter_t *filter, float vin); |
|||
|
|||
// #ifdef __cplusplus |
|||
// } |
|||
// #endif |
|||
#define MEDIAN_FILTER_MAX_SIZE 200 |
|||
|
|||
typedef struct { |
|||
float val[MEDIAN_FILTER_MAX_SIZE]; |
|||
float temp[MEDIAN_FILTER_MAX_SIZE]; |
|||
|
|||
int medianSize; |
|||
int numVal; |
|||
} median_filter_t; |
|||
|
|||
void median_filter_init(median_filter_t *filter, int medianSize); |
|||
float median_filter_update(median_filter_t *filter, float val); |
|||
|
|||
|
|||
#define MEDIAN_FILTER_SIZE 300 |
|||
typedef struct { |
|||
float fifo[MEDIAN_FILTER_SIZE]; |
|||
float processcache[MEDIAN_FILTER_SIZE]; |
|||
bool enable; |
|||
|
|||
int windows_size; |
|||
int datanum; |
|||
} BaselineDriftRemoval_t; |
|||
|
|||
void BaselineDriftRemoval_Init(BaselineDriftRemoval_t *filter, int windows_size, bool enable); |
|||
float BaselineDriftRemoval_Update(BaselineDriftRemoval_t *filter, float vin); |
|||
|
|||
|
@ -0,0 +1,57 @@ |
|||
#include "iflytop_simple_filter_ext.h" |
|||
|
|||
void LPFilterExt_init(LPFilterExt_t *filter, float cutoffFreqHz, float sampleTimeS, int order, bool enable) { |
|||
if (order > FILTER_MAX_ORDER) { |
|||
order = FILTER_MAX_ORDER; |
|||
} |
|||
|
|||
filter->order = order; |
|||
for (int i = 0; i < order; i++) { |
|||
LPFilter_Init(&filter->lp_filter[i], cutoffFreqHz, sampleTimeS, enable); |
|||
} |
|||
} |
|||
float LPFilterExt_update(LPFilterExt_t *filter, float v_in) { |
|||
float v_out = v_in; |
|||
for (int i = 0; i < filter->order; i++) { |
|||
v_out = LPFilter_Update(&filter->lp_filter[i], v_out); |
|||
} |
|||
return v_out; |
|||
} |
|||
|
|||
void HPFilterExt_init(HPFilterExt_t *filter, float cutoffFreqHz, float sampleTimeS, int order, bool enable) { |
|||
if (order > FILTER_MAX_ORDER) { |
|||
order = FILTER_MAX_ORDER; |
|||
} |
|||
|
|||
filter->order = order; |
|||
|
|||
for (int i = 0; i < order; i++) { |
|||
HPFilter_Init(&filter->hp_filter[i], cutoffFreqHz, sampleTimeS, enable); |
|||
} |
|||
} |
|||
float HPFilterExt_update(HPFilterExt_t *filter, float v_in) { |
|||
float v_out = v_in; |
|||
for (int i = 0; i < filter->order; i++) { |
|||
v_out = HPFilter_Update(&filter->hp_filter[i], v_out); |
|||
} |
|||
return v_out; |
|||
} |
|||
|
|||
void NOTCHFilterExt_init(NOTCHFilterExt_t *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS, int order, bool enable) { |
|||
if (order > FILTER_MAX_ORDER) { |
|||
order = FILTER_MAX_ORDER; |
|||
} |
|||
|
|||
filter->order = order; |
|||
|
|||
for (int i = 0; i < order; i++) { |
|||
NOTCHFilter_Init(&filter->notch_filter[i], centerFreqHz, notchWidthHz, sampleTimeS, enable); |
|||
} |
|||
} |
|||
float NOTCHFilterExt_update(NOTCHFilterExt_t *filter, float v_in) { |
|||
float v_out = v_in; |
|||
for (int i = 0; i < filter->order; i++) { |
|||
v_out = NOTCHFilter_Update(&filter->notch_filter[i], v_out); |
|||
} |
|||
return v_out; |
|||
} |
@ -0,0 +1,31 @@ |
|||
#pragma once |
|||
#include "iflytop_simple_filter.h" |
|||
|
|||
#define FILTER_MAX_ORDER 20 |
|||
typedef struct { |
|||
LPFilter_t lp_filter[FILTER_MAX_ORDER]; |
|||
int order; |
|||
} LPFilterExt_t; |
|||
|
|||
void LPFilterExt_init(LPFilterExt_t *filter, float cutoffFreqHz, float sampleTimeS, int order, bool enable); |
|||
float LPFilterExt_update(LPFilterExt_t *filter, float v_in); |
|||
|
|||
typedef struct { |
|||
HPFilter_t hp_filter[FILTER_MAX_ORDER]; |
|||
int order; |
|||
} HPFilterExt_t; |
|||
|
|||
void HPFilterExt_init(HPFilterExt_t *filter, float cutoffFreqHz, float sampleTimeS, int order, bool enable); |
|||
float HPFilterExt_update(HPFilterExt_t *filter, float v_in); |
|||
|
|||
|
|||
typedef struct { |
|||
NOTCHFilter_t notch_filter[FILTER_MAX_ORDER]; |
|||
int order; |
|||
} NOTCHFilterExt_t; |
|||
|
|||
void NOTCHFilterExt_init(NOTCHFilterExt_t *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS, int order, bool enable); |
|||
float NOTCHFilterExt_update(NOTCHFilterExt_t *filter, float v_in); |
|||
|
|||
|
|||
|
@ -1,56 +1,3 @@ |
|||
#pragma once |
|||
#include <stdint.h> |
|||
|
|||
/******************************************************************************************************** |
|||
* LOW PASS FILTER |
|||
********************************************************************************************************/ |
|||
typedef struct { |
|||
float coef[2]; |
|||
float v_out[2]; |
|||
} LPFilter; |
|||
|
|||
void LPFilter_Init(LPFilter *filter, float cutoffFreqHz, float sampleTimeS); |
|||
float LPFilter_Update(LPFilter *filter, float v_in); |
|||
|
|||
/******************************************************************************************************** |
|||
* HIGH PASS FILTER |
|||
********************************************************************************************************/ |
|||
typedef struct { |
|||
float coef; |
|||
float v_out[2]; |
|||
float v_in[2]; |
|||
|
|||
} HPFilter; |
|||
|
|||
void HPFilter_Init(HPFilter *filter, float cutoffFreqHz, float sampleTimeS); |
|||
float HPFilter_Update(HPFilter *filter, float v_in); |
|||
|
|||
/******************************************************************************************************** |
|||
* BAND PASS FILTER |
|||
********************************************************************************************************/ |
|||
|
|||
typedef struct { |
|||
LPFilter lpf; |
|||
HPFilter hpf; |
|||
float out_in; |
|||
} PBFilter; |
|||
|
|||
void PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS); |
|||
float PBFilter_Update(PBFilter *filter, float v_in); |
|||
|
|||
/******************************************************************************************************** |
|||
* NOTCH FILTER |
|||
********************************************************************************************************/ |
|||
|
|||
typedef struct { |
|||
float alpha; |
|||
float beta; |
|||
|
|||
float vin[3]; |
|||
float vout[3]; |
|||
|
|||
} NOTCHFilter; |
|||
|
|||
void NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS); |
|||
float NOTCHFilter_Update(NOTCHFilter *filter, float vin); |
|||
|
15558
release/V30/three_lead_ecg.hex
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue