1. 项目概述
今天要分享的是我在Altera Cyclone IV FPGA上实现的一个信号处理项目——基于FFT算法的两路正弦波相位差检测系统。这个设计主要应用于需要精确测量信号相位差的场景,比如电机控制、电力系统监测或者通信系统中的载波同步等。
先说说为什么选择FFT方法。相比传统的过零检测法或相关函数法,FFT可以在频域直接提取相位信息,抗噪声能力更强,精度也更高。当然,代价就是需要更多的硬件资源。我在项目中使用了1024点浮点FFT,在50MHz采样率下实现了0.35度的相位分辨率,这个精度对于大多数工业应用已经足够了。
2. 硬件平台选型
2.1 FPGA芯片选择
我选用了Altera(现在属于Intel)的Cyclone IV EP4CE10系列芯片,主要基于以下几点考虑:
- 性价比高:对于1024点FFT这样的中等规模数字信号处理,Cyclone IV的资源完全够用,价格却比高端系列便宜不少
- 开发环境成熟:Quartus II对Cyclone系列的支持非常完善
- 功耗低:静态功耗只有几十毫瓦,适合嵌入式应用
注意:如果项目预算充足,可以考虑Cyclone V或10系列,它们的DSP块更多,性能更好。
2.2 外设接口设计
系统需要处理两路模拟信号输入,所以前端需要:
- 双通道ADC(我用的AD9288,8位100MSPS)
- 抗混叠滤波器(二阶巴特沃斯,截止频率设为采样率的40%)
- 电平转换电路(将ADC输出转换为3.3V LVCMOS)
3. 软件设计与实现
3.1 Quartus II工程配置
使用Quartus II 13.1版本建立工程时,有几个关键设置需要注意:
- 在Device设置中,明确选择具体型号(EP4CE10F17C8)
- 将默认的Verilog版本设置为2001
- 在Analysis & Synthesis Settings中,打开"Optimize HDL Synthesis for Performance"
3.2 FFT IP核配置
Altera提供的FFT IP核是本项目的核心,配置时需要特别注意以下参数:
| 参数项 | 推荐设置 | 说明 |
|---|---|---|
| Transform Length | 1024 | 点数越多分辨率越高,但资源消耗也越大 |
| Data Format | Floating Point | 相位检测需要高精度,浮点比定点更合适 |
| Twiddle ROM | Auto | 让工具自动优化ROM使用 |
| Engine Architecture | Variable Streaming | 平衡速度和资源使用 |
| Complex Multiplier | 3 Multipliers | 性能和资源的折中选择 |
verilog复制fft_core fft_inst (
.clk(clk_100M),
.reset_n(!sys_rst),
.inverse(1'b0), // 正向FFT
.sink_valid(adc_valid),
.sink_sop(adc_sop), // 帧起始
.sink_eop(adc_eop), // 帧结束
.sink_real(adc_data_real),
.sink_imag(12'd0), // 实信号输入
.source_ready(1'b1) // 始终准备接收输出
);
这里有个重要技巧:处理实信号时,将虚部输入接地(12'd0),这样FFT核会自动启用实信号优化模式,节省约30%的资源。
3.3 相位计算实现
FFT输出的频域数据需要转换为相位信息,这涉及到复数到幅值/相位的转换。我采用了CORDIC算法来实现这一功能,因为它在FPGA上效率很高。
verilog复制// 符号位提取和绝对值计算
always @(posedge clk) begin
if(fft_valid) begin
quad_judge <= {fft_imag[31], fft_real[31]}; // 捕获符号位判断象限
abs_real <= fft_real[30:0]; // 取绝对值
abs_imag <= fft_imag[30:0];
end
end
// CORDIC反正切计算
cordic_atan cordic_inst(
.clk(clk),
.areset(sys_rst),
.x_in(abs_real),
.y_in(abs_imag),
.phase_out(raw_phase) // 输出-π到+π
);
这里有几个关键点:
- 先提取符号位判断象限,再计算绝对值,可以节省流水线级数
- CORDIC核输出的相位范围是-π到+π(对应-180°到+180°)
- 弧度到角度的转换建议使用查找表而非实时计算,可以节省大量逻辑资源
3.4 相位差计算与补偿
计算两路信号的相位差时,需要考虑圆周特性,即359°和1°的实际差值是2°而不是358°。这需要通过环形补偿来实现:
verilog复制// 相位差环形修正逻辑
always @(posedge clk) begin
phase_diff_raw <= phase_a - phase_b;
phase_diff <= (phase_diff_raw > 32'h40000000) ? phase_diff_raw - 32'h80000000 :
(phase_diff_raw < 32'hC0000000) ? phase_diff_raw + 32'h80000000 :
phase_diff_raw;
end
这段代码的作用是:
- 当原始相位差大于π(32'h40000000)时,减去2π(32'h80000000)
- 当原始相位差小于-π(32'hC0000000)时,加上2π
- 否则保持原值
这种表示方法使用了Q31定点数格式,其中最高位是符号位,其余31位表示-π到+π的范围。
4. 系统优化与调试
4.1 同步问题解决
在初期测试中,发现相位差测量结果存在随机跳变。通过SignalTap逻辑分析仪抓取波形后发现,这是由于两路信号的FFT处理没有严格同步导致的。
解决方法是在FFT前加入双通道同步FIFO:
verilog复制sync_fifo fifo_dual(
.aclr(sys_rst),
.data({adc_a, adc_b}), // 两路输入合并
.wrreq(adc_valid), // 写入使能
.rdreq(fft_sink_ready), // 读取使能
.q({sync_a, sync_b}) // 同步输出
);
这个FIFO确保了两路信号:
- 使用相同的时钟域
- 同时进入FFT处理管道
- 保持严格的采样对齐
4.2 资源优化技巧
经过编译,整个设计使用了:
- 8923个逻辑单元(LE)
- 36个18位乘法器
- 56Kbit存储器
如果资源紧张,可以考虑以下优化措施:
- 将FFT点数从1024降到512,资源节省约40%,但相位分辨率降为0.7°
- 使用定点数代替浮点数,节省约25%的DSP资源
- 降低FFT输出数据位宽,但要注意保持足够的动态范围
4.3 精度测试结果
在50MHz采样率下,对1MHz正弦波进行测试:
| 理论相位差 | 测量均值 | 标准差 |
|---|---|---|
| 10° | 10.02° | 0.12° |
| 45° | 44.97° | 0.15° |
| 90° | 90.03° | 0.18° |
| 180° | 179.95° | 0.21° |
测试结果表明,系统在全量程范围内都能保持较高的测量精度,标准差控制在0.2°以内,满足大多数工业应用的需求。
5. 实际应用建议
5.1 抗噪声措施
在实际应用中,信号往往伴有噪声,这会降低相位测量精度。建议采取以下措施:
- 在ADC前端加入适当的带通滤波
- 对FFT前的数据进行加窗处理(如汉宁窗)
- 多次测量取平均
- 在数字域加入移动平均滤波器
5.2 动态范围扩展
为了处理幅度变化的输入信号,可以考虑:
- 在前端加入可编程增益放大器(PGA)
- 实现自动增益控制(AGC)环路
- 在FFT前进行归一化处理
5.3 实时性优化
如果需要更高的刷新率,可以:
- 使用重叠FFT技术,牺牲部分效率换取更高的更新率
- 降低FFT点数
- 提高系统时钟频率(注意时序收敛问题)
我在电机控制应用中测试了这个相位检测系统,用于测量转子位置传感器的两路输出信号的相位差。实测表明,系统能够稳定工作在-40°C到85°C的工业温度范围内,相位测量精度保持在0.5°以内,完全满足高性能伺服控制的需求。