From ecc67fc670f9dcb1e61373ea100009276f7b9e4d Mon Sep 17 00:00:00 2001 From: zhaohe Date: Fri, 31 May 2024 20:59:15 +0800 Subject: [PATCH] V102 --- .vscode/settings.json | 6 +- README.md | 4 + app/app.uvoptx | 222 +++++++++++++-------- app/app.uvprojx | 50 +++++ app/src/algo/MedianFilter.c | 78 ++++++++ app/src/algo/MedianFilter.h | 39 ++++ app/src/algo/baseline_filtering.c | 118 +++++++++++ app/src/algo/baseline_filtering.h | 7 + app/src/algo/fix_delay_fifo.c | 23 +++ app/src/algo/fix_delay_fifo.h | 17 ++ app/src/algo/smoothing_filter.c | 30 +++ app/src/algo/smoothing_filter.h | 14 ++ app/src/app_event.h | 8 +- app/src/basic/version.h | 2 +- app/src/board/board.h | 2 +- app/src/heart_wave_sample_service.c | 79 +++----- .../heart_wave_sample_service_report_buf.c | 54 +++++ .../heart_wave_sample_service_report_buf.h | 9 + 18 files changed, 620 insertions(+), 142 deletions(-) create mode 100644 app/src/algo/MedianFilter.c create mode 100644 app/src/algo/MedianFilter.h create mode 100644 app/src/algo/baseline_filtering.c create mode 100644 app/src/algo/baseline_filtering.h create mode 100644 app/src/algo/fix_delay_fifo.c create mode 100644 app/src/algo/fix_delay_fifo.h create mode 100644 app/src/algo/smoothing_filter.c create mode 100644 app/src/algo/smoothing_filter.h create mode 100644 app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.c create mode 100644 app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 08583fc..f73691d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -168,7 +168,11 @@ "thread": "cpp", "cinttypes": "cpp", "device_exception_manager.h": "c", - "xiosbase": "c" + "xiosbase": "c", + "baseline_filtering.h": "c", + "heart_wave_sample_service_report_buf.h": "c", + "vcruntime.h": "c", + "smoothing_filter.h": "c" }, "files.encoding": "gbk" } \ No newline at end of file diff --git a/README.md b/README.md index ff86fa2..e596afb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # three_lead_ecg_v2 ``` +V101: + 1. 修改每包上报数据长度,从4帧修改成25帧 + 2. 添加去基线算法,上位机收到数据后需减去8388607,即可得到基线为0的数据 + V28: 1.优化电池电量 diff --git a/app/app.uvoptx b/app/app.uvoptx index 833c64c..1a77a3b 100644 --- a/app/app.uvoptx +++ b/app/app.uvoptx @@ -588,6 +588,66 @@ 0 0 + + 1 + 18 + 1 + 0 + 0 + 0 + .\src\heart_wave_sample_service\heart_wave_sample_service_report_buf.c + heart_wave_sample_service_report_buf.c + 0 + 0 + + + 1 + 19 + 1 + 0 + 0 + 0 + .\src\algo\baseline_filtering.c + baseline_filtering.c + 0 + 0 + + + 1 + 20 + 1 + 0 + 0 + 0 + .\src\algo\fix_delay_fifo.c + fix_delay_fifo.c + 0 + 0 + + + 1 + 21 + 1 + 0 + 0 + 0 + .\src\algo\MedianFilter.c + MedianFilter.c + 0 + 0 + + + 1 + 22 + 1 + 0 + 0 + 0 + .\src\algo\smoothing_filter.c + smoothing_filter.c + 0 + 0 + @@ -598,7 +658,7 @@ 0 2 - 18 + 23 1 0 0 @@ -618,7 +678,7 @@ 0 3 - 19 + 24 1 0 0 @@ -630,7 +690,7 @@ 3 - 20 + 25 1 0 0 @@ -650,7 +710,7 @@ 0 4 - 21 + 26 1 0 0 @@ -670,7 +730,7 @@ 0 5 - 22 + 27 1 0 0 @@ -682,7 +742,7 @@ 5 - 23 + 28 1 0 0 @@ -694,7 +754,7 @@ 5 - 24 + 29 1 0 0 @@ -706,7 +766,7 @@ 5 - 25 + 30 1 0 0 @@ -718,7 +778,7 @@ 5 - 26 + 31 1 0 0 @@ -730,7 +790,7 @@ 5 - 27 + 32 1 0 0 @@ -742,7 +802,7 @@ 5 - 28 + 33 1 0 0 @@ -754,7 +814,7 @@ 5 - 29 + 34 1 0 0 @@ -774,7 +834,7 @@ 0 6 - 30 + 35 1 0 0 @@ -794,7 +854,7 @@ 0 7 - 31 + 36 1 0 0 @@ -806,7 +866,7 @@ 7 - 32 + 37 1 0 0 @@ -818,7 +878,7 @@ 7 - 33 + 38 1 0 0 @@ -830,7 +890,7 @@ 7 - 34 + 39 1 0 0 @@ -842,7 +902,7 @@ 7 - 35 + 40 1 0 0 @@ -854,7 +914,7 @@ 7 - 36 + 41 1 0 0 @@ -866,7 +926,7 @@ 7 - 37 + 42 1 0 0 @@ -878,7 +938,7 @@ 7 - 38 + 43 1 0 0 @@ -890,7 +950,7 @@ 7 - 39 + 44 1 0 0 @@ -902,7 +962,7 @@ 7 - 40 + 45 1 0 0 @@ -914,7 +974,7 @@ 7 - 41 + 46 1 0 0 @@ -926,7 +986,7 @@ 7 - 42 + 47 1 0 0 @@ -938,7 +998,7 @@ 7 - 43 + 48 1 0 0 @@ -950,7 +1010,7 @@ 7 - 44 + 49 1 0 0 @@ -962,7 +1022,7 @@ 7 - 45 + 50 1 0 0 @@ -974,7 +1034,7 @@ 7 - 46 + 51 1 0 0 @@ -986,7 +1046,7 @@ 7 - 47 + 52 1 0 0 @@ -998,7 +1058,7 @@ 7 - 48 + 53 1 0 0 @@ -1010,7 +1070,7 @@ 7 - 49 + 54 1 0 0 @@ -1022,7 +1082,7 @@ 7 - 50 + 55 1 0 0 @@ -1042,7 +1102,7 @@ 0 8 - 51 + 56 1 0 0 @@ -1054,7 +1114,7 @@ 8 - 52 + 57 1 0 0 @@ -1066,7 +1126,7 @@ 8 - 53 + 58 1 0 0 @@ -1078,7 +1138,7 @@ 8 - 54 + 59 1 0 0 @@ -1090,7 +1150,7 @@ 8 - 55 + 60 1 0 0 @@ -1102,7 +1162,7 @@ 8 - 56 + 61 1 0 0 @@ -1114,7 +1174,7 @@ 8 - 57 + 62 1 0 0 @@ -1126,7 +1186,7 @@ 8 - 58 + 63 1 0 0 @@ -1138,7 +1198,7 @@ 8 - 59 + 64 1 0 0 @@ -1150,7 +1210,7 @@ 8 - 60 + 65 1 0 0 @@ -1162,7 +1222,7 @@ 8 - 61 + 66 1 0 0 @@ -1174,7 +1234,7 @@ 8 - 62 + 67 1 0 0 @@ -1186,7 +1246,7 @@ 8 - 63 + 68 1 0 0 @@ -1198,7 +1258,7 @@ 8 - 64 + 69 1 0 0 @@ -1210,7 +1270,7 @@ 8 - 65 + 70 1 0 0 @@ -1222,7 +1282,7 @@ 8 - 66 + 71 1 0 0 @@ -1234,7 +1294,7 @@ 8 - 67 + 72 1 0 0 @@ -1246,7 +1306,7 @@ 8 - 68 + 73 1 0 0 @@ -1258,7 +1318,7 @@ 8 - 69 + 74 1 0 0 @@ -1270,7 +1330,7 @@ 8 - 70 + 75 1 0 0 @@ -1282,7 +1342,7 @@ 8 - 71 + 76 1 0 0 @@ -1294,7 +1354,7 @@ 8 - 72 + 77 1 0 0 @@ -1306,7 +1366,7 @@ 8 - 73 + 78 1 0 0 @@ -1318,7 +1378,7 @@ 8 - 74 + 79 1 0 0 @@ -1330,7 +1390,7 @@ 8 - 75 + 80 1 0 0 @@ -1342,7 +1402,7 @@ 8 - 76 + 81 1 0 0 @@ -1354,7 +1414,7 @@ 8 - 77 + 82 1 0 0 @@ -1374,7 +1434,7 @@ 0 9 - 78 + 83 1 0 0 @@ -1386,7 +1446,7 @@ 9 - 79 + 84 1 0 0 @@ -1398,7 +1458,7 @@ 9 - 80 + 85 1 0 0 @@ -1410,7 +1470,7 @@ 9 - 81 + 86 1 0 0 @@ -1422,7 +1482,7 @@ 9 - 82 + 87 1 0 0 @@ -1434,7 +1494,7 @@ 9 - 83 + 88 1 0 0 @@ -1454,7 +1514,7 @@ 0 10 - 84 + 89 1 0 0 @@ -1466,7 +1526,7 @@ 10 - 85 + 90 1 0 0 @@ -1478,7 +1538,7 @@ 10 - 86 + 91 1 0 0 @@ -1498,7 +1558,7 @@ 0 11 - 87 + 92 1 0 0 @@ -1510,7 +1570,7 @@ 11 - 88 + 93 1 0 0 @@ -1522,7 +1582,7 @@ 11 - 89 + 94 1 0 0 @@ -1542,7 +1602,7 @@ 0 12 - 90 + 95 1 0 0 @@ -1554,7 +1614,7 @@ 12 - 91 + 96 1 0 0 @@ -1566,7 +1626,7 @@ 12 - 92 + 97 1 0 0 @@ -1586,7 +1646,7 @@ 0 13 - 93 + 98 1 0 0 @@ -1598,7 +1658,7 @@ 13 - 94 + 99 1 0 0 @@ -1618,7 +1678,7 @@ 0 14 - 95 + 100 1 0 0 @@ -1630,7 +1690,7 @@ 14 - 96 + 101 1 0 0 @@ -1642,7 +1702,7 @@ 14 - 97 + 102 1 0 0 @@ -1654,7 +1714,7 @@ 14 - 98 + 103 1 0 0 diff --git a/app/app.uvprojx b/app/app.uvprojx index ac6f118..2f82e54 100644 --- a/app/app.uvprojx +++ b/app/app.uvprojx @@ -468,6 +468,31 @@ 1 .\src\board\device_exception_manager.c + + heart_wave_sample_service_report_buf.c + 1 + .\src\heart_wave_sample_service\heart_wave_sample_service_report_buf.c + + + baseline_filtering.c + 1 + .\src\algo\baseline_filtering.c + + + fix_delay_fifo.c + 1 + .\src\algo\fix_delay_fifo.c + + + MedianFilter.c + 1 + .\src\algo\MedianFilter.c + + + smoothing_filter.c + 1 + .\src\algo\smoothing_filter.c + @@ -4317,6 +4342,31 @@ 1 .\src\board\device_exception_manager.c + + heart_wave_sample_service_report_buf.c + 1 + .\src\heart_wave_sample_service\heart_wave_sample_service_report_buf.c + + + baseline_filtering.c + 1 + .\src\algo\baseline_filtering.c + + + fix_delay_fifo.c + 1 + .\src\algo\fix_delay_fifo.c + + + MedianFilter.c + 1 + .\src\algo\MedianFilter.c + + + smoothing_filter.c + 1 + .\src\algo\smoothing_filter.c + diff --git a/app/src/algo/MedianFilter.c b/app/src/algo/MedianFilter.c new file mode 100644 index 0000000..bd78960 --- /dev/null +++ b/app/src/algo/MedianFilter.c @@ -0,0 +1,78 @@ +/* + * MedianFilter.c + * + * Created on: May 19, 2018 + * Author: alexandru.bogdan + */ + +#include "MedianFilter.h" + +#include + +int32_t MEDIANFILTER_Init(sMedianFilter_t *medianFilter) { + if (medianFilter && medianFilter->medianBuffer && (medianFilter->numNodes % 2) && (medianFilter->numNodes > 1)) { + // initialize buffer nodes + for (unsigned int i = 0; i < medianFilter->numNodes; i++) { + medianFilter->medianBuffer[i].value = 0; + medianFilter->medianBuffer[i].nextAge = &medianFilter->medianBuffer[(i + 1) % medianFilter->numNodes]; + medianFilter->medianBuffer[i].nextValue = &medianFilter->medianBuffer[(i + 1) % medianFilter->numNodes]; + medianFilter->medianBuffer[(i + 1) % medianFilter->numNodes].prevValue = &medianFilter->medianBuffer[i]; + } + // initialize heads + medianFilter->ageHead = medianFilter->medianBuffer; + medianFilter->valueHead = medianFilter->medianBuffer; + medianFilter->medianHead = &medianFilter->medianBuffer[medianFilter->numNodes / 2]; + + return 0; + } + + return -1; +} + +int32_t MEDIANFILTER_Insert(sMedianFilter_t *medianFilter, int32_t sample) { + unsigned int i; + sMedianNode_t *newNode, *it; + + if (medianFilter->ageHead == medianFilter->valueHead) { // if oldest node is also the smallest node, increment value head + medianFilter->valueHead = medianFilter->valueHead->nextValue; + } + + if ((medianFilter->ageHead == medianFilter->medianHead) || (medianFilter->ageHead->value > medianFilter->medianHead->value)) { // prepare for median correction + medianFilter->medianHead = medianFilter->medianHead->prevValue; + } + + // replace age head with new sample + newNode = medianFilter->ageHead; + newNode->value = sample; + + // remove age head from list + medianFilter->ageHead->nextValue->prevValue = medianFilter->ageHead->prevValue; + medianFilter->ageHead->prevValue->nextValue = medianFilter->ageHead->nextValue; + // increment age head + medianFilter->ageHead = medianFilter->ageHead->nextAge; + + // find new node position + it = medianFilter->valueHead; // set iterator as value head + for (i = 0; i < medianFilter->numNodes - 1; i++) { + if (sample < it->value) { + if (i == 0) { // replace value head if new node is the smallest + medianFilter->valueHead = newNode; + } + break; + } + it = it->nextValue; + } + + // insert new node in list + it->prevValue->nextValue = newNode; + newNode->prevValue = it->prevValue; + it->prevValue = newNode; + newNode->nextValue = it; + + // adjust median node + if (i >= (medianFilter->numNodes / 2)) { + medianFilter->medianHead = medianFilter->medianHead->nextValue; + } + + return medianFilter->medianHead->value; +} \ No newline at end of file diff --git a/app/src/algo/MedianFilter.h b/app/src/algo/MedianFilter.h new file mode 100644 index 0000000..92bc379 --- /dev/null +++ b/app/src/algo/MedianFilter.h @@ -0,0 +1,39 @@ +/* + * MedianFilter.h + * + * Created on: May 19, 2018 + * Author: alexandru.bogdan + */ + +#ifndef MEDIANFILTER_H_ +#define MEDIANFILTER_H_ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sMedianNode +{ + int32_t value; //sample value + struct sMedianNode *nextAge; //pointer to next oldest value + struct sMedianNode *nextValue; //pointer to next smallest value + struct sMedianNode *prevValue; //pointer to previous smallest value +}sMedianNode_t; + +typedef struct +{ + unsigned int numNodes; //median node buffer length + sMedianNode_t *medianBuffer; //median node buffer + sMedianNode_t *ageHead; //pointer to oldest value + sMedianNode_t *valueHead; //pointer to smallest value + sMedianNode_t *medianHead; //pointer to median value +}sMedianFilter_t; + +int32_t MEDIANFILTER_Init(sMedianFilter_t *medianFilter); +int32_t MEDIANFILTER_Insert(sMedianFilter_t *medianFilter, int32_t sample); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/app/src/algo/baseline_filtering.c b/app/src/algo/baseline_filtering.c new file mode 100644 index 0000000..8b83fd3 --- /dev/null +++ b/app/src/algo/baseline_filtering.c @@ -0,0 +1,118 @@ +#include "baseline_filtering.h" + +#include +#include + +#include "MedianFilter.h" +#include "fix_delay_fifo.h" +#include "smoothing_filter.h" + +#define REPORT_MEDIAN_WINDOWS_SIZE 101 // 必须是奇数 + +#define _ARRARY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +static sMedianFilter_t medianFilter0; +static sMedianNode_t medianBufferBuffer0[REPORT_MEDIAN_WINDOWS_SIZE]; +static int32_t m_fifo_buffer_0[REPORT_MEDIAN_WINDOWS_SIZE / 2]; +static fix_delay_fifo_t m_fifo0; + +static sMedianFilter_t medianFilter1; +static sMedianNode_t medianBufferBuffer1[REPORT_MEDIAN_WINDOWS_SIZE]; +static int32_t m_fifo_buffer_1[REPORT_MEDIAN_WINDOWS_SIZE / 2]; +static fix_delay_fifo_t m_fifo1; + +static sMedianFilter_t medianFilter2; +static sMedianNode_t medianBufferBuffer2[REPORT_MEDIAN_WINDOWS_SIZE]; +static int32_t m_fifo_buffer_2[REPORT_MEDIAN_WINDOWS_SIZE / 2]; +static fix_delay_fifo_t m_fifo2; + +static SmoothingFilter_t smoothingFilter0; +static SmoothingFilter_t smoothingFilter1; +static SmoothingFilter_t smoothingFilter2; + +static int32_t m_frame_cnt; +static int32_t result0; +static int32_t result1; +static int32_t result2; + +void baseline_filter_init() { baseline_filter_reset(); } + +void baseline_filter_reset() { + { + memset(&medianFilter0, 0, sizeof(medianFilter0)); + memset(medianBufferBuffer0, 0, sizeof(medianBufferBuffer0)); + medianFilter0.numNodes = REPORT_MEDIAN_WINDOWS_SIZE; + medianFilter0.medianBuffer = medianBufferBuffer0; + MEDIANFILTER_Init(&medianFilter0); + + fix_delay_fifo_init(&m_fifo0, m_fifo_buffer_0, REPORT_MEDIAN_WINDOWS_SIZE / 2); + } + + { + memset(&medianFilter1, 0, sizeof(medianFilter1)); + memset(medianBufferBuffer1, 0, sizeof(medianBufferBuffer1)); + medianFilter1.numNodes = REPORT_MEDIAN_WINDOWS_SIZE; + medianFilter1.medianBuffer = medianBufferBuffer1; + MEDIANFILTER_Init(&medianFilter1); + + fix_delay_fifo_init(&m_fifo1, m_fifo_buffer_1, REPORT_MEDIAN_WINDOWS_SIZE / 2); + } + + { + memset(&medianFilter2, 0, sizeof(medianFilter2)); + memset(medianBufferBuffer2, 0, sizeof(medianBufferBuffer2)); + medianFilter2.numNodes = REPORT_MEDIAN_WINDOWS_SIZE; + medianFilter2.medianBuffer = medianBufferBuffer2; + MEDIANFILTER_Init(&medianFilter2); + + fix_delay_fifo_init(&m_fifo2, m_fifo_buffer_2, REPORT_MEDIAN_WINDOWS_SIZE / 2); + } + + // smoothingFilter0 + // smoothingFilter1 + // smoothingFilter2 + + SmoothingFilter_Init(&smoothingFilter0, 5, true); + SmoothingFilter_Init(&smoothingFilter1, 5, true); + SmoothingFilter_Init(&smoothingFilter2, 5, true); + + m_frame_cnt = 0; +} + +void baseline_filter_push(int32_t val0, int32_t val1, int32_t val2) { + int32_t medianValue0 = MEDIANFILTER_Insert(&medianFilter0, val0); + int32_t delay_data0 = fix_delay_fifo_update(&m_fifo0, val0); + + float medianValue1 = MEDIANFILTER_Insert(&medianFilter1, val1); + float delay_data1 = fix_delay_fifo_update(&m_fifo1, val1); + + float medianValue2 = MEDIANFILTER_Insert(&medianFilter2, val2); + float delay_data2 = fix_delay_fifo_update(&m_fifo2, val2); + + m_frame_cnt++; + + if (m_frame_cnt < REPORT_MEDIAN_WINDOWS_SIZE) { + result0 = 0; + result1 = 0; + result2 = 0; + return; + } + result0 = delay_data0 - medianValue0; + result1 = delay_data1 - medianValue1; + result2 = delay_data2 - medianValue2; + + result0 = SmoothingFilter_Update(&smoothingFilter0, result0); + result1 = SmoothingFilter_Update(&smoothingFilter1, result1); + result2 = SmoothingFilter_Update(&smoothingFilter2, result2); +} + +int32_t baseline_filter_get_result(int32_t index) { + if (index == 0) { + return result0; + } else if (index == 1) { + return result1; + } else if (index == 2) { + return result2; + } + return 0; +} diff --git a/app/src/algo/baseline_filtering.h b/app/src/algo/baseline_filtering.h new file mode 100644 index 0000000..31e77dd --- /dev/null +++ b/app/src/algo/baseline_filtering.h @@ -0,0 +1,7 @@ +#pragma once +#include + +void baseline_filter_init(); +void baseline_filter_reset(); +void baseline_filter_push(int32_t val0, int32_t val1, int32_t val2); +int32_t baseline_filter_get_result(int32_t index); diff --git a/app/src/algo/fix_delay_fifo.c b/app/src/algo/fix_delay_fifo.c new file mode 100644 index 0000000..345ebc4 --- /dev/null +++ b/app/src/algo/fix_delay_fifo.c @@ -0,0 +1,23 @@ +#include "fix_delay_fifo.h" + +void fix_delay_fifo_init(fix_delay_fifo_t *buffer, int32_t *fifo, int fifosize){ + + buffer->fifo = fifo; + buffer->fifosize = fifosize; + buffer->head = 0; + buffer->tail = 0; + memset(buffer->fifo, 0, fifosize * sizeof(int32_t)); + +} +int32_t fix_delay_fifo_update(fix_delay_fifo_t *buffer, int32_t vin){ + + buffer->fifo[buffer->tail] = vin; + buffer->tail = (buffer->tail + 1) % buffer->fifosize; + int32_t fifoheadval = 0; + if (buffer->tail == buffer->head) { + fifoheadval = buffer->fifo[buffer->head]; + buffer->head = (buffer->head + 1) % buffer->fifosize; + } + return fifoheadval; + +} \ No newline at end of file diff --git a/app/src/algo/fix_delay_fifo.h b/app/src/algo/fix_delay_fifo.h new file mode 100644 index 0000000..12c4ea3 --- /dev/null +++ b/app/src/algo/fix_delay_fifo.h @@ -0,0 +1,17 @@ +#ifndef FILTERS_H +#define FILTERS_H +#include +#include +typedef struct { + int32_t *fifo; + int fifosize; + + int head; + int tail; + +} fix_delay_fifo_t; + +void fix_delay_fifo_init(fix_delay_fifo_t *buffer, int32_t *fifo, int fifosize); +int32_t fix_delay_fifo_update(fix_delay_fifo_t *buffer, int32_t vin); + +#endif \ No newline at end of file diff --git a/app/src/algo/smoothing_filter.c b/app/src/algo/smoothing_filter.c new file mode 100644 index 0000000..6273b68 --- /dev/null +++ b/app/src/algo/smoothing_filter.c @@ -0,0 +1,30 @@ +#include "smoothing_filter.h" +void SmoothingFilter_Init(SmoothingFilter_t *filter, int windows_size, bool enable) { + if (windows_size > 1000) { + windows_size = 1000; + } + filter->windows_size = windows_size; + filter->datanum = 0; + filter->sum = 0; + filter->datanum = 0; + for (int i = 0; i < windows_size; i++) { + filter->datawindows[i] = 0; + } + filter->data_offset = 0; + filter->enable = enable; +} +int32_t SmoothingFilter_Update(SmoothingFilter_t *filter, int32_t vin) { + if (!filter->enable) return vin; + + filter->sum -= filter->datawindows[filter->data_offset]; + filter->datawindows[filter->data_offset] = vin; + filter->sum += filter->datawindows[filter->data_offset]; + filter->data_offset = (filter->data_offset + 1) % filter->windows_size; + + filter->datanum++; + if (filter->datanum > filter->windows_size) { + filter->datanum = filter->windows_size; + } + + return filter->sum / filter->datanum; +} \ No newline at end of file diff --git a/app/src/algo/smoothing_filter.h b/app/src/algo/smoothing_filter.h new file mode 100644 index 0000000..513cddf --- /dev/null +++ b/app/src/algo/smoothing_filter.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include +typedef struct { + int32_t datawindows[30]; + int windows_size; + int datanum; + int data_offset; + int32_t sum; + bool enable; +} SmoothingFilter_t; + +void SmoothingFilter_Init(SmoothingFilter_t *filter, int windows_size, bool enable); +int32_t SmoothingFilter_Update(SmoothingFilter_t *filter, int32_t vin); \ No newline at end of file diff --git a/app/src/app_event.h b/app/src/app_event.h index 3db6639..86719ca 100644 --- a/app/src/app_event.h +++ b/app/src/app_event.h @@ -1,8 +1,8 @@ #pragma once #include #include -#include "board/board.h" +#include "board/board.h" typedef enum { kevent_sensor_drop = 0, // 导联连接事件 @@ -33,8 +33,10 @@ typedef struct { app_event_type_t eventType; union { struct { - uint32_t frameIndex; - one_frame_data_t data[LITTLE_DATA_BLOCK_FRAME_NUM]; + uint32_t frameIndex; + // one_frame_data_t data[LITTLE_DATA_BLOCK_FRAME_NUM]; + one_frame_data_t* data; + int len; } little_data_block; struct { diff --git a/app/src/basic/version.h b/app/src/basic/version.h index e156853..296c04f 100644 --- a/app/src/basic/version.h +++ b/app/src/basic/version.h @@ -2,7 +2,7 @@ #define CATEGORY "M1002" // 三导联 #define MANUFACTURER_NAME "iflytop" -#define FIRMWARE_VERSION (28) +#define FIRMWARE_VERSION (102) #define BLESTACK_VERSION 1 #define BOOTLOADER_VERSION 1 #define HARDWARE_VERSION (1) diff --git a/app/src/board/board.h b/app/src/board/board.h index 32735a2..2d69074 100644 --- a/app/src/board/board.h +++ b/app/src/board/board.h @@ -63,7 +63,7 @@ #define APP_MAX_STORAGE_TIME_S (uint32_t)(72 * 60 * 60) // #define SAMPLE_RATE 400 -#define LITTLE_DATA_BLOCK_FRAME_NUM 4 // 每两帧回调一次,对应100HZ +#define LITTLE_DATA_BLOCK_FRAME_NUM 25 // 每两帧回调一次,对应100HZ #define SAMPLE_PRECISION 24 #define APP_MAX_EVEN_SIZE (MAX(APP_TIMER_SCHED_EVENT_DATA_SIZE, sizeof(app_event_t))) diff --git a/app/src/heart_wave_sample_service.c b/app/src/heart_wave_sample_service.c index 375cc46..bc0cd38 100644 --- a/app/src/heart_wave_sample_service.c +++ b/app/src/heart_wave_sample_service.c @@ -2,12 +2,14 @@ // #include "znordic.h" // +#include "algo/baseline_filtering.h" #include "app_button.h" #include "app_event.h" #include "app_event_distribute.h" #include "basic/ads1293/ads1293.h" #include "basic/filters.h" #include "board/device_exception_manager.h" +#include "heart_wave_sample_service/heart_wave_sample_service_report_buf.h" #include "nrf_drv_gpiote.h" #include "nrfx_timer.h" #include "sample_data_manager_service.h" @@ -84,10 +86,6 @@ static uint8_t m_frame_buffer_b[HEART_WAVE_SAMPLE_SERVICE_CACHE_SIZE]; static uint8_t *m_frame_buffer; static int32_t m_frame_buffer_index; -// 小包采样数据缓存,用于触发实时上报逻辑使用 -static one_frame_data_t m_sensor_little_frame_cache[LITTLE_DATA_BLOCK_FRAME_NUM]; -static uint32_t m_little_frame_index; - static uint8_t m_lodstate0; static uint8_t m_lodstate1; @@ -146,24 +144,6 @@ static inline void pFrameBufferAB_push_one_byte(uint8_t byte) { * LittleDataBuffer操作 * *******************************************************************************/ -static inline void pLittleBlockCache_push_one_frame(uint32_t *data) { - if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { - return; - } - m_sensor_little_frame_cache[m_little_frame_index].data0 = data[0]; - m_sensor_little_frame_cache[m_little_frame_index].data1 = data[1]; - m_sensor_little_frame_cache[m_little_frame_index].data2 = data[2]; - m_little_frame_index++; -} - -static inline bool pLittleBlockCache_is_full(void) { - if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { - return true; - } - return false; -} -static inline void pLittleBlockCache_reset(void) { m_little_frame_index = 0; } - /******************************************************************************* * 事件操作辅助方法 * *******************************************************************************/ @@ -176,24 +156,6 @@ static inline void pEventHelper_trigger_capture_data_block_event(uint8_t *data, AppEvent_pushEvent(&event); } -static inline void pEventHelper_trigger_little_block_data_event() { - static app_event_t event; - event.eventType = kevent_capture_little_data_block_event; - // memcpy(event.val.little_data_block.data, m_sensor_little_frame_cache, LITTLE_DATA_BLOCK_FRAME_NUM * sizeof(one_frame_data_t)); - - for (uint32_t i = 0; i < LITTLE_DATA_BLOCK_FRAME_NUM; i++) { - event.val.little_data_block.data[i].data0 = m_sensor_little_frame_cache[i].data0; - event.val.little_data_block.data[i].data1 = m_sensor_little_frame_cache[i].data1; - event.val.little_data_block.data[i].data2 = m_sensor_little_frame_cache[i].data2; - // event.val.little_data_block.data[0].data0 = 1111111111; - // event.val.little_data_block.data[0].data1 = 2222222222; - // event.val.little_data_block.data[0].data2 = 3333333333; - } - - event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; - AppEvent_pushEvent(&event); -} - static inline void pEventHelper_trigger_sensor_drop_event(uint8_t drop0, uint8_t drop1) { static app_event_t event; event.eventType = kevent_sensor_drop; @@ -472,18 +434,25 @@ static void ads1293_sample_one_frame() { // medianFilter uint32_t val[3]; - val[0] = MedianFilter_Update(&medianFilter[0], sample[SENSOR0_ID]); - val[1] = MedianFilter_Update(&medianFilter[1], sample[SENSOR1_ID]); - val[2] = MedianFilter_Update(&medianFilter[2], sample[SENSOR2_ID]); - - // int32_t val0 = LPFilter_Update(&lowpassfilter[0], sample[SENSOR0_ID]); - // int32_t val1 = LPFilter_Update(&lowpassfilter[1], sample[SENSOR1_ID]); - // int32_t val2 = LPFilter_Update(&lowpassfilter[2], sample[SENSOR2_ID]); +#if 1 + baseline_filter_push((int32_t)sample[SENSOR0_ID], (int32_t)sample[SENSOR1_ID], (int32_t)sample[SENSOR2_ID]); + int32_t val0 = (int32_t)baseline_filter_get_result(0) + 0x7FFFFF; + int32_t val1 = (int32_t)baseline_filter_get_result(1) + 0x7FFFFF; + int32_t val2 = (int32_t)baseline_filter_get_result(2) + 0x7FFFFF; + + if (val0 < 0) val0 = 0; + if (val1 < 0) val1 = 0; + if (val2 < 0) val2 = 0; + + val[0] = val0; + val[1] = val1; + val[2] = val2; +#else val[0] = sample[SENSOR0_ID]; val[1] = sample[SENSOR1_ID]; val[2] = sample[SENSOR2_ID]; - +#endif if (val[0] > 0xffffff) val[0] = 0xffffff; if (val[1] > 0xffffff) val[1] = 0xffffff; if (val[2] > 0xffffff) val[2] = 0xffffff; @@ -516,10 +485,9 @@ static void ads1293_sample_one_frame() { /** * @brief 缓存数据,并触发小数据块事件 */ - pLittleBlockCache_push_one_frame(&val[0]); - if (pLittleBlockCache_is_full()) { - pEventHelper_trigger_little_block_data_event(); - pLittleBlockCache_reset(); + HWSSReportBuf_push_one_frame(&val[0]); + if (HWSSReportBuf_is_full()) { + HWSSReportBuf_trigger_little_block_data_event(); } } @@ -529,7 +497,7 @@ static void ads1293_uninit() { nrf_drv_spi_uninit(&spi); } -void hwss_init(void) {} +void hwss_init(void) { baseline_filter_init(); } void hwss_load(void) { ZERROR_CHECK(nrfx_gpiote_init()); @@ -571,7 +539,7 @@ void hwss_start_capture(void) { MedianFilter_Init(&medianFilter[1]); MedianFilter_Init(&medianFilter[2]); - pLittleBlockCache_reset(); + HWSSReportBuf_reset(); // ads1293_start_conversion(&m_ads1293_0); // ads1293_start_conversion(&m_ads1293_1); @@ -608,6 +576,8 @@ void hwss_start_capture(void) { nrf_gpio_pin_set(ADS1293_SPI_CS1_PIN); } + baseline_filter_reset(); + nrfx_gpiote_in_event_enable(ADS1293_READY_PIN, true); } @@ -617,7 +587,6 @@ void hwss_stop_capture(void) { m_work_flag = false; m_frame_index = 0; m_frame_filter_index = 0; - pLittleBlockCache_reset(); // ads1293_stop_conversion(&m_ads1293_0); // ads1293_stop_conversion(&m_ads1293_1); diff --git a/app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.c b/app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.c new file mode 100644 index 0000000..d7d7f7f --- /dev/null +++ b/app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.c @@ -0,0 +1,54 @@ + +#include + +#include "app_event.h" +#include "app_event_distribute.h" + +// 小包采样数据缓存,用于触发实时上报逻辑使用 +static one_frame_data_t m_sensor_little_frame_cache_A[LITTLE_DATA_BLOCK_FRAME_NUM]; +static one_frame_data_t m_sensor_little_frame_cache_B[LITTLE_DATA_BLOCK_FRAME_NUM]; +static one_frame_data_t *curbuf = m_sensor_little_frame_cache_A; +static uint32_t m_little_frame_index; +static uint32_t m_frame_index; + +static void HWSSReportBuf_ExchangeAB() { + if (curbuf == m_sensor_little_frame_cache_A) { + curbuf = m_sensor_little_frame_cache_B; + } else { + curbuf = m_sensor_little_frame_cache_A; + } +} + +void HWSSReportBuf_push_one_frame(uint32_t *data) { + if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { + return; + } + curbuf[m_little_frame_index].data0 = data[0]; + curbuf[m_little_frame_index].data1 = data[1]; + curbuf[m_little_frame_index].data2 = data[2]; + m_little_frame_index++; + m_frame_index++; +} + +bool HWSSReportBuf_is_full(void) { + if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { + return true; + } + return false; +} +void HWSSReportBuf_reset(void) { + m_little_frame_index = 0; + m_frame_index = 0; +} + +void HWSSReportBuf_trigger_little_block_data_event() { + static app_event_t event; + event.eventType = kevent_capture_little_data_block_event; + + event.val.little_data_block.data = curbuf; + event.val.little_data_block.len = LITTLE_DATA_BLOCK_FRAME_NUM; + event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; + m_little_frame_index = 0; + AppEvent_pushEvent(&event); + HWSSReportBuf_ExchangeAB(); +} \ No newline at end of file diff --git a/app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.h b/app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.h new file mode 100644 index 0000000..fbec34e --- /dev/null +++ b/app/src/heart_wave_sample_service/heart_wave_sample_service_report_buf.h @@ -0,0 +1,9 @@ +#pragma once +#include + +void HWSSReportBuf_push_one_frame(uint32_t *data); + +bool HWSSReportBuf_is_full(void); +void HWSSReportBuf_reset(void); + +void HWSSReportBuf_trigger_little_block_data_event(); \ No newline at end of file