verilog利用线性插值实现正弦波生成器(dds)
笔记哥 /
04-05 /
36点赞 /
0评论 /
915阅读
# verilog实现线性插值实现正弦波生成器
最近在项目上遇到一个需要在低资源FPGA上实现FFT逻辑的项目,而且要求实现窗函数。对于窗函数来说,莫非是实现正弦波生成器,正弦波生成器可以利用DDS模块,CORDIC模块,或者查找表的方式实现,以下主要讲解ROM核线性插值相结合的波形生成器,用于生成正弦波。
# 1.线性插值
线性插值是一种数据估值算法,由于其拟合线是一条直线,所以叫做线性插值。即通过需要估值点的左右两个点的权重以及距离,对估值点的权重进行计算的一种算法。
(x1,y1)
(x1,y1)(x0,y0)
(x0,y0)(x,y)
(x,y)Text is not SVG - cannot display
由于估值拟合线是直线那么,已知`(x0,y0)`和`(x1,y1)`,以及`x`到两点的距离,对`y`进行计算。
\[\begin{split}
&\frac{y\_1-y\_0}{x\_1-x\_0} = \frac{y-y\_0}{x-x\_0} \\ &y = y\_0 + \frac{(y\_1-y\_0)\*(x-x\_0)}{x\_1-x\_0}
\end{split}
\]
对正弦函数进行估值:
(x1,y1)
(x1,y1)(x0,y0)
(x0,y0)(x,y)
(x,y)(x2,y2)
(x2,y2)Text is not SVG - cannot display
其中`(x,y)`表示估算值,`(x2,y2)`表示真实值,误差为`y2-y`,即当`x1-x0`越小,估算值越准确。样本点越多越精确。
# 2.样本生成
以下matlab代码用于生成正弦函数样本值,用于进行数据估算。
```csharp
clc,clear,close all
%% 生成 rom 数据
Width=16;
Depth=256;
phi=linspace(0,2*pi,Depth+1);
phi=phi(1:end-1)';
cos_sig=cos(phi);
cos_sig=floor(cos_sig*(2^(Width-1)-1));
plot(cos_sig)
%% 生成.coe文件
filename='.\cos_rom.coe';
fid = fopen(filename,'w');
radix = 10;
fprintf(fid,"memory_initialization_radix=%d;\n",radix); %使用的进制
fprintf(fid,"memory_initialization_vector=");
for i=1:size(cos_sig,1)
fprintf(fid,"\n%d",cos_sig(i));
end
fprintf(fid,";");
fclose(fid);
```
# 3.verilog实现线性插值
以下将使用参数:样本深度256,相位最大值65536进行讲解。
对某一个点进行线性估值的时候,我们需要知道当前点在样本中对应相应点的邻近点。样本邻近两点相位差`65536/256 = 256`,假设插值相位位置为phase,则相邻点为`floor(phase/256)`和`floor(phase/256)+1`,`floor`表示向下取整,rom表示查找表数据。
那么
\[\begin{equation}
y = y\_0 + \frac{(y\_1-y\_0)\*(x-x\_0)}{x\_1-x\_0}
= rom(floor(phase/256)) + \frac{(rom(floor(phase/256) + 1)-rom(floor(phase/256)))\*(phase-floor(phase/256)\*256)}{256}
\end{equation}
\]
以下为VERILOG代码实现:
```csharp
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/03/29 15:47:50
// Design Name:
// Module Name: cos_gen_pipeline
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module cos_gen_pipeline(
input clk ,
input rst ,
input valid ,
input [15:0] phase , //相位,0~65535对应0~2pi)
output rdy ,
output reg [15:0] cos_out
);
reg [4:0] valid_d;
always @(posedge clk) begin
if(rst)begin
valid_d <= 0;
end else begin
valid_d <= {valid_d[3:0],valid};
end
end
assign rdy = valid_d[4];
wire [7:0] addr1;
wire [7:0] addr2;
wire signed [15:0] cos_dat1;
wire signed [15:0] cos_dat2;
wire [15:0] phase1;
//-----------线性插值-----------------------------
assign addr1 = (phase>>8) ;
assign addr2 = (phase>>8)+1 ;
assign phase1 = addr1<<8 ;
cos_rom cos_rom_inst1(
.clka (clk ),
.addra (addr1 ),
.douta (cos_dat1 )
);
cos_rom cos_rom_inst2(
.clka (clk ),
.addra (addr2 ),
.douta (cos_dat2 )
);
reg [15:0] phase_d0 ;
reg [15:0] phase_d1 ;
reg [15:0] phase1_d0 ;
reg [15:0] phase1_d1 ;
always @(posedge clk) begin
if(rst)begin
phase_d0 <= 0 ;
phase_d1 <= 0 ;
phase1_d0 <= 0 ;
phase1_d1 <= 0 ;
end else begin
phase_d0 <= phase ;
phase_d1 <= phase_d0 ;
phase1_d0 <= phase1 ;
phase1_d1 <= phase1_d0 ;
end
end
reg [31:0] multi;
reg [15:0] delta_cos_data ;
reg [15:0] delta_phase ;
always @(posedge clk) begin
if(rst)begin
multi <= 0;
end else begin
if(cos_dat2 > cos_dat1)begin
delta_cos_data <= (cos_dat2 - cos_dat1) ;
delta_phase <= phase_d1 - phase1_d1 ;
multi <= delta_cos_data*delta_phase ;
end else begin
delta_cos_data <= (cos_dat1 - cos_dat2) ;
delta_phase <= phase_d1 - phase1_d1 ;
multi <= delta_cos_data*delta_phase ;
end
end
end
reg signed [15:0] cos_dat1_d;
reg signed [15:0] cos_dat2_d;
always @(posedge clk) begin
if(rst)begin
cos_dat1_d <= 0;
cos_dat2_d <= 0;
end else begin
cos_dat1_d <= cos_dat1;
cos_dat2_d <= cos_dat2;
end
end
reg signed [15:0] cos_dat1_d1;
reg signed [15:0] cos_dat2_d1;
always @(posedge clk) begin
if(rst)begin
cos_dat1_d1 <= 0;
cos_dat2_d1 <= 0;
end else begin
cos_dat1_d1 <= cos_dat1_d;
cos_dat2_d1 <= cos_dat2_d;
end
end
always @(posedge clk) begin
if(rst)begin
cos_out <= 0;
end else begin
if(cos_dat2_d1 > cos_dat1_d1)begin
cos_out <= cos_dat1_d1 + (multi >> 8);
end else begin
cos_out <= cos_dat1_d1 - (multi >> 8);
end
end
end
endmodule
```
仿真代码:
```csharp
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/04/05 00:00:38
// Design Name:
// Module Name: tb_cos_gen_pipeline
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_cos_gen_pipeline();
reg clk;
reg rst;
initial begin
clk <=0;
rst <=1;
#300
rst <=0;
end
always #10 clk <= ~clk;
reg valid ;
reg [15:0] phase ;
localparam FREQ_FTW = 6554; // 频率控制字 生成5Mhz的正弦波,采样率50M,round((5/50)*(2^16))
always @(posedge clk)begin
if(rst)begin
valid <= 0;
phase <= 0;
end
else begin
valid <= 1;
phase <= phase + FREQ_FTW;
end
end
wire rdy ;
wire [15:0] cos_out ;
cos_gen_pipeline cos_gen_pipeline(
.clk (clk ),
.rst (rst ),
.valid (valid ), //使能信号
.phase (phase ), //相位,0~65535对应[0~2pi)
.rdy (rdy ), //输出准备好信号
.cos_out (cos_out)
);
integer file = 0;
initial begin
file = $fopen("cos_gen_pipeline.txt", "w");
if (file == 0) begin
$display("Error opening file");
$finish;
end
end
reg [15:0] data_cnt = 0;
always @(posedge clk)begin
if(rdy)begin
data_cnt <= data_cnt + 1;
$fwrite(file, "%d\n", $signed(cos_out));
if(data_cnt == 4096*4-1)begin
$fclose(file);
$finish;
end
end
end
endmodule
```
仿真结果:


这样一个正弦波生成器就完成了,SNR=91db,足以满足大多数的使用情况了,如果需要更高的精度,可以更改样本的点数,为了提升频率精度,需要对相位控制字位宽进行扩展。
本文来自投稿,不代表本站立场,如若转载,请注明出处:http//www.knowhub.vip/share/2/2006
- 热门的技术博文分享
- 1 . ESP实现Web服务器
- 2 . 从零到一:打造高效的金仓社区 API 集成到 MCP 服务方案
- 3 . 使用C#构建一个同时问多个LLM并总结的小工具
- 4 . .NET 原生驾驭 AI 新基建实战系列Milvus ── 大规模 AI 应用的向量数据库首选
- 5 . 在Avalonia/C#中使用依赖注入过程记录
- 6 . [设计模式/Java] 设计模式之工厂方法模式
- 7 . 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
- 8 . SQL 中的各种连接 JOIN 的区别总结!
- 9 . JavaScript 中防抖和节流的多种实现方式及应用场景
- 10 . SaltStack 远程命令执行中文乱码问题
- 11 . 推荐10个 DeepSeek 神级提示词,建议搜藏起来使用
- 12 . C#基础:枚举、数组、类型、函数等解析
- 13 . VMware平台的Ubuntu部署完全分布式Hadoop环境
- 14 . C# 多项目打包时如何将项目引用转为包依赖
- 15 . Chrome 135 版本开发者工具(DevTools)更新内容
- 16 . 从零创建npm依赖,只需执行一条命令
- 17 . 关于 Newtonsoft.Json 和 System.Text.Json 混用导致的的序列化不识别的问题
- 18 . 大模型微调实战之训练数据集准备的艺术与科学
- 19 . Windows快速安装MongoDB之Mongo实战
- 20 . 探索 C# 14 新功能:实用特性为编程带来便利