DSP 28335 傅里叶变换和滤波程序实现

DSP 28335 傅里叶变换和滤波程序实现

1. 系统配置和头文件

#include "DSP28x_Project.h"     // DSP2833x头文件
#include "math.h"
#include "fpu.h"

// 定义FFT相关参数
#define FFT_SIZE 1024           // FFT点数
#define LOG2_FFT_SIZE 10        // log2(FFT_SIZE)
#define PI 3.14159265358979

// 全局变量声明
#pragma DATA_SECTION(fft_input, "FFTBuffer");
#pragma DATA_SECTION(fft_output, "FFTBuffer");
#pragma DATA_SECTION(fir_coeffs, "FIRCoef");
#pragma DATA_SECTION(iir_coeffs, "IIRCoef");

float fft_input[FFT_SIZE];      // FFT输入缓冲区
float fft_output[FFT_SIZE];     // FFT输出缓冲区
float fft_mag[FFT_SIZE/2];      // 幅值谱
float fft_phase[FFT_SIZE/2];    // 相位谱

// 窗函数
float window[FFT_SIZE];

2. FFT实现(基2时间抽取)

// 复数结构体
typedef struct {
    float real;
    float imag;
} Complex;

// 位反转函数
void bit_reverse(Complex* data, int n)
{
    int i, j, k;
    Complex temp;
    
    j = 0;
    for(i = 0; i < n-1; i++)
    {
        if(i < j)
        {
            temp = data[i];
            data[i] = data[j];
            data[j] = temp;
        }
        
        k = n >> 1;
        while(k <= j)
        {
            j -= k;
            k >>= 1;
        }
        j += k;
    }
}

// 复数乘法
Complex complex_multiply(Complex a, Complex b)
{
    Complex result;
    result.real = a.real * b.real - a.imag * b.imag;
    result.imag = a.real * b.imag + a.imag * b.real;
    return result;
}

// 蝶形运算
void butterfly(Complex* data, int n, int m)
{
    int i, j, k, le, le2;
    Complex u, w, t;
    
    le = 1 << m;
    le2 = le >> 1;
    
    // 初始化旋转因子
    u.real = 1.0;
    u.imag = 0.0;
    w.real = cos(PI / le2);
    w.imag = -sin(PI / le2);
    
    for(j = 0; j < le2; j++)
    {
        for(i = j; i < n; i += le)
        {
            int ip = i + le2;
            t = complex_multiply(data[ip], u);
            data[ip].real = data[i].real - t.real;
            data[ip].imag = data[i].imag - t.imag;
            data[i].real = data[i].real + t.real;
            data[i].imag = data[i].imag + t.imag;
        }
        u = complex_multiply(u, w);
    }
}

// 主FFT函数
void fft(float* input, float* output_real, float* output_imag, int n, int log2n)
{
    int i;
    Complex* data = (Complex*)output_real;  // 复用输出缓冲区
    
    // 准备复数数据
    for(i = 0; i < n; i++)
    {
        data[i].real = input[i];
        data[i].imag = 0.0;
    }
    
    // 位反转
    bit_reverse(data, n);
    
    // 蝶形运算
    for(i = 1; i <= log2n; i++)
    {
        butterfly(data, n, i);
    }
    
    // 分离实部和虚部
    for(i = 0; i < n; i++)
    {
        output_real[i] = data[i].real;
        output_imag[i] = data[i].imag;
    }
}

3. 窗函数生成

// 汉宁窗
void hanning_window(float* window, int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
        window[i] = 0.5 * (1.0 - cos(2.0 * PI * i / (n - 1)));
    }
}

// 海明窗
void hamming_window(float* window, int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
        window[i] = 0.54 - 0.46 * cos(2.0 * PI * i / (n - 1));
    }
}

// 应用窗函数
void apply_window(float* data, float* window, int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
        data[i] *= window[i];
    }
}

4. 幅值和相位计算

// 计算幅值谱
void compute_magnitude(float* real, float* imag, float* mag, int n)
{
    int i;
    for(i = 0; i < n/2; i++)  // 只计算前一半(对称)
    {
        mag[i] = sqrt(real[i] * real[i] + imag[i] * imag[i]);
    }
}

// 计算相位谱
void compute_phase(float* real, float* imag, float* phase, int n)
{
    int i;
    for(i = 0; i < n/2; i++)
    {
        if(real[i] != 0.0)
        {
            phase[i] = atan2(imag[i], real[i]) * 180.0 / PI;
        }
        else
        {
            phase[i] = 0.0;
        }
    }
}

5. FIR滤波器实现

// FIR滤波器结构体
typedef struct {
    float* coeffs;     // 滤波器系数
    float* buffer;     // 延迟线缓冲区
    int length;        // 滤波器长度
    int index;         // 当前索引
} FIRFilter;

// 初始化FIR滤波器
void fir_init(FIRFilter* fir, float* coeffs, float* buffer, int length)
{
    fir->coeffs = coeffs;
    fir->buffer = buffer;
    fir->length = length;
    fir->index = 0;
    
    // 清空缓冲区
    int i;
    for(i = 0; i < length; i++)
    {
        fir->buffer[i] = 0.0;
    }
}

// FIR滤波器处理
float fir_filter(FIRFilter* fir, float input)
{
    int i;
    float output = 0.0;
    
    // 更新缓冲区
    fir->buffer[fir->index] = input;
    
    // 计算卷积
    for(i = 0; i < fir->length; i++)
    {
        int idx = (fir->index - i + fir->length) % fir->length;
        output += fir->coeffs[i] * fir->buffer[idx];
    }
    
    // 更新索引
    fir->index = (fir->index + 1) % fir->length;
    
    return output;
}

// 批量FIR滤波
void fir_filter_batch(FIRFilter* fir, float* input, float* output, int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
        output[i] = fir_filter(fir, input[i]);
    }
}

6. IIR滤波器实现

// 二阶IIR滤波器结构体
typedef struct {
    float a1, a2;     // 分母系数
    float b0, b1, b2; // 分子系数
    float x1, x2;     // 输入延迟
    float y1, y2;     // 输出延迟
} IIRBiquad;

// 初始化二阶IIR滤波器
void iir_biquad_init(IIRBiquad* iir, float b0, float b1, float b2, float a1, float a2)
{
    iir->b0 = b0;
    iir->b1 = b1;
    iir->b2 = b2;
    iir->a1 = a1;
    iir->a2 = a2;
    
    iir->x1 = 0.0;
    iir->x2 = 0.0;
    iir->y1 = 0.0;
    iir->y2 = 0.0;
}

// 二阶IIR滤波器处理
float iir_biquad_filter(IIRBiquad* iir, float input)
{
    float output = iir->b0 * input + iir->b1 * iir->x1 + iir->b2 * iir->x2
                   - iir->a1 * iir->y1 - iir->a2 * iir->y2;
    
    // 更新延迟
    iir->x2 = iir->x1;
    iir->x1 = input;
    iir->y2 = iir->y1;
    iir->y1 = output;
    
    return output;
}

7. 滤波器设计函数

// 生成低通FIR滤波器系数(窗函数法)
void design_fir_lpf(float* coeffs, int length, float fc, float fs)
{
    int i, center;
    float omega_c = 2.0 * PI * fc / fs;
    
    center = length / 2;
    
    for(i = 0; i < length; i++)
    {
        if(i == center)
        {
            coeffs[i] = omega_c / PI;
        }
        else
        {
            float n = i - center;
            coeffs[i] = sin(omega_c * n) / (PI * n);
        }
        
        // 应用汉宁窗
        coeffs[i] *= 0.5 * (1.0 - cos(2.0 * PI * i / (length - 1)));
    }
}

// 生成带通FIR滤波器系数
void design_fir_bpf(float* coeffs, int length, float f1, float f2, float fs)
{
    int i, center;
    float omega1 = 2.0 * PI * f1 / fs;
    float omega2 = 2.0 * PI * f2 / fs;
    
    center = length / 2;
    
    for(i = 0; i < length; i++)
    {
        if(i == center)
        {
            coeffs[i] = (omega2 - omega1) / PI;
        }
        else
        {
            float n = i - center;
            coeffs[i] = (sin(omega2 * n) - sin(omega1 * n)) / (PI * n);
        }
        
        // 应用海明窗
        coeffs[i] *= 0.54 - 0.46 * cos(2.0 * PI * i / (length - 1));
    }
}

8. 实时处理模块

// 实时FFT处理结构体
typedef struct {
    float input_buffer[FFT_SIZE];
    float fft_real[FFT_SIZE];
    float fft_imag[FFT_SIZE];
    float mag[FFT_SIZE/2];
    float phase[FFT_SIZE/2];
    int buffer_index;
    int ready;
} RealTimeFFT;

// 初始化实时FFT
void realtime_fft_init(RealTimeFFT* rt_fft)
{
    int i;
    for(i = 0; i < FFT_SIZE; i++)
    {
        rt_fft->input_buffer[i] = 0.0;
        rt_fft->fft_real[i] = 0.0;
        rt_fft->fft_imag[i] = 0.0;
    }
    for(i = 0; i < FFT_SIZE/2; i++)
    {
        rt_fft->mag[i] = 0.0;
        rt_fft->phase[i] = 0.0;
    }
    rt_fft->buffer_index = 0;
    rt_fft->ready = 0;
}

// 添加新样本
void realtime_fft_add_sample(RealTimeFFT* rt_fft, float sample)
{
    rt_fft->input_buffer[rt_fft->buffer_index] = sample;
    rt_fft->buffer_index++;
    
    if(rt_fft->buffer_index >= FFT_SIZE)
    {
        rt_fft->buffer_index = 0;
        rt_fft->ready = 1;  // 缓冲区已满,可以执行FFT
    }
}

// 执行实时FFT
void realtime_fft_process(RealTimeFFT* rt_fft)
{
    if(rt_fft->ready)
    {
        // 应用窗函数
        apply_window(rt_fft->input_buffer, window, FFT_SIZE);
        
        // 执行FFT
        fft(rt_fft->input_buffer, rt_fft->fft_real, rt_fft->fft_imag, FFT_SIZE, LOG2_FFT_SIZE);
        
        // 计算幅值和相位
        compute_magnitude(rt_fft->fft_real, rt_fft->fft_imag, rt_fft->mag, FFT_SIZE);
        compute_phase(rt_fft->fft_real, rt_fft->fft_imag, rt_fft->phase, FFT_SIZE);
        
        rt_fft->ready = 0;
    }
}

9. 主程序和ADC配置

// 全局变量
FIRFilter fir_lpf;
IIRBiquad iir_biquad;
RealTimeFFT rt_fft;

float fir_coeffs[65];      // 65阶FIR滤波器系数
float fir_buffer[65];      // FIR滤波器延迟线
float adc_samples[FFT_SIZE];  // ADC采样数据

// ADC中断服务程序
__interrupt void adc_isr(void)
{
    static int sample_count = 0;
    float sample;
    
    // 读取ADC结果(假设12位ADC)
    sample = (float)AdcRegs.ADCRESULT0 * 3.0 / 4095.0;  // 转换为电压
    
    // FIR滤波
    sample = fir_filter(&fir_lpf, sample);
    
    // IIR滤波
    sample = iir_biquad_filter(&iir_biquad, sample);
    
    // 添加到FFT缓冲区
    realtime_fft_add_sample(&rt_fft, sample);
    
    // 保存样本用于批处理
    adc_samples[sample_count] = sample;
    sample_count++;
    
    if(sample_count >= FFT_SIZE)
    {
        sample_count = 0;
        // 可以触发批处理FFT
    }
    
    // 清除ADC中断标志
    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

// 系统初始化
void System_Init(void)
{
    // 初始化系统控制
    InitSysCtrl();
    
    // 初始化PIE控制
    DINT;
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();
    
    // 初始化ADC
    InitAdc();
    
    // 初始化FPU
    InitFpu();
    
    // 初始化ePWM(用于ADC触发)
    InitEPwm();
}

// ADC配置
void ADC_Config(void)
{
    // 配置ADC时钟
    EALLOW;
    SysCtrlRegs.HISPCP.all = ADC_MODCLK;  // HSPCLK = SYSCLKOUT/ADC_MODCLK
    EDIS;
    
    // 配置ADC
    AdcRegs.ADCTRL1.bit.ACQ_PS = 0x0F;     // 采样窗口大小
    AdcRegs.ADCTRL1.bit.CPS = 0;          // 时钟预分频
    AdcRegs.ADCTRL3.bit.ADCCLKPS = 0x3;   // ADC内核时钟分频
    AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;     // 级联序列模式
    AdcRegs.ADCMAXCONV.bit.MAX_CONV = 0;  // 1个转换
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0;  // 选择ADCINA0
    
    // 使能中断
    AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;  // 使能SEQ1中断
    AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0;  // 每个序列结束中断
    
    // 配置中断
    EALLOW;
    PieVectTable.ADC = &adc_isr;  // 设置中断向量
    EDIS;
    
    PieCtrlRegs.PIEIER1.bit.INTx6 = 1;  // 使能ADC中断
    IER |= M_INT1;                      // 使能CPU中断1
    EINT;                               // 使能全局中断
}

// ePWM配置(用于ADC触发)
void EPWM_Config(void)
{
    // 配置ePWM1
    EPwm1Regs.TBPRD = 1500;  // 周期 = 1500个TBCLK周期
    EPwm1Regs.TBPHS.half.TBPHS = 0;
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;  // 增减计数
    
    // 配置ADC触发
    EPwm1Regs.ETSEL.bit.SOCAEN = 1;  // 使能SOCA
    EPwm1Regs.ETSEL.bit.SOCASEL = 4; // 定时器等于0时触发
    EPwm1Regs.ETPS.bit.SOCAPRD = 1;  // 单次触发
    
    // 启动ePWM
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0;
    EPwm1Regs.TBCTL.bit.CLKDIV = 0;
}

int main(void)
{
    // 系统初始化
    System_Init();
    
    // 初始化变量
    int i;
    
    // 生成窗函数
    hanning_window(window, FFT_SIZE);
    
    // 设计FIR滤波器(低通,截止频率100Hz,采样率1kHz)
    design_fir_lpf(fir_coeffs, 65, 100.0, 1000.0);
    
    // 初始化FIR滤波器
    fir_init(&fir_lpf, fir_coeffs, fir_buffer, 65);
    
    // 设计IIR滤波器(二阶低通,截止频率200Hz,采样率1kHz)
    float fs = 1000.0;
    float fc = 200.0;
    float omega = 2.0 * PI * fc / fs;
    float alpha = sin(omega) / (2.0 * 0.707);  // Q=0.707
    
    float b0 = (1.0 - cos(omega)) / 2.0;
    float b1 = 1.0 - cos(omega);
    float b2 = b0;
    float a0 = 1.0 + alpha;
    float a1 = -2.0 * cos(omega);
    float a2 = 1.0 - alpha;
    
    // 归一化
    b0 /= a0;
    b1 /= a0;
    b2 /= a0;
    a1 /= a0;
    a2 /= a0;
    
    // 初始化IIR滤波器
    iir_biquad_init(&iir_biquad, b0, b1, b2, a1, a2);
    
    // 初始化实时FFT
    realtime_fft_init(&rt_fft);
    
    // 配置ADC
    ADC_Config();
    
    // 配置ePWM
    EPWM_Config();
    
    // 主循环
    while(1)
    {
        // 执行实时FFT处理
        realtime_fft_process(&rt_fft);
        
        // 查找主要频率分量
        float max_mag = 0.0;
        int max_index = 0;
        float sampling_rate = 1000.0;  // 1kHz采样率
        
        for(i = 0; i < FFT_SIZE/2; i++)
        {
            if(rt_fft.mag[i] > max_mag)
            {
                max_mag = rt_fft.mag[i];
                max_index = i;
            }
        }
        
        // 计算频率
        float freq = (float)max_index * sampling_rate / FFT_SIZE;
        
        // 这里可以添加其他处理逻辑
        // 例如:根据频率进行控制,或者通过通信接口发送结果
        
        // 简单的延时
        DELAY_US(1000);
    }
    
    return 0;
}

10. 批处理FFT和滤波示例

// 批处理示例
void batch_processing_example(void)
{
    int i;
    float filtered_data[FFT_SIZE];
    float fft_real[FFT_SIZE];
    float fft_imag[FFT_SIZE];
    float magnitude[FFT_SIZE/2];
    
    // 生成测试信号(50Hz正弦波 + 150Hz正弦波 + 噪声)
    for(i = 0; i < FFT_SIZE; i++)
    {
        float t = (float)i / 1000.0;  // 采样率1kHz
        fft_input[i] = sin(2.0 * PI * 50.0 * t) + 
                       0.5 * sin(2.0 * PI * 150.0 * t) + 
                       0.1 * ((float)rand()/RAND_MAX - 0.5);
    }
    
    // FIR滤波
    fir_filter_batch(&fir_lpf, fft_input, filtered_data, FFT_SIZE);
    
    // 应用窗函数
    apply_window(filtered_data, window, FFT_SIZE);
    
    // 执行FFT
    fft(filtered_data, fft_real, fft_imag, FFT_SIZE, LOG2_FFT_SIZE);
    
    // 计算幅值谱
    compute_magnitude(fft_real, fft_imag, magnitude, FFT_SIZE);
    
    // 查找峰值频率
    float max_mag = 0.0;
    int max_index = 0;
    float sampling_rate = 1000.0;
    
    for(i = 1; i < FFT_SIZE/2; i++)  // 跳过直流分量
    {
        if(magnitude[i] > max_mag)
        {
            max_mag = magnitude[i];
            max_index = i;
        }
    }
    
    float peak_freq = (float)max_index * sampling_rate / FFT_SIZE;
    
    // 可以输出或使用peak_freq
}

11. 优化建议

// 使用DSP库进行优化
#include "DSP28x_FPU.h"
#include "FPU.h"

// 使用TI的FPU库进行复数乘法优化
#pragma CODE_SECTION(complex_multiply_fpu, "ramfuncs");
__interrupt void complex_multiply_fpu(Complex* a, Complex* b, Complex* result)
{
    result->real = a->real * b->real - a->imag * b->imag;
    result->imag = a->real * b->imag + a->imag * b->real;
}

// 使用查找表优化三角函数计算
float sin_table[360];
float cos_table[360];

void init_trig_tables(void)
{
    int i;
    for(i = 0; i < 360; i++)
    {
        float angle = (float)i * PI / 180.0;
        sin_table[i] = sin(angle);
        cos_table[i] = cos(angle);
    }
}

// 优化蝶形运算
#pragma CODE_SECTION(butterfly_optimized, "ramfuncs");
void butterfly_optimized(Complex* data, int n, int m, float* sin_table, float* cos_table)
{
    // 优化版本,使用查找表和循环展开
    // ... 实现略 ...
}

参考代码 基于DSP 28335的傅里叶变化和滤波程序 www.youwenfan.com/contentcnv/71014.html

配置说明

  1. CMD文件配置
MEMORY
{
    PAGE 0:   /* Program Memory */
    PAGE 1:   /* Data Memory */
    
    /* 为FFT缓冲区分配特定内存区域 */
    FFTBuffer  : origin = 0x008000, length = 0x010000
    FIRCoef    : origin = 0x009000, length = 0x001000
    IIRCoef    : origin = 0x00A000, length = 0x001000
}

SECTIONS
{
    /* 分配FFT缓冲区到特定区域 */
    FFTBuffer   : > FFTBuffer,   PAGE = 1
    FIRCoef     : > FIRCoef,     PAGE = 1
    IIRCoef     : > IIRCoef,     PAGE = 1
}
  1. 编译选项

    • 启用FPU支持
    • 优化级别设置为-O2或-O3
    • 使用大内存模式

使用注意事项

  1. 实时性:FFT运算量较大,需要根据实际采样率和点数评估性能
  2. 内存使用:大点数FFT需要大量内存,合理分配内存区域
  3. 数值精度:定点实现时注意数据范围和精度
  4. 中断处理:FFT计算期间可能需要禁用中断以确保数据一致性
  5. 窗函数选择:根据应用需求选择合适的窗函数

专注于matlab/simulink,电子电路,编程