Arduino Uno处理BIDMC(PPG)信号无输出问题排查
Arduino Uno处理PPG信号无串口输出的问题排查与修复
1. 全局数组数据污染导致后续计算异常
inreal是全局数组,loop()每次循环都会直接修改它的数值(均值减法、归一化操作直接覆盖原始数据)。第一次循环后数组已变为预处理结果,第二次循环基于错误数据计算,会出现数值异常(如极大/极小值、NaN),最终导致程序卡住无法输出。
修复方案:
在loop()中创建局部数组复制原始数据,避免修改全局数组;或直接将所有处理逻辑移到setup()中,仅执行一次(固定样本测试无需循环)。
void setup() { Serial.begin(9600); while(!Serial); // 等待串口连接 int n=250; double signal[250]; // 复制原始数据到局部数组 for(int j=0;j<n;j++){ signal[j] = inreal[j]; } // 后续预处理、滤波均使用signal数组 }
2. 变量类型不匹配导致maxVal为垃圾值
inreal是double类型数组,均值减法后结果为浮点型,但maxVal被定义为int类型,会截断浮点数值,导致maxVal成为错误的垃圾值。后续归一化时除以错误值,会引发数值异常,中断程序输出。
修复方案:
将maxVal改为double类型:
// 寻找最大值 double maxVal = signal[0]; for (int i = 0; i < n; i++) { if (signal[i] > maxVal) { maxVal = signal[i]; } }
3. 缺少串口连接等待导致输出丢失
Serial.begin(9600)后未等待串口监视器连接,初始输出会直接丢失,甚至引发后续输出异常。
修复方案:
在setup()中添加等待逻辑:
void setup() { Serial.begin(9600); while(!Serial); // 等待串口连接 }
4. DFT计算量过大导致程序卡顿
250点DFT为O(n²)运算,每次loop()需执行62500次循环,且包含三角函数计算,Arduino Uno处理能力有限,会导致CPU长时间占用,无法及时响应串口输出,表现为无输出。
修复方案:
- 将处理逻辑移到
setup()中,仅执行一次; - 替换手动DFT为Arduino官方FFT库,大幅降低计算耗时。
5. 呼吸率计算逻辑错误(附带修复)
当前直接取DFT实部最大值乘以60的逻辑完全错误:频谱幅度应为sqrt(outreal[k]^2 + outimg[k]^2),峰值对应频率为k * 采样率 / 样本数,呼吸率为频率乘以60(BIDMC PPG采样率为125Hz)。
修复方案:
// 寻找频谱峰值对应的频率 double maxAmplitude = 0; int peakIndex = 0; double Fs = 125.0; // BIDMC PPG采样率 for (int i = 0; i < n/2; i++) { // 仅处理正频率部分 double amplitude = sqrt(outreal[i]*outreal[i] + outimg[i]*outimg[i]); if (amplitude > maxAmplitude) { maxAmplitude = amplitude; peakIndex = i; } } // 计算呼吸率 double resp_rate = (peakIndex * Fs / n) * 60; Serial.println(resp_rate);
修复后的核心代码示例
#include <SPI.h> #include<SD.h> #define PI 3.1415926535897932384626433832795 void dft(const double inrealn[],double outreal[],double outimg[],size_t n); double inreal[251]={-9577, // 原始数据保持不变,此处省略 -2082 }; void setup() { Serial.begin(9600); while(!Serial); int n=250; double signal[250]; // 复制原始数据 for(int j=0;j<n;j++){ signal[j] = inreal[j]; } // 均值减法 float sum1=0; for(int j=0;j<n;j++){ sum1=sum1+signal[j]; } float mean=sum1/n; for(int i=0;i<n;i++){ signal[i]=signal[i]-mean; } // 寻找最大值 double maxVal = signal[0]; for (int i = 0; i < n; i++) { if (signal[i] > maxVal) { maxVal = signal[i]; } } // 归一化 for(int j=0;j<n;j++){ signal[j]=signal[j]/maxVal; } // 谐振器系数计算与滤波 float a1=-2*0.997*cos(0.3*2*PI); float a2=0.997*0.997; float b=(1-0.997)*sqrt(1+(0.997*0.997)-2*0.997*cos(2*0.3)); double inrealn[250]={0}; for(int j=2;j<n;j++){ inrealn[j]=-a1*inrealn[j-1]-a2*inrealn[j-2]+b*signal[j]; } // DFT与呼吸率计算 double outreal[250]={0}; double outimg[250]={0}; dft(inrealn,outreal,outimg,n); double maxAmplitude = 0; int peakIndex = 0; double Fs = 125.0; for (int i = 0; i < n/2; i++) { double amplitude = sqrt(outreal[i]*outreal[i] + outimg[i]*outimg[i]); if (amplitude > maxAmplitude) { maxAmplitude = amplitude; peakIndex = i; } } double resp_rate = (peakIndex * Fs / n) * 60; Serial.println(resp_rate); } void loop() { // 空转即可 } void dft(const double inrealn[],double outreal[],double outimg[],size_t n){ for (int k=0;k<n;k++){ double sumreal=0; double sumimg=0; for (int t=0;t<n;t++){ double angles=2*PI*t*k/n; sumreal+=inrealn[t]*cos(angles); sumimg+=-inrealn[t]*sin(angles); } outreal[k]=sumreal; outimg[k]=sumimg; } }
内容的提问来源于stack exchange,提问作者rks
相关产品推荐
相关产品推荐

