STM32F103RCT6使用ADC对50kHZ的波进行顺序采样后做FFT,并计算失真度的代码
时间: 2024-04-30 22:24:04 浏览: 222
stm32ADC采集正弦波并用stm32DSP库的FFT处理数据计算失真度.7z
5星 · 资源好评率100%
由于题目中没有给出具体的失真度定义,这里假设失真度是指采样和FFT过程中引入的误差。
首先需要配置ADC模块进行采样,以下是一个简单的配置:
```c
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1时钟
ADC_InitTypeDef ADC_InitStructure; // ADC配置结构体
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描模式开启
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换模式开启
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 手动触发转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 采样通道数
ADC_Init(ADC1, &ADC_InitStructure); // 初始化ADC1
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5); // 配置ADC1通道0为采样通道
```
然后需要进行数据采样和存储,以下是一个简单的采样和存储代码:
```c
uint16_t adcData[512]; // 存储采样数据的数组
for(int i = 0; i < 512; ++i) {
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 开始转换
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换完成
adcData[i] = ADC_GetConversionValue(ADC1); // 读取采样数据
}
```
接下来是FFT计算,这里可以使用某些库来进行计算,也可以手写FFT算法。以下是手写FFT算法的代码:
```c
#define PI 3.1415926535897932384626433832795
void fft(double *xr, double *xi, int n) {
if(n == 1) return;
double xr1[n / 2], xi1[n / 2], xr2[n / 2], xi2[n / 2];
for(int i = 0; i < n / 2; ++i) {
xr1[i] = xr[2 * i];
xi1[i] = xi[2 * i];
xr2[i] = xr[2 * i + 1];
xi2[i] = xi[2 * i + 1];
}
fft(xr1, xi1, n / 2);
fft(xr2, xi2, n / 2);
double wReal, wImag, wRec, wImc;
for(int k = 0; k < n / 2; ++k) {
wReal = cos(2 * PI * k / n);
wImag = -sin(2 * PI * k / n);
wRec = wReal * xr2[k] - wImag * xi2[k];
wImc = wReal * xi2[k] + wImag * xr2[k];
xr[k] = xr1[k] + wRec;
xi[k] = xi1[k] + wImc;
xr[k + n / 2] = xr1[k] - wRec;
xi[k + n / 2] = xi1[k] - wImc;
}
}
double mag(double a, double b) {
return sqrt(a * a + b * b);
}
double distortion(double *xr, double *xi, int n, double f) {
double maxMag = 0;
int maxIndex = 0;
for(int i = 0; i < n / 2; ++i) {
double m = mag(xr[i], xi[i]);
if(m > maxMag) {
maxMag = m;
maxIndex = i;
}
}
double freq = (double)maxIndex * f / n;
double magReal = xr[maxIndex];
double magImag = xi[maxIndex];
double diffReal = cos(2 * PI * freq) * magReal - sin(2 * PI * freq) * magImag;
double diffImag = cos(2 * PI * freq) * magImag + sin(2 * PI * freq) * magReal;
double diffMag = mag(diffReal, diffImag);
return diffMag / maxMag;
}
int main() {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1时钟
ADC_InitTypeDef ADC_InitStructure; // ADC配置结构体
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描模式开启
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换模式开启
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 手动触发转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 采样通道数
ADC_Init(ADC1, &ADC_InitStructure); // 初始化ADC1
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5); // 配置ADC1通道0为采样通道
uint16_t adcData[512]; // 存储采样数据的数组
for(int i = 0; i < 512; ++i) {
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 开始转换
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换完成
adcData[i] = ADC_GetConversionValue(ADC1); // 读取采样数据
}
double xr[512], xi[512];
for(int i = 0; i < 512; ++i) {
xr[i] = adcData[i] / 4096.0 * 3.3; // 转换为电压值
xi[i] = 0;
}
fft(xr, xi, 512);
double f = 50000.0 / 512;
double dist = distortion(xr, xi, 512, f);
printf("Distortion: %lf\n", dist);
return 0;
}
```
这段代码中采样频率为50000Hz,采样512个点,对采样数据进行FFT计算,并计算失真度。注:此处手写FFT算法只是为了方便说明,实际应用中应该使用现成的库。
失真度的计算方式为:找到幅值最大的频率分量,计算该分量在实际频率上偏离的幅度,并除以幅值最大的分量的幅度。这样计算出来的失真度越小,说明采样和FFT过程中引入的误差越小。
阅读全文