一阶锁相环的FPGA实现(基于quartus+matlab)

一阶锁相环的FPGA实现(基于quartus+matlab)

\quad 前言:本篇文章参考了杜勇的《锁相环技术原理及FPGA实现》,这本书上是以quartus ii 为工具实现的,由于我之前一直使用的是Xilinx的产品,所以就计划将其移植到Vivado平台上,结果就让人崩溃不已~,没有成功。我想了一下,可能是因为ip核的问题吧。所以我不得不转移到quartus平台上来了。
\quad Quartus版本:18.0 prime 标准版
\quad Modelsim版本:Modelsim-altera 10.5b

一.软件使用当中遇到的问题

\quad 由于对Quartus 软件的不熟悉,导致很多问题:

  • ip核配置问题
  • 仿真问题

\quad 仿真问题是最头疼的了。我搞了三天时间,才算搞定。具体的解决方案如下:在官网上下载与quartus同一版本的Modelsim-altera,同时保证电脑中没有其他的modelsim的版本,这样就可以避免配置文件modelsim.ini的冲突了。

二.一阶锁相环的设计与实现

\quad 下面涉及的理论的知识可以去参考一下《锁相环技术原理及FPGA实现》。接下来着重要说的是FPGA的实现。

2.1 环路设计参数相关

\quad 设计参数:

  • 系统频率=采样频率=8KHz
  • 鉴相器输出位宽:19bit
  • 鉴相滤波器系数位宽:8bit
  • 鉴相滤波器输出数据位宽:30bit
  • 环路增益K=34Hz
  • NCO频率字位宽:30bit
  • NCO相位累加字位宽:35bit
  • NCO初始频率字:177986918(400Hz)

环路增益

K = K 0 K d K l p f K=K_0K_dK_{lpf} K=K0KdKlpf

\quad K d K_d Kd为鉴相器增益, K d = 1 2 K m U i U o K_d=\frac{1}{2}K_mU_iU_o Kd=21KmUiUo K 0 K_0 K0为NCO的控制灵敏度, K 0 = f c l k / 2 B n c o K_0=f_{clk}/2^{B_{nco}} K0=fclk/2Bnco K l p f K_{lpf} Klpf f i r fir fir滤波器的增益。

2.2 一阶环的结构

\quad 如下图所示:

在这里插入图片描述

\quad 鉴相器的结构:


在这里插入图片描述

2.2.1鉴相滤波器的实现

\quad 乘法器的实现暂不赘述,下面主要讲 f i r fir fir滤波器的实现。
\quad f i r fir fir滤波器在FPGA上通过例化 i p ip ip核来是实现,这其中最重要的是 f i r fir fir抽头系数的产生。网上的普遍做法是利用 m a t l a b matlab matlab F D A T O O L FDATOOL FDATOOL工具,产生系数。我这里直接用了《锁相环技术原理及FPGA实现》里面的程序生成了对应的lpf.txt。具体参数为:采样频率为8Khz,过渡带为[300 600](单位Hz)具体如下:

function h_pm=FilterCompare
%FilterCompare.m程序清单
%用kaiserord计算满中性能要求的最小滤波器阶数;
%用firpm和fir1分别设计最优滤波器,以及窗函数滤波器,并绘制其幅频响应
%输出最优滤波器系数

fs=8000;         								%采样频率 
fc=[300 600];   								%过渡带
mag=[1 0];       								%窗函数的理想滤波器幅度

dev=[0.04 0.04];  								%纹波
[n,wn,beta,ftype]=kaiserord(fc,mag,dev,fs)    	%获取凯塞窗参数
fpm=[0 fc(1)*2/fs fc(2)*2/fs 1];  				%firpm函数的频段向量
magpm=[1 1 0 0];                  				%firpm函数的幅值向量
format long;

%设计凯塞窗及海明窗滤波器
h_kaiser=fir1(n,wn,ftype,kaiser(n+1,beta));
h_hamm=fir1(n,fc(2)*2/fs);
%设计最优滤波器
h_pm=firpm(n,fpm,magpm);

%求滤波器的幅频响应
m_kaiser=20*log10(abs(fft(h_kaiser,1024)));
m_hamm=20*log10(abs(fft(h_hamm,1024)));
m_pm=20*log10(abs(fft(h_pm,1024)));

%设置幅频响应的横坐标单位为Hz
x_f=[0:(fs/length(m_kaiser)):fs/2];
%只显示正频率部分的幅频响应
m1=m_kaiser(1:length(x_f));
m2=m_hamm(1:length(x_f));
m3=m_pm(1:length(x_f));

%绘制幅频响应曲线
plot(x_f,m1,'-',x_f,m2,'-.',x_f,m3,'--');
xlabel('频率(Hz)');ylabel('幅度(dm_pmB)');
legend('凯塞窗','海明窗','最优滤波器');grid;

\quad 下面着重讲一下fir滤波器的配置,在下面的页面打开FIR II


在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
其他按照默认的设置即可。
\quad 下面是将其在代码中例化:

   pd_filter u2(
	   .clk (clk),
	   .reset_n (pd_filter_rst_n),
	   .ast_sink_data (pd_mult_out[18:0]),//pd_mult_out[18:0]
	   .ast_sink_valid (pd_filter_sink_valid),
	   .ast_sink_error (pd_filter_sink_error),
	   .ast_source_data (pd_filter_out)
	   );

\quad 这里需要注意的是,复位信号的持续时间要超过一个时钟周期,否则 f i r fir fir输出将会异常。

2.2.2 数控振荡器(NCO)的实现

具体配置如图所示:

在这里插入图片描述在这里插入图片描述在这里插入图片描述
\quad 例化如下:

	//实例化NCO核
   nco u3(
	   .phi_inc_i (START_FREQUENCY),
	   .clk (clk),
	   .reset_n (nco_rst_n),
	   .clken (nco_clken),
		.freq_mod_i (pd_filter_out[29:0]),
	   .fsin_o (nco_sin),
	   .fcos_o (nco_cos),
	   .out_valid (nco_out_valid_nc)
		);
2.2.3 调用仿真

\quad 首先要说明的是,由于加入ip核后,仿真会报错,所以就将代码中的有关ip核的部分注释,启动modelsim后再取消代码注释,重新编译后开始仿真,这样就可以仿真ip了。
\quad 一阶环主要测试频差改变时,系统的锁定情况,分类如下:

  1. NCO输出频率400HZ,频差为0,达到锁定状态


    在这里插入图片描述

  2. NCO输出频率417Hz,频差为17Hz,失锁状态

在这里插入图片描述

\quad 经过我多次实验,发现我写的这个一阶锁相环的捕获带宽和《锁相环技术原理及FPGA实现》中的程序相比,小的多。后期在进行二阶锁相环设计时,会将这个问题弄清楚的(感觉上是FIR IP核架构不同)的原因。

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA锁相环是一种数字电路设计技术,用于控制频率和相位,实现时钟同步和信号重构等功能。下面是关于FPGA锁相环代码实现的一些要点。 首先,FPGA锁相环的代码实现通常包括两个主要模块:相位频率控制器(PFC)和数字控制单元(DCU)。 PFC模块负责产生稳定的参考信号和反馈信号,并通过相位比较器(Phase Comparator)计算相位差。然后,它通过滤波器和VCO(Voltage Controlled Oscillator)控制电路,调整VCO的频率和相位,使其与参考信号保持同步。 DCU模块则是用于控制PFC模块的参数,它根据需要设置锁相环的工作频率和相位误差等参数。 在实现FPGA锁相环代码时,可以使用HDL(Hardware Description Language)如VHDL或Verilog进行开发。以下是代码示例: 1. 定义输入输出端口: ```verilog module PLL ( input wire CLK_IN, input wire RESET, output wire CLK_OUT ); ``` 2. 实现PFC模块: ```verilog reg [n-1:0] divider; // 分频器初始值 wire [n-1:0] feedback_signal; // 反馈信号 wire [m-1:0] div_out; // 分频输出信号 reg [n-1:0] phase_difference; // 相位差 always @(posedge CLK_IN or posedge RESET) begin if (RESET) divider <= 0; else begin if (feedback_signal) divider <= divider + 1; end end assign feedback_signal = div_out[n-1]; // 选择其中一个分频输出作为反馈信号 assign CLK_OUT = VCO_out; // VCO_out为调节后的输出信号 ``` 3. 实现DCU模块: ```verilog reg [k-1:0] frequency_set; // 频率设置 reg [n-1:0] phase_error_set; // 相位误差设置 reg [l-1:0] control_signal; // 控制信号 always @(posedge CLK_IN or posedge RESET) begin if (RESET) control_signal <= 0; else begin // 根据相位误差和频率设置计算控制信号 if (phase_difference > phase_error_set) begin control_signal <= control_signal + 1; end else if (phase_difference < -phase_error_set) begin control_signal <= control_signal - 1; end else if (divider > frequency_set) begin control_signal <= control_signal + 1; end else if (divider < frequency_set) begin control_signal <= control_signal - 1; end end end ``` 以上是关于FPGA锁相环代码实现的简要说明。需要根据具体设计要求进行相应的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值