Update project
This commit is contained in:
33
git.bat
Normal file
33
git.bat
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001 >nul
|
||||||
|
echo ========================================
|
||||||
|
echo Git 上传脚本 - Rader_Success_5
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
set GIT_PATH="C:\Program Files\Git\bin\git.exe"
|
||||||
|
set REMOTE_URL=http://lmhrt.cn:6771/ming/Rader_IQ
|
||||||
|
|
||||||
|
echo [1/5] 检查 Git 状态...
|
||||||
|
%GIT_PATH% status
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo [2/5] 添加所有文件到暂存区...
|
||||||
|
%GIT_PATH% add -A
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo [3/5] 提交更改...
|
||||||
|
set /p commit_msg="请输入提交信息 (默认: Update project): "
|
||||||
|
if "%commit_msg%"=="" set commit_msg=Update project
|
||||||
|
%GIT_PATH% commit -m "%commit_msg%"
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo [4/5] 推送到远程仓库...
|
||||||
|
%GIT_PATH% push
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo 上传完成!
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
39
src/main.cpp
39
src/main.cpp
@@ -6,59 +6,42 @@
|
|||||||
#include "radar_vitals.h"
|
#include "radar_vitals.h"
|
||||||
#include "io_flash.h"
|
#include "io_flash.h"
|
||||||
|
|
||||||
|
static float I_buf[BASE_DATA_LEN];
|
||||||
|
static float Q_buf[BASE_DATA_LEN];
|
||||||
|
|
||||||
|
|
||||||
// 全局变量声明
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 雷达数据采集任务
|
|
||||||
* 定期读取ADC数据并调用radar_vitals_process()处理数据
|
|
||||||
* @param parameter 任务参数(未使用)
|
|
||||||
*/
|
|
||||||
void radarDataTask(void *parameter) {
|
void radarDataTask(void *parameter) {
|
||||||
Serial.println("📡 雷达数据采集任务启动");
|
Serial.println("📡 雷达数据采集任务启动");
|
||||||
|
|
||||||
radar_sample_t sample;
|
radar_sample_t sample;
|
||||||
radar_vitals_t vitals;
|
radar_vitals_t vitals;
|
||||||
float I_buf[DATA_LEN];
|
|
||||||
float Q_buf[DATA_LEN];
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
// 采集DATA_LEN个样本
|
for(int i = 0; i < BASE_DATA_LEN; i++) {
|
||||||
for(int i=0; i<DATA_LEN; i++) {
|
sample.i_value = adc1_get_raw(ADC1_CHANNEL_0);
|
||||||
// 读取ADC值
|
sample.q_value = adc1_get_raw(ADC1_CHANNEL_1);
|
||||||
sample.i_value = adc1_get_raw(ADC1_CHANNEL_0); // PIN_I (GPIO1) 对应 ADC1_CHANNEL_0
|
|
||||||
sample.q_value = adc1_get_raw(ADC1_CHANNEL_1); // PIN_Q (GPIO2) 对应 ADC1_CHANNEL_1
|
|
||||||
sample.timestamp = millis();
|
sample.timestamp = millis();
|
||||||
|
|
||||||
// 转换为电压并存储
|
|
||||||
I_buf[i] = (sample.i_value / 4095.0f) * 3.3f;
|
I_buf[i] = (sample.i_value / 4095.0f) * 3.3f;
|
||||||
Q_buf[i] = (sample.q_value / 4095.0f) * 3.3f;
|
Q_buf[i] = (sample.q_value / 4095.0f) * 3.3f;
|
||||||
|
|
||||||
// 延时以达到采样率
|
vTaskDelay(1000 / BASE_SAMPLE_RATE / portTICK_PERIOD_MS);
|
||||||
vTaskDelay(1000 / SAMPLE_RATE / portTICK_PERIOD_MS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算IQ电压平均值
|
|
||||||
float avgI = 0, avgQ = 0;
|
float avgI = 0, avgQ = 0;
|
||||||
for(int i=0; i<DATA_LEN; i++) {
|
for(int i = 0; i < BASE_DATA_LEN; i++) {
|
||||||
avgI += I_buf[i];
|
avgI += I_buf[i];
|
||||||
avgQ += Q_buf[i];
|
avgQ += Q_buf[i];
|
||||||
}
|
}
|
||||||
avgI /= DATA_LEN;
|
avgI /= BASE_DATA_LEN;
|
||||||
avgQ /= DATA_LEN;
|
avgQ /= BASE_DATA_LEN;
|
||||||
|
|
||||||
// 使用新的处理方法
|
radar_process(I_buf, Q_buf, BASE_DATA_LEN);
|
||||||
radar_process(I_buf, Q_buf, DATA_LEN);
|
|
||||||
|
|
||||||
// 获取人体状态
|
|
||||||
human_state_t state = radar_get_state();
|
human_state_t state = radar_get_state();
|
||||||
|
|
||||||
// 统一打印所有状态信息
|
|
||||||
if (state == NO_PERSON) {
|
if (state == NO_PERSON) {
|
||||||
Serial.printf("👤 No person - IQ电压: I=%.3fV, Q=%.3fV\n", avgI, avgQ);
|
Serial.printf("👤 No person - IQ电压: I=%.3fV, Q=%.3fV\n", avgI, avgQ);
|
||||||
} else {
|
} else {
|
||||||
// 打印静止状态、IQ电压和心率呼吸率
|
|
||||||
Serial.printf("👤 Human static - IQ电压: I=%.3fV, Q=%.3fV - 💓 心率: %.1f BPM, 呼吸: %.1f BPM\n", avgI, avgQ, radar_get_heart_bpm(), radar_get_resp_bpm());
|
Serial.printf("👤 Human static - IQ电压: I=%.3fV, Q=%.3fV - 💓 心率: %.1f BPM, 呼吸: %.1f BPM\n", avgI, avgQ, radar_get_heart_bpm(), radar_get_resp_bpm());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +69,7 @@ void setup() {
|
|||||||
xTaskCreatePinnedToCore(
|
xTaskCreatePinnedToCore(
|
||||||
radarDataTask,
|
radarDataTask,
|
||||||
"Radar Data Task",
|
"Radar Data Task",
|
||||||
8192,
|
32768,
|
||||||
NULL,
|
NULL,
|
||||||
4,
|
4,
|
||||||
NULL,
|
NULL,
|
||||||
|
|||||||
@@ -6,23 +6,43 @@
|
|||||||
#define ADC_MAX 4095.0f
|
#define ADC_MAX 4095.0f
|
||||||
#define VREF 3.3f
|
#define VREF 3.3f
|
||||||
#define TWO_PI 6.2831853f
|
#define TWO_PI 6.2831853f
|
||||||
#define RADAR_LAMBDA 0.0125f // 24GHz 波长(米)
|
#define RADAR_LAMBDA 0.0125f
|
||||||
|
|
||||||
/******** 内部状态 ********/
|
/******** 内部状态 ********/
|
||||||
static float fs = 20.0f;
|
static float fs = BASE_SAMPLE_RATE;
|
||||||
|
|
||||||
// 状态变量
|
// 状态变量
|
||||||
static float phase[DATA_LEN];
|
static float phase[BASE_DATA_LEN];
|
||||||
static float unwrap_phase[DATA_LEN];
|
static float unwrap_phase[BASE_DATA_LEN];
|
||||||
static human_state_t human_state = NO_PERSON;
|
static human_state_t human_state = NO_PERSON;
|
||||||
static float resp_bpm = 0;
|
static float resp_bpm = 0;
|
||||||
static float heart_bpm = 0;
|
static float heart_bpm = 0;
|
||||||
|
|
||||||
// 平滑处理相关变量
|
// 平滑处理相关变量
|
||||||
static float resp_bpm_history[10] = {0};
|
static float resp_bpm_history[5] = {0};
|
||||||
static float heart_bpm_history[10] = {0};
|
static float heart_bpm_history[5] = {0};
|
||||||
static int history_index = 0;
|
static int history_index = 0;
|
||||||
|
|
||||||
|
// 降采样缓冲区
|
||||||
|
static float resp_phase[RESP_DATA_LEN];
|
||||||
|
static float hr_phase[HR_DATA_LEN];
|
||||||
|
|
||||||
|
// 简单低通滤波器
|
||||||
|
static float lowpass_filter(float input, float *state, float alpha) {
|
||||||
|
*state = alpha * input + (1.0f - alpha) * *state;
|
||||||
|
return *state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 降采样函数
|
||||||
|
void downsample(float *input, float *output, int input_len, int output_len) {
|
||||||
|
float ratio = (float)input_len / output_len;
|
||||||
|
for(int i = 0; i < output_len; i++) {
|
||||||
|
int idx = (int)(i * ratio);
|
||||||
|
if(idx >= input_len) idx = input_len - 1;
|
||||||
|
output[i] = input[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +52,8 @@ static int history_index = 0;
|
|||||||
/******** 新的雷达处理函数 ********/
|
/******** 新的雷达处理函数 ********/
|
||||||
void radar_process(float *I, float *Q, int len)
|
void radar_process(float *I, float *Q, int len)
|
||||||
{
|
{
|
||||||
|
if(len > BASE_DATA_LEN) len = BASE_DATA_LEN;
|
||||||
|
|
||||||
/* 1. 去直流 (DC Removal)
|
/* 1. 去直流 (DC Removal)
|
||||||
* I'(n) = I(n) - mean(I)
|
* I'(n) = I(n) - mean(I)
|
||||||
* Q'(n) = Q(n) - mean(Q)
|
* Q'(n) = Q(n) - mean(Q)
|
||||||
@@ -92,61 +114,66 @@ void radar_process(float *I, float *Q, int len)
|
|||||||
human_state = STATIC_HUMAN;
|
human_state = STATIC_HUMAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 6. 呼吸 / 心率频率估计
|
/* 6. 降采样处理 */
|
||||||
* 方法:频段能量最大值搜索(简化 DFT)
|
downsample(unwrap_phase, resp_phase, len, RESP_DATA_LEN);
|
||||||
* Fs_eff = SAMPLE_RATE / decimation
|
downsample(unwrap_phase, hr_phase, len, HR_DATA_LEN);
|
||||||
*/
|
|
||||||
const float Fs_eff = 200.0f; // 4kHz / 20
|
|
||||||
|
|
||||||
// ---- 呼吸:0.1 ~ 0.5 Hz ----
|
/* 7. 呼吸频率估计 (0.1 ~ 0.5 Hz) */
|
||||||
float max_resp_mag = 0; float resp_freq = 0;
|
float max_resp_mag = 0;
|
||||||
for(float f=0.1f; f<=0.5f; f+=0.02f){
|
float resp_freq = 0;
|
||||||
|
for(float f = 0.1f; f <= 0.6f; f += 0.002f) {
|
||||||
float re = 0, im = 0;
|
float re = 0, im = 0;
|
||||||
for(int n=0;n<len;n++){
|
for(int n = 0; n < RESP_DATA_LEN; n++) {
|
||||||
float ang = 2*M_PI*f*n/Fs_eff;
|
float ang = 2 * M_PI * f * n / RESP_SAMPLE_RATE;
|
||||||
re += unwrap_phase[n]*cosf(ang);
|
re += resp_phase[n] * cosf(ang);
|
||||||
im -= unwrap_phase[n]*sinf(ang);
|
im -= resp_phase[n] * sinf(ang);
|
||||||
}
|
}
|
||||||
float mag = re * re + im * im;
|
float mag = re * re + im * im;
|
||||||
if(mag > max_resp_mag){ max_resp_mag = mag; resp_freq = f; }
|
if(mag > max_resp_mag) {
|
||||||
|
max_resp_mag = mag;
|
||||||
|
resp_freq = f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
float new_resp_bpm = resp_freq * 60.0f;
|
float new_resp_bpm = resp_freq * 60.0f;
|
||||||
|
|
||||||
// ---- 心率:0.8 ~ 2.5 Hz ----
|
/* 8. 心率频率估计 (0.8 ~ 2.5 Hz) */
|
||||||
float max_hr_mag = 0; float hr_freq = 0;
|
float max_hr_mag = 0;
|
||||||
for(float f=0.8f; f<=2.5f; f+=0.05f){
|
float hr_freq = 0;
|
||||||
|
for(float f = 0.6f; f <= 3.0f; f += 0.01f) {
|
||||||
float re = 0, im = 0;
|
float re = 0, im = 0;
|
||||||
for(int n=0;n<len;n++){
|
for(int n = 0; n < HR_DATA_LEN; n++) {
|
||||||
float ang = 2*M_PI*f*n/Fs_eff;
|
float ang = 2 * M_PI * f * n / HR_SAMPLE_RATE;
|
||||||
re += unwrap_phase[n]*cosf(ang);
|
re += hr_phase[n] * cosf(ang);
|
||||||
im -= unwrap_phase[n]*sinf(ang);
|
im -= hr_phase[n] * sinf(ang);
|
||||||
}
|
}
|
||||||
float mag = re * re + im * im;
|
float mag = re * re + im * im;
|
||||||
if(mag > max_hr_mag){ max_hr_mag = mag; hr_freq = f; }
|
if(mag > max_hr_mag) {
|
||||||
|
max_hr_mag = mag;
|
||||||
|
hr_freq = f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
float new_heart_bpm = hr_freq * 60.0f;
|
float new_heart_bpm = hr_freq * 60.0f;
|
||||||
|
|
||||||
// 异常值检测和过滤
|
// 异常值检测和过滤
|
||||||
if(new_heart_bpm < 40 || new_heart_bpm > 180) {
|
if(new_heart_bpm < 40 || new_heart_bpm > 180) {
|
||||||
new_heart_bpm = heart_bpm; // 使用上次值
|
new_heart_bpm = heart_bpm;
|
||||||
}
|
}
|
||||||
if(new_resp_bpm < 4 || new_resp_bpm > 40) {
|
if(new_resp_bpm < 4 || new_resp_bpm > 40) {
|
||||||
new_resp_bpm = resp_bpm; // 使用上次值
|
new_resp_bpm = resp_bpm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移动平均滤波
|
// 移动平均滤波
|
||||||
heart_bpm_history[history_index] = new_heart_bpm;
|
heart_bpm_history[history_index] = new_heart_bpm;
|
||||||
resp_bpm_history[history_index] = new_resp_bpm;
|
resp_bpm_history[history_index] = new_resp_bpm;
|
||||||
history_index = (history_index + 1) % 10;
|
history_index = (history_index + 1) % 5;
|
||||||
|
|
||||||
// 计算平均值
|
|
||||||
float sum_hr = 0, sum_resp = 0;
|
float sum_hr = 0, sum_resp = 0;
|
||||||
for(int i=0; i<10; i++){
|
for(int i = 0; i < 5; i++) {
|
||||||
sum_hr += heart_bpm_history[i];
|
sum_hr += heart_bpm_history[i];
|
||||||
sum_resp += resp_bpm_history[i];
|
sum_resp += resp_bpm_history[i];
|
||||||
}
|
}
|
||||||
heart_bpm = sum_hr / 10.0f;
|
heart_bpm = sum_hr / 5.0f;
|
||||||
resp_bpm = sum_resp / 10.0f;
|
resp_bpm = sum_resp / 5.0f;
|
||||||
|
|
||||||
// 四舍五入到最接近的整数
|
// 四舍五入到最接近的整数
|
||||||
heart_bpm = roundf(heart_bpm);
|
heart_bpm = roundf(heart_bpm);
|
||||||
@@ -166,13 +193,12 @@ float radar_get_heart_bpm(){ return heart_bpm; }
|
|||||||
/******** 初始化 ********/
|
/******** 初始化 ********/
|
||||||
void radar_vitals_init(float fs_hz)
|
void radar_vitals_init(float fs_hz)
|
||||||
{
|
{
|
||||||
fs = fs_hz;
|
fs = BASE_SAMPLE_RATE;
|
||||||
human_state = NO_PERSON;
|
human_state = NO_PERSON;
|
||||||
resp_bpm = 0;
|
resp_bpm = 0;
|
||||||
heart_bpm = 0;
|
heart_bpm = 0;
|
||||||
|
|
||||||
// 初始化历史数据数组
|
for(int i = 0; i < 5; i++) {
|
||||||
for(int i=0; i<10; i++){
|
|
||||||
resp_bpm_history[i] = 0;
|
resp_bpm_history[i] = 0;
|
||||||
heart_bpm_history[i] = 0;
|
heart_bpm_history[i] = 0;
|
||||||
}
|
}
|
||||||
@@ -184,17 +210,15 @@ void radar_vitals_init(float fs_hz)
|
|||||||
* 初始化雷达相关的ADC和引脚
|
* 初始化雷达相关的ADC和引脚
|
||||||
*/
|
*/
|
||||||
void radar_init() {
|
void radar_init() {
|
||||||
// 配置雷达I/Q引脚为ADC输入
|
|
||||||
pinMode(PIN_I, INPUT);
|
pinMode(PIN_I, INPUT);
|
||||||
pinMode(PIN_Q, INPUT);
|
pinMode(PIN_Q, INPUT);
|
||||||
|
|
||||||
// 初始化ADC
|
|
||||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||||
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_12); // PIN_I (GPIO1) 对应 ADC1_CHANNEL_0
|
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_12);
|
||||||
adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_DB_12); // PIN_Q (GPIO2) 对应 ADC1_CHANNEL_1
|
adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_DB_12);
|
||||||
|
|
||||||
Serial.println("🏗️ 初始化雷达管理器...");
|
Serial.println("🏗️ 初始化雷达管理器...");
|
||||||
radar_vitals_init(SAMPLE_RATE);
|
radar_vitals_init(BASE_SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define SAMPLE_RATE 4000 // 基础采样率(Hz)
|
#define BASE_SAMPLE_RATE 200 // 基础采样率(Hz)
|
||||||
#define DATA_LEN 256 // 数据长度
|
#define BASE_DATA_LEN 1024 // 基础数据长度 (5.12秒)
|
||||||
|
|
||||||
|
#define RESP_SAMPLE_RATE 10 // 呼吸处理采样率(Hz) - 2倍呼吸频率上限
|
||||||
|
#define HR_SAMPLE_RATE 50 // 心率处理采样率(Hz) - 2倍心率频率上限
|
||||||
|
|
||||||
|
#define RESP_DATA_LEN 51 // 呼吸处理数据长度 (5.1秒)
|
||||||
|
#define HR_DATA_LEN 256 // 心率处理数据长度 (5.12秒)
|
||||||
|
|
||||||
// 人体状态枚举
|
// 人体状态枚举
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
Reference in New Issue
Block a user