[Add Code]: Add hanning windows
This commit is contained in:
parent
ad03636629
commit
35a4f5c4ff
@ -18,5 +18,5 @@ Log : 旧版本体征监测垫程序 ,兼容最新算法
|
||||
---
|
||||
```
|
||||
Date: 2025年5月9日
|
||||
Log : 增加相关修正数据
|
||||
Log : 增加相关修正数据 增加窗函数
|
||||
```
|
File diff suppressed because one or more lines are too long
@ -37,6 +37,10 @@ int count_up_hr = 0, count_down_hr = 0, count_up_hr_m = 0, count_down_hr_m = 0,
|
||||
// 数据后处理时计数数据上升与下降次数
|
||||
int count_up_br = 0, count_down_br = 0, count_up_br_m = 0, count_down_br_m = 0, count_out_range_br = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void breathDataPostProcessing(void);
|
||||
/**
|
||||
* @function:
|
||||
@ -742,6 +746,17 @@ void cwt_getBreath_Test(void)
|
||||
}
|
||||
|
||||
#include "MyBandFitter.h"
|
||||
void apply_hanning_window(float32_t *input, float32_t *output, uint32_t data_len, uint32_t FFT_SIZE)
|
||||
{
|
||||
// 生成汉宁窗系数并加窗
|
||||
for (uint32_t i = 0; i < data_len; i++)
|
||||
{
|
||||
float32_t window = 0.5f * (1 - cosf(2 * PI * i / (data_len - 1)));
|
||||
output[i] = input[i] * window;
|
||||
}
|
||||
// 补零至FFT_SIZE
|
||||
memset(&output[data_len], 0, (FFT_SIZE - data_len) * sizeof(float32_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* @function: fft_Output
|
||||
@ -753,13 +768,14 @@ void cwt_getBreath_Test(void)
|
||||
#define FFT_POINT 2048
|
||||
uint32_t FFT_Size = FFT_POINT;
|
||||
float32_t FFT_InPut[FFT_POINT] = {0};
|
||||
float32_t FFT_OutPut[FFT_POINT] = {0};
|
||||
float32_t FFT_OutPut[(FFT_POINT / 2) + 1] = {0};
|
||||
float32_t FFT_OutPut_Real[FFT_POINT] = {0};
|
||||
|
||||
float stash_Ratio[ARRAY_NUMBER] = {0};
|
||||
uint16_t fft_HeartBeatCurrentFilter = 0;
|
||||
float32_t HeartValueRes2Peaks[4] = {0.0f};
|
||||
float32_t FFT_HeartRateRes[2] = {0.0f};
|
||||
float32_t Energy_Ratio[4] = {0.0f};
|
||||
float32_t fft_Output(float32_t *Input, int Length, char type)
|
||||
{
|
||||
float32_t FFT_HeartRateVal[2] = {0};
|
||||
@ -779,22 +795,18 @@ float32_t fft_Output(float32_t *Input, int Length, char type)
|
||||
// printf("\r\n-----------------Start---------------------\n");
|
||||
/* 初始化结构体S*/
|
||||
arm_rfft_fast_init_f32(&FFT_Struct, FFT_Size);
|
||||
for (int i = 0; i < FFT_POINT; i++)
|
||||
{
|
||||
if (i < Length)
|
||||
FFT_InPut[i] = Input[i];
|
||||
else
|
||||
FFT_InPut[i] = 0;
|
||||
}
|
||||
apply_hanning_window(Input, FFT_InPut, Length, FFT_Size); // 加hanning窗且补零到2048
|
||||
|
||||
arm_rfft_fast_f32(&FFT_Struct, FFT_InPut, FFT_OutPut_Real, FFT_Dir);
|
||||
/* 实数FFT运算*/
|
||||
arm_cmplx_mag_f32(FFT_OutPut_Real, FFT_OutPut, FFT_Size);
|
||||
// for (int i = 0; i < FFT_POINT / 2; i++)
|
||||
// {
|
||||
// printf("%f\r\n", FFT_OutPut[i]);
|
||||
// }
|
||||
// printf("\r\n-----------------End---------------------\n");
|
||||
// 偏置的计算 用于加权
|
||||
arm_cmplx_mag_f32(FFT_OutPut_Real, FFT_OutPut, (FFT_POINT / 2) + 1);
|
||||
// 能量修正(乘以1.63)
|
||||
float32_t total_energy = 0.0f;
|
||||
for (int i = 0; i < (FFT_Size / 2) + 1; i++)
|
||||
{
|
||||
FFT_OutPut[i] *= 1.63f; // 能量校准
|
||||
total_energy += (FFT_OutPut[i]) * (FFT_OutPut[i]);
|
||||
}
|
||||
#if 0
|
||||
if (type == TYPE_HEART)
|
||||
{
|
||||
@ -812,10 +824,17 @@ float32_t fft_Output(float32_t *Input, int Length, char type)
|
||||
valuePeakNum = peakProcess(FFT_OutPut, 200, maxPeakIndex, maxPeakValue);
|
||||
// 对不一样滤波器 进行计算
|
||||
if (fft_HeartBeatCurrentFilter == FILTER_HI_TYPE)
|
||||
{
|
||||
stash_Ratio[0] = maxPeakValue[1] / maxPeakValue[0];
|
||||
Energy_Ratio[0] = (maxPeakValue[0] * maxPeakValue[0]) / total_energy;
|
||||
Energy_Ratio[1] = (maxPeakValue[1] * maxPeakValue[1]) / total_energy;
|
||||
}
|
||||
else if (fft_HeartBeatCurrentFilter == FILTER_LO_TYPE)
|
||||
{
|
||||
stash_Ratio[1] = maxPeakValue[1] / maxPeakValue[0];
|
||||
|
||||
Energy_Ratio[2] = (maxPeakValue[0] * maxPeakValue[0]) / total_energy;
|
||||
Energy_Ratio[3] = (maxPeakValue[1] * maxPeakValue[1]) / total_energy;
|
||||
}
|
||||
FFT_HeartRateVal[0] = (((float32_t)maxPeakIndex[0] * 50.0f) / FFT_POINT) * 60;
|
||||
FFT_HeartRateVal[1] = (((float32_t)maxPeakIndex[1] * 50.0f) / FFT_POINT) * 60;
|
||||
printf("FFT_HeartRateVal [0] : %f", FFT_HeartRateVal[0]);
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
#include "find_peaks.h"
|
||||
#include "MyTool.h"
|
||||
|
||||
void compute_dynamic_threshold_optimized(const float *data, float *thresholds)
|
||||
{
|
||||
@ -157,3 +158,71 @@ int time_domain_heart_rate(float *hp_data)
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
float compute_target_acf(const float *data, int lag, float mean, float total_energy)
|
||||
{
|
||||
const int N = DATA_LENGTH - lag;
|
||||
if (N <= 0 || total_energy < 1e-6f)
|
||||
return 0.0f;
|
||||
|
||||
float sum_product = 0.0f;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
float x = data[i] - mean;
|
||||
float y = data[i + lag] - mean;
|
||||
sum_product += x * y;
|
||||
}
|
||||
return sum_product / total_energy;
|
||||
}
|
||||
// 快速选择心率
|
||||
int fast_select_hr(const float candidates[4], const float *data, float *fft_energy_ratios)
|
||||
{
|
||||
float32_t std = 0.0f;
|
||||
float32_t avg = 0.0f;
|
||||
avg = MyToolAvgValue((float32_t *)data, DATA_LENGTH);
|
||||
std = MyToolStdValue((float32_t *)data, DATA_LENGTH);
|
||||
// 预处理计算均值和总能量
|
||||
float parsed_data[DATA_LENGTH];
|
||||
// memset(parsed_data, data, sizeof(float) * DATA_LENGTH);
|
||||
float mean = 0.0f, total_energy = 0.0f;
|
||||
for (int i = 0; i < DATA_LENGTH; i++)
|
||||
{
|
||||
parsed_data[i] = (data[i] - avg) / std;
|
||||
mean += parsed_data[i];
|
||||
total_energy += parsed_data[i] * parsed_data[i];
|
||||
}
|
||||
mean /= DATA_LENGTH;
|
||||
total_energy -= DATA_LENGTH * mean * mean; // 修正总能量
|
||||
// 遍历候选心率
|
||||
float max_score = -1.0f;
|
||||
int selected_idx = -1;
|
||||
float temp = 0.0f;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
const float hr = (i < 2) ? candidates[i] / 2 : candidates[i];
|
||||
// 转换候选心率为lag值
|
||||
int target_lag = (int)(50 * 60.0f / hr + 0.5f);
|
||||
if (target_lag <= 0 || target_lag >= DATA_LENGTH / 2)
|
||||
continue;
|
||||
// 局部窗口ACF峰值检测
|
||||
float acf_peak = -1.0f;
|
||||
int search_radius = 1;
|
||||
for (int offset = 0; offset <= search_radius; offset++)
|
||||
{
|
||||
int current_lag = target_lag + offset;
|
||||
if (current_lag < 1 || current_lag >= DATA_LENGTH - 1)
|
||||
continue;
|
||||
float acf_val = compute_target_acf(parsed_data, current_lag, mean, total_energy);
|
||||
acf_peak = fmax(acf_peak, acf_val);
|
||||
}
|
||||
// 综合评分(网页6的加权策略)
|
||||
float score = 0.7f * acf_peak + 0.3f * fft_energy_ratios[i];
|
||||
if (score > max_score)
|
||||
{
|
||||
max_score = score;
|
||||
selected_idx = i;
|
||||
}
|
||||
}
|
||||
return selected_idx;
|
||||
}
|
@ -24,5 +24,6 @@ typedef struct {
|
||||
|
||||
|
||||
int time_domain_heart_rate(float* hp_data);
|
||||
int fast_select_hr(const float candidates[4], const float *data, float *fft_energy_ratios);
|
||||
|
||||
#endif // FIND_PEAKS_H
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1048,6 +1048,7 @@ extern char i_count_off_bed;
|
||||
extern char i_count_no_human;
|
||||
extern char i_count_No_Breath;
|
||||
extern float Diff_detail_Record;
|
||||
extern uint16_t EnergyData;
|
||||
extern uint16_t FiveMinutesCount;
|
||||
extern uint16_t fft_HeartBeatRate_Result;
|
||||
extern uint16_t time_HeartBeatRate_Result;
|
||||
@ -1088,17 +1089,14 @@ void wifi_RealTime_log_send(char *MyStr)
|
||||
\"bootResult\": %d,\"log\":\"%s\",\"Diff_detail_Record\": %f,\"ADC_Value\": %.4f,\"Channel_1310\": %d,\"i_count_no\": %d,\"i_count_off_bed\": %d,\
|
||||
\"i_count_No_Breath\": %d,\"i_count_max\": %f,\"FFT_br\": %f,\"Diff\": %f,\"Diff_Detail\": %f,\"OPM\": %f,\"OPM_Record\": %f,\"OPM_Record_2\": %f,\
|
||||
\"OPM_Origin\": %f,\"Ratio[0]\": %f,\"Ratio[1]\": %f,\"Peak[0]\": %f,\"Peak[1]\": %f,\"Peak[2]\": %f,\"Peak[3]\": %f,\"HR_result\": %d,\"time_result\": %d,\
|
||||
\"Optical\": [",
|
||||
\"EnergyData\": %d}",
|
||||
UploadVersion, BuildTimeString,
|
||||
(timeClockCount_Send + (((signed char)warning_config.timeZone) * 60 * 60 * 1000)), timeClockCount_Send, bootResult,
|
||||
MyStr, (float)Diff_detail_Record, ADC_1310, channel_1310, i_count_no_human, i_count_off_bed, i_count_No_Breath, (float)i_count_Max,
|
||||
(float)FFT_br, (float)Diff, (float)Diff_Detail, (float)OPM_Current, (float)OPM_Record, (float)OPM_Record_2, (float)OPM_Original,
|
||||
(float)(stash_Ratio[0]), (float)(stash_Ratio[1]), (float)(HeartValueRes2Peaks[0]), (float)(HeartValueRes2Peaks[1]),
|
||||
(float)(HeartValueRes2Peaks[2]), (float)(HeartValueRes2Peaks[3]), fft_HeartBeatRate_Result, time_HeartBeatRate_Result);
|
||||
length = strlen(JsonOutputBuffer) + strlen(array) + 2;
|
||||
// strcat(JsonOutputBuffer, array);
|
||||
// printf("Length 2 = %d\n", length);
|
||||
strcat(JsonOutputBuffer, "]}");
|
||||
(float)(HeartValueRes2Peaks[2]), (float)(HeartValueRes2Peaks[3]), fft_HeartBeatRate_Result, time_HeartBeatRate_Result, EnergyData);
|
||||
length = strlen(JsonOutputBuffer) + strlen(array);
|
||||
}
|
||||
// printf("%d JSON OUTPUT: %s \n", length, JsonOutputBuffer);
|
||||
str[0] = 0XA5;
|
||||
|
@ -123,6 +123,7 @@ extern char FitterCollectDoneFlag_Breath;
|
||||
extern char FitterCollectDoneFlag_CheckBed;
|
||||
|
||||
extern char WarnConfigDoneFlag;
|
||||
extern float32_t Energy_Ratio[4];
|
||||
extern warning_config_t warning_config;
|
||||
|
||||
WarningMsg_t WarningMsg; // 告警消息
|
||||
@ -872,6 +873,7 @@ float KalmarFilter(float inData)
|
||||
* @return {*}
|
||||
* @author: lzc
|
||||
*/
|
||||
uint16_t EnergyData = 0;
|
||||
uint16_t Chip_ID_Data = 0;
|
||||
uint16_t fft_HeartBeatRate_Hi = 0;
|
||||
uint16_t fft_HeartBeatRate_Lo = 0;
|
||||
@ -896,6 +898,7 @@ int main(void)
|
||||
struct tm *time;
|
||||
time_t timestamp = 0; /* 时间戳 */
|
||||
char Send_Once = 1;
|
||||
int EnergyIndex = 0;
|
||||
int ReSendStartCommand_Count = 0;
|
||||
MattressParameterInit(); // 床垫 初始化
|
||||
// 初始化IIC
|
||||
@ -1009,16 +1012,6 @@ int main(void)
|
||||
if (start_calculate_flg == 1)
|
||||
{
|
||||
start_calculate_flg = 0;
|
||||
//------------------------------ 算法验证 ---------------------------------------//
|
||||
/*
|
||||
printf("\n--------------------- Start --------------------------------\n");
|
||||
fft_heartDataPostProcessing(round(fft_Output(outPutFitterOPMData_Heart,
|
||||
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
||||
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
||||
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
||||
printf("Heart Rate: %d Breath Rate: %d\n", HeartBeatRate, BreathRate);
|
||||
printf("\n--------------------- End --------------------------------\n");
|
||||
*/
|
||||
//------------------------------ FFT算法 ---------------------------------------//
|
||||
if (equipment_status_value == InBed_Status)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "system_stm32f4xx.h"
|
||||
|
||||
// 1 表示是 养老 ; 0 表示 是BCS
|
||||
#define THE_VERSION 1
|
||||
#define THE_VERSION 0
|
||||
|
||||
// 1 表示是 提速 ; 0 表示 正常
|
||||
#define SPEED_UP_MODE_EN 0
|
||||
|
File diff suppressed because one or more lines are too long
@ -390,6 +390,11 @@
|
||||
<WinNumber>1</WinNumber>
|
||||
<ItemText>BreathRate</ItemText>
|
||||
</Ww>
|
||||
<Ww>
|
||||
<count>46</count>
|
||||
<WinNumber>1</WinNumber>
|
||||
<ItemText>FFT_HeartRateVal</ItemText>
|
||||
</Ww>
|
||||
</WatchWindow1>
|
||||
<WatchWindow2>
|
||||
<Ww>
|
||||
|
@ -187,12 +187,12 @@
|
||||
<RvdsMve>0</RvdsMve>
|
||||
<hadIRAM2>1</hadIRAM2>
|
||||
<hadIROM2>0</hadIROM2>
|
||||
<StupSel>8</StupSel>
|
||||
<StupSel>16</StupSel>
|
||||
<useUlib>1</useUlib>
|
||||
<EndSel>0</EndSel>
|
||||
<uLtcg>0</uLtcg>
|
||||
<nSecure>0</nSecure>
|
||||
<RoSelD>3</RoSelD>
|
||||
<RoSelD>4</RoSelD>
|
||||
<RwSelD>4</RwSelD>
|
||||
<CodeSel>0</CodeSel>
|
||||
<OptFeed>0</OptFeed>
|
||||
@ -204,8 +204,8 @@
|
||||
<Ro1Chk>0</Ro1Chk>
|
||||
<Ro2Chk>0</Ro2Chk>
|
||||
<Ro3Chk>0</Ro3Chk>
|
||||
<Ir1Chk>1</Ir1Chk>
|
||||
<Ir2Chk>0</Ir2Chk>
|
||||
<Ir1Chk>0</Ir1Chk>
|
||||
<Ir2Chk>1</Ir2Chk>
|
||||
<Ra1Chk>0</Ra1Chk>
|
||||
<Ra2Chk>0</Ra2Chk>
|
||||
<Ra3Chk>0</Ra3Chk>
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user