需要用到的软件:waveserialport
vofa++
1.波形想用MCU进行采集首先你要考虑到你的采集频率因为如果你的对象波形即你要采集的波形,他过于快速的话有一些MCU它是不能的比如说有一些它的主频才36兆72兆呢你如果遇到一个特别快的波形毫秒级别那他就检测不了
2.然后你得想个办法,调用定时器也好,或者使用固定延时也罢反正你就是要再定一个采样频率,因为不同波形它的频率是不一样的我们相应的采样频率也得不一样如果说你的采样频率不符合的话你是很难提取一个周期的波形当在数字信号系统中有一条定理它规定了我的采集频率一定要比我的波形的频率要是它频率的一半最少是一半不然的话你的波形就是不完整的,也就是说你的采样频率要比我的波形快2倍这样的话你才能采集到一个完整的波形周期如果说你比的波形的频率还要慢的话那你根本就采集不到一个完整的波形
3.接着你的采样方法去采集你的ADC波形成一个数组然后用串口输出符合你串口波形软件的协议的串口信息到我的串口显示软件里面看看我的波形长的是什么样子 采样频率怎么计算呢就是你点与点之间的间隔吗比如说我这个红光采样是每六毫秒采样一次那就是1秒除以我的六毫秒等于我的赫兹125
在这一步中因为你不知道你的波形大概是多少个点也就是你不知道你的波形在你的采样频率下是多少个数据为一个数组,也就是说你一个周期你不知道你有多少个采样点,那你的数组就要定的越大越好定到你的数组里面可以看得出我一个规律的波形出来,比如说我下面这张图片我订的是一个两百个点的一个数据集去采集我的ADC然后再输出串口然后显示成波形可以明显的看到他们是有一个很虽然说长得不像但是是有一个规律存在在里面的它们长得都十分足够大的足够包含我一个周期的点数的的相似那这就是我们这个数组
4.有了这个数组以后因为我们能从中看出我们一个完整规律的一个波形出来那我们就要把它拆成点然后用手去数一下到底一个周期的波形里面有多少个点呢那你这样那我们数出来的这个数就是我的一个周期以内在当前的采样频率下有多少个点为一个周期也就是我一个周期会包含多少一个采样点注意的是这个采样点的个数会随着我们的采样频率的变化而变化所以说一开始你的采样频率就需要确定好而且要比你的要测的波形的频率快两倍
你看虽然我定数组刚开始定两百,但是我这个两百的数组里面包含了两个周期的波形,那我就把这个连线拆成了点,因为我用的vofa++加这个串口波形显示软件,
我就可以把它切换成连线模式也好然后画点模式也好然后我就可以再这个话点模式下数一下我一个周期大概是有多少个点这里我就数出来了我一个周期大概是有八十个点那我定的数组就不应该是两百而是八十如果你不用模糊佳佳你需要怎么去呃知道你的这个周期大概包含了多少个采样点呢最完整的方法就是不断的下降直到你的波形不完整为止也就是说你从两百降到一百五降到一百四降到一百三然后降到八十看一下你的波形到底在哪一个值它是非常的稳定的非常的好看的准确的
5.所有的波都是可以用正弦波进行组合而成 你用不同频率的正弦波就能组成不同形状的波形,比如说一个血氧的波形就可能由两赫兹的正弦波三赫兹的正弦波和12赫兹的正弦波组成,只需要你把这些几赫兹几赫兹的波形进行拆分,就是把一个波形拆成它的组成正弦波就可以看出你哪一个频率的波形是最多最广泛的,比如说一个血氧的波形就是两赫兹三赫兹和12赫兹的正弦波,那你把它采集到的adc数据输入到某个软件中,让他去帮你提取里面的正弦波,那你的波形是有杂波的,你的杂波出现于六赫兹。十八赫兹或者二十赫兹等等,那这些赫兹它的波形因为只是噪声只是干扰,它不会有规律,所以在你的软件里面显现。出这些频率的波形,它在你传入的波形中出现的概率比较低,它没有那些规律的波形出现的概率比较高,所以你就会得到一种不同频率的波在你传入的波形中出现的频率。哪一个波形出现的哪一个频率波。正弦波出现的最多,那他就是你想要得到的规律波形被拆成的几种频率的正弦波,比如一个带噪声的血氧波形,它是由两赫兹6赫兹12,赫兹20,赫兹30,赫兹40,赫兹十八赫兹的正弦波组成,你把这个波形用adc提取了之后,把数字发到那个软件中一个周期里面他就会帮你分辨这个周期的波形是有多少这种频率的正弦波组成的,
那在你显示的那个结果。中你就会看到两赫兹六赫兹十二赫兹的正弦波,它在你的这个周期波形里面出现的频率是最多的,那也就是说你这个新血氧的波形就是由这几种频率赫兹的波形组成的。那其他的18赫兹20赫兹的波形就是噪声,这样的话你就可以选择低通滤波器,高通滤波器带阻滤波器进行波形。频率的一个滤除,比如说我用低通滤波器截止频率为13赫兹那13赫兹以上的20赫兹18赫兹全部都滤掉了,等于是我的噪声被滤掉了
这个软件它有几个参数
波形点数:就是我要显示多少个串口传进来的波形数据点,也就是说你串口用单片机传数据到电脑之后它会先存储起来组成缓冲区,然后在这个串口波形显示框里面你要指定你要提取你这个缓冲区里面多少个点,把它转换到这个显示区里面,那其他没有转换的,那就还是保存在缓冲区,你显示的波形点越多呢,你这个重复出现的频率正弦波也就越准确,那这些重复出现的频率正弦波就是我这个波形真正组成该波形的频率正弦波,那其他那一些不常出现的频率正弦波就是杂波噪声,我们要做的就是保存我们这个真正组成规律波形的频率正弦波,也就是占比百分百占比百分百最常出现那一片波形要保存起来,其他的波形全部滤掉也就是这张图里面的二十到六十赫兹全部不要了,在严格来说就是十以上的全部波形都不要了,那我们就要使用低通滤波器来完成
FFT点数:自动填写
采样频率:你的mcu采样频率
信号频率:最多出现的频率正弦波 这里就是那个为占比为1的 也就是频率为2hz的正弦波
接下来是我用的滤波函数:
低通滤波器:滤除高于截止频率的波形
#include <stdio.h> #include <math.h> #define PI 3.14159265358979323846 // 滤波器结构体 typedef struct { // 滤波器系数 float b0, b1, b2; float a1, a2; // 状态变量 float x1, x2; // 输入延迟 float y1, y2; // 输出延迟 } LowPassFilter; // 初始化二阶低通滤波器 void initLowPassFilter(LowPassFilter* filter, float cutoffFreq, float sampleRate) { float Q = 1.0f / sqrtf(2.0f); // 巴特沃斯滤波器Q值 float omega0 = 2 * PI * cutoffFreq / sampleRate; float alpha = sinf(omega0) / (2 * Q); // 计算系数 float b0 = (1 - cosf(omega0)) / 2; float b1 = 1 - cosf(omega0); float b2 = b0; float a0 = 1 + alpha; // 归一化系数 filter->b0 = b0 / a0; filter->b1 = b1 / a0; filter->b2 = b2 / a0; filter->a1 = -2 * cosf(omega0) / a0; filter->a2 = (1 - alpha) / a0; // 初始化状态 filter->x1 = filter->x2 = 0; filter->y1 = filter->y2 = 0; } // 处理单个样本 float processSample(LowPassFilter* filter, float input) { float output = filter->b0 * input + filter->b1 * filter->x1 + filter->b2 * filter->x2 - filter->a1 * filter->y1 - filter->a2 * filter->y2; // 更新状态 filter->x2 = filter->x1; filter->x1 = input; filter->y2 = filter->y1; filter->y1 = output; return output; }
使用实例:
(1)
//实例波形数据message_RED[80] message_IR[80] LowPassFilter filter; float output_IR[80]; float output_RED[80]; int main(void) { const float sampleRate = 125.0f; // 采样率1kHz const float cutoffFreq = 4.0f; // 截止频率20Hz const int numSamples = 80; // 处理1000个样本 initLowPassFilter(&filter, cutoffFreq, sampleRate); for(int yy = 0; yy <79; yy++) { float input = message_RED[yy]; output_RED[yy] = processSample(&filter, input); //低通滤波器循环处理 input = message_IR[yy]; output_IR[yy] = processSample(&filter, input); }
(2)
#include <stdio.h> #include <math.h> #define PI 3.14159265358979323846 // 滤波器结构体 typedef struct { // 滤波器系数 float b0, b1, b2; float a1, a2; // 状态变量 float x1, x2; // 输入延迟 float y1, y2; // 输出延迟 } LowPassFilter; // 初始化二阶低通滤波器 void initLowPassFilter(LowPassFilter* filter, float cutoffFreq, float sampleRate) { float Q = 1.0f / sqrtf(2.0f); // 巴特沃斯滤波器Q值 float omega0 = 2 * PI * cutoffFreq / sampleRate; float alpha = sinf(omega0) / (2 * Q); // 计算系数 float b0 = (1 - cosf(omega0)) / 2; float b1 = 1 - cosf(omega0); float b2 = b0; float a0 = 1 + alpha; // 归一化系数 filter->b0 = b0 / a0; filter->b1 = b1 / a0; filter->b2 = b2 / a0; filter->a1 = -2 * cosf(omega0) / a0; filter->a2 = (1 - alpha) / a0; // 初始化状态 filter->x1 = filter->x2 = 0; filter->y1 = filter->y2 = 0; } // 处理单个样本 float processSample(LowPassFilter* filter, float input) { float output = filter->b0 * input + filter->b1 * filter->x1 + filter->b2 * filter->x2 - filter->a1 * filter->y1 - filter->a2 * filter->y2; // 更新状态 filter->x2 = filter->x1; filter->x1 = input; filter->y2 = filter->y1; filter->y1 = output; return output; } int main() { const float sampleRate = 1000.0f; // 采样率1kHz const float cutoffFreq =