用verilog HDL实现数字基带信号的2FSK调制

 

2FSK的介绍可以参考:https://blog.csdn.net/qq_39148922/article/details/84337730

下面介绍verilog HDL的源代码

module FSK(
	input clk,//时钟信号
	output reg [7:0]sigOut,//输出已调信号
	output reg [7:0]carryWave1,//1对应的载波幅度
	output reg [7:0]carryWave0,//0对应的载波幅度
	output wire codeSource,//数字基带信号
	output reg codeClk=0,//用来控制数字基带信号的时钟
	output reg stClk=0//用来控制载波的时钟,数字基带时钟周期应为载波时钟的n倍
);

//分频器部分
reg [7:0]codeClkCount=0;//时钟计数器
reg [3:0]carryClkCount=0;//载波时钟计数器
always @(posedge clk)
begin
	//codeClk
	if(codeClkCount==127)
	begin
		codeClk=~codeClk;
		codeClkCount=0;
	end
	else
	begin
		codeClkCount=codeClkCount+1;
	end
	
	//carryClk
	if(carryClkCount==1)
	begin
		stClk=~stClk;
		carryClkCount=0;
	end
	else
	begin
		carryClkCount=carryClkCount+1;
	end
end

//数字基带信号,m序列发生器
reg [5:0]outReg=6'b010101;//序列寄存器初始化
reg mAdded;//m序列移位的辅助变量
assign codeSource=outReg[5];//输出变量为寄存器序列的最高位
always @(negedge codeClk)
begin
	//手动异或
	if(outReg[0]==outReg[5])
	begin
		mAdded=0;
	end
	else
	begin
		mAdded=1;
	end
	outReg=outReg<<1;//对寄存器左移
	outReg=outReg+mAdded;
end

//载波的产生
reg [7:0]waveCount=0;//载波幅度查询变量
always @(posedge stClk)
begin
	if(waveCount==63)
	begin
		waveCount=0;
	end
	else
	begin
		waveCount=waveCount+1;
	end
	
	//根据查询变量进行载波幅度查询
	case(waveCount)
		0:begin carryWave0<=0;carryWave1<=0; end
		1:begin carryWave0<=12;carryWave1<=25; end
		2:begin carryWave0<=25;carryWave1<=49; end
		3:begin carryWave0<=37;carryWave1<=71; end
		4:begin carryWave0<=49;carryWave1<=90; end
		5:begin carryWave0<=60;carryWave1<=106; end
		6:begin carryWave0<=71;carryWave1<=117; end
		7:begin carryWave0<=81;carryWave1<=125; end
		8:begin carryWave0<=90;carryWave1<=127; end
		9:begin carryWave0<=98;carryWave1<=125; end
		10:begin carryWave0<=106;carryWave1<=117; end
		11:begin carryWave0<=112;carryWave1<=106; end
		12:begin carryWave0<=117;carryWave1<=90; end
		13:begin carryWave0<=122;carryWave1<=71; end
		14:begin carryWave0<=125;carryWave1<=49; end
		15:begin carryWave0<=126;carryWave1<=25; end
		16:begin carryWave0<=127;carryWave1<=0; end
		17:begin carryWave0<=126;carryWave1<=-25; end
		18:begin carryWave0<=125;carryWave1<=-49; end
		19:begin carryWave0<=122;carryWave1<=-71; end
		20:begin carryWave0<=117;carryWave1<=-90; end
		21:begin carryWave0<=112;carryWave1<=-106; end
		22:begin carryWave0<=106;carryWave1<=-117; end
		23:begin carryWave0<=98;carryWave1<=-125; end
		24:begin carryWave0<=90;carryWave1<=-127; end
		25:begin carryWave0<=81;carryWave1<=-125; end
		26:begin carryWave0<=71;carryWave1<=-117; end
		27:begin carryWave0<=60;carryWave1<=-106; end
		28:begin carryWave0<=49;carryWave1<=-90; end
		29:begin carryWave0<=37;carryWave1<=-71; end
		30:begin carryWave0<=25;carryWave1<=-49; end
		31:begin carryWave0<=12;carryWave1<=-25; end
		32:begin carryWave0<=0;carryWave1<=0; end
		33:begin carryWave0<=-12;carryWave1<=25; end
		34:begin carryWave0<=-25;carryWave1<=49; end
		35:begin carryWave0<=-37;carryWave1<=71; end
		36:begin carryWave0<=-49;carryWave1<=90; end
		37:begin carryWave0<=-60;carryWave1<=106; end
		38:begin carryWave0<=-71;carryWave1<=117; end
		39:begin carryWave0<=-81;carryWave1<=125; end
		40:begin carryWave0<=-90;carryWave1<=127; end
		41:begin carryWave0<=-98;carryWave1<=125; end
		42:begin carryWave0<=-106;carryWave1<=117; end
		43:begin carryWave0<=-112;carryWave1<=106; end
		44:begin carryWave0<=-117;carryWave1<=90; end
		45:begin carryWave0<=-122;carryWave1<=71; end
		46:begin carryWave0<=-125;carryWave1<=49; end
		47:begin carryWave0<=-126;carryWave1<=25; end
		48:begin carryWave0<=-127;carryWave1<=0; end
		49:begin carryWave0<=-126;carryWave1<=-25; end
		50:begin carryWave0<=-125;carryWave1<=-49; end
		51:begin carryWave0<=-122;carryWave1<=-71; end
		52:begin carryWave0<=-117;carryWave1<=-90; end
		53:begin carryWave0<=-112;carryWave1<=-106; end
		54:begin carryWave0<=-106;carryWave1<=-117; end
		55:begin carryWave0<=-98;carryWave1<=-125; end
		56:begin carryWave0<=-90;carryWave1<=-127; end
		57:begin carryWave0<=-81;carryWave1<=-125; end
		58:begin carryWave0<=-71;carryWave1<=-117; end
		59:begin carryWave0<=-60;carryWave1<=-106; end
		60:begin carryWave0<=-49;carryWave1<=-90; end
		61:begin carryWave0<=-37;carryWave1<=-71; end
		62:begin carryWave0<=-25;carryWave1<=-49; end
		63:begin carryWave0<=-12;carryWave1<=-25; end
	endcase
end

//调制部分
always @(posedge stClk)
begin
	if(codeSource)
	begin
		sigOut=carryWave1;
	end
	else
	begin
		sigOut=carryWave0;
	end
end

endmodule

方法相对粗糙一些,毕竟是第一次用verilog实现调制的过程,就是按照调制的原理分步完成,考虑到的可优化的地方较少。

下面逐个对每个模块进行介绍。

分频器

//分频器部分
reg [7:0]codeClkCount=0;//时钟计数器
reg [3:0]carryClkCount=0;//载波时钟计数器
always @(posedge clk)
begin
	//codeClk
	if(codeClkCount==127)
	begin
		codeClk=~codeClk;
		codeClkCount=0;
	end
	else
	begin
		codeClkCount=codeClkCount+1;
	end
	
	//carryClk
	if(carryClkCount==1)
	begin
		stClk=~stClk;
		carryClkCount=0;
	end
	else
	begin
		carryClkCount=carryClkCount+1;
	end
end

对于分频器,写过verilog的同学应该都比较熟悉。就是让程序去数数嘛,看着时钟滴答滴答的走:1、2、3、4……127!然后将时钟取反一次,再次重新计数。这叫做256分频。计数置位的时刻应该是分频数的一半。

需要特别说明的是,在这里之所以需要两个时钟,主要还是为了下面的系统处理进行服务的。分频数应该适应于要处理的问题。我们希望看到数字信号的每个码元对应正弦波的一个周期,或者两个周期,总之要有一个容易判断的对应关系。不然如果一串数字信号是00001111,这样的信号调制过后,谁能知道一个正弦波中有几个0几个1呢。

至于分频后时钟比例的确定,到后面载波的部分再进一步确定。

数字基带信号的产生

//数字基带信号,m序列发生器
reg [5:0]outReg=6'b010101;//序列寄存器初始化
reg mAdded;//m序列移位的辅助变量
assign codeSource=outReg[5];//输出变量为寄存器序列的最高位
always @(negedge codeClk)
begin
	//手动异或
	if(outReg[0]==outReg[5])
	begin
		mAdded=0;
	end
	else
	begin
		mAdded=1;
	end
	outReg=outReg<<1;//对寄存器左移
	outReg=outReg+mAdded;
end

数字基带信号通过m序列产生。m序列通过控制寄存器移位来产生“不太有规律”的信号,这样的信号通常用来当作一个系统的检测序列。不必太纠结于m序列的产生原理,只要是可以测试系统的二进制序列都可以。完全可以随心所欲地写一串二进制码让它循环输出,也可以达到测试系统的效果。

载波的产生

//载波的产生
reg [7:0]waveCount=0;//载波幅度查询变量
always @(posedge stClk)
begin
	if(waveCount==63)
	begin
		waveCount=0;
	end
	else
	begin
		waveCount=waveCount+1;
	end
	
	//根据查询变量进行载波幅度查询
	case(waveCount)
		0:begin carryWave0<=0;carryWave1<=0; end
		1:begin carryWave0<=12;carryWave1<=25; end
		2:begin carryWave0<=25;carryWave1<=49; end
		3:begin carryWave0<=37;carryWave1<=71; end
		4:begin carryWave0<=49;carryWave1<=90; end
		5:begin carryWave0<=60;carryWave1<=106; end
		6:begin carryWave0<=71;carryWave1<=117; end
		7:begin carryWave0<=81;carryWave1<=125; end
		8:begin carryWave0<=90;carryWave1<=127; end
		9:begin carryWave0<=98;carryWave1<=125; end
		10:begin carryWave0<=106;carryWave1<=117; end
		11:begin carryWave0<=112;carryWave1<=106; end
		12:begin carryWave0<=117;carryWave1<=90; end
		13:begin carryWave0<=122;carryWave1<=71; end
		14:begin carryWave0<=125;carryWave1<=49; end
		15:begin carryWave0<=126;carryWave1<=25; end
		16:begin carryWave0<=127;carryWave1<=0; end
		17:begin carryWave0<=126;carryWave1<=-25; end
		18:begin carryWave0<=125;carryWave1<=-49; end
		19:begin carryWave0<=122;carryWave1<=-71; end
		20:begin carryWave0<=117;carryWave1<=-90; end
		21:begin carryWave0<=112;carryWave1<=-106; end
		22:begin carryWave0<=106;carryWave1<=-117; end
		23:begin carryWave0<=98;carryWave1<=-125; end
		24:begin carryWave0<=90;carryWave1<=-127; end
		25:begin carryWave0<=81;carryWave1<=-125; end
		26:begin carryWave0<=71;carryWave1<=-117; end
		27:begin carryWave0<=60;carryWave1<=-106; end
		28:begin carryWave0<=49;carryWave1<=-90; end
		29:begin carryWave0<=37;carryWave1<=-71; end
		30:begin carryWave0<=25;carryWave1<=-49; end
		31:begin carryWave0<=12;carryWave1<=-25; end
		32:begin carryWave0<=0;carryWave1<=0; end
		33:begin carryWave0<=-12;carryWave1<=25; end
		34:begin carryWave0<=-25;carryWave1<=49; end
		35:begin carryWave0<=-37;carryWave1<=71; end
		36:begin carryWave0<=-49;carryWave1<=90; end
		37:begin carryWave0<=-60;carryWave1<=106; end
		38:begin carryWave0<=-71;carryWave1<=117; end
		39:begin carryWave0<=-81;carryWave1<=125; end
		40:begin carryWave0<=-90;carryWave1<=127; end
		41:begin carryWave0<=-98;carryWave1<=125; end
		42:begin carryWave0<=-106;carryWave1<=117; end
		43:begin carryWave0<=-112;carryWave1<=106; end
		44:begin carryWave0<=-117;carryWave1<=90; end
		45:begin carryWave0<=-122;carryWave1<=71; end
		46:begin carryWave0<=-125;carryWave1<=49; end
		47:begin carryWave0<=-126;carryWave1<=25; end
		48:begin carryWave0<=-127;carryWave1<=0; end
		49:begin carryWave0<=-126;carryWave1<=-25; end
		50:begin carryWave0<=-125;carryWave1<=-49; end
		51:begin carryWave0<=-122;carryWave1<=-71; end
		52:begin carryWave0<=-117;carryWave1<=-90; end
		53:begin carryWave0<=-112;carryWave1<=-106; end
		54:begin carryWave0<=-106;carryWave1<=-117; end
		55:begin carryWave0<=-98;carryWave1<=-125; end
		56:begin carryWave0<=-90;carryWave1<=-127; end
		57:begin carryWave0<=-81;carryWave1<=-125; end
		58:begin carryWave0<=-71;carryWave1<=-117; end
		59:begin carryWave0<=-60;carryWave1<=-106; end
		60:begin carryWave0<=-49;carryWave1<=-90; end
		61:begin carryWave0<=-37;carryWave1<=-71; end
		62:begin carryWave0<=-25;carryWave1<=-49; end
		63:begin carryWave0<=-12;carryWave1<=-25; end
	endcase
end

用来进行频率调制的是两种正弦波,而正弦波是连续的模拟信号,在数字系统中只能通过采样对它进行近似化处理。预先设定好64个数值,并且对时钟滴答进行计数。计数到不同的时刻的时候,就按照时刻对应的数值查询预先存储好的正弦波的幅度值。比如现在时钟计数变量waveCount=48;那面就根据case语句找到对应的carryWave0=127,carryWave1=0。

如何获得这些正弦波的数值呢?用计算器么?你有耐心的话可以尝试一下。下面介绍一些如何用matlab生成这些代码,matlab真可谓大学生写作业的偷懒神器(不过有一套答案的话更是美滋滋)。

matlab偷懒代码

t=0:63;
y0=round(127*sin(2*pi*t/64));
y1=round(127*sin(4*pi*t/64));

fid=fopen('dataSave.txt','wt');
for i=0:63
    fprintf(fid,'%d:begin carryWave0<=%d;carryWave1<=%d; end\n',i,y0(i+1),y1(i+1));
end
fclose(fid);

用matlab对正弦波取样,计算,存储到记事本中,而且,在生成的时候直接将语句中的begin end和一些必要的逻辑符号都包括了。毕竟只是个偷懒的手段,重在解决问题,脑补matlab大佬笑笑不说话的样子……

计算正弦波的时候,之所以将幅度取为127,是载波幅度寄存器的限制。8位的寄存器共可以表达256个数字,考虑到正负两边,因此绝对值最大127了。这个要根据调制的时候分配的寄存器大小来考虑。

调制部分

//调制部分
always @(posedge stClk)
begin
	if(codeSource)
	begin
		sigOut=carryWave1;
	end
	else
	begin
		sigOut=carryWave0;
	end
end

2FSK调制的核心思想就是0和1两种不同的状态对应两种不同的频率,到信号接收端的时候通过判断信号的频率从而确定数字信号原本的状态。因此通过一个if的判断语句即可完成。

 

testbench代码如下

`timescale 10ns/10ps
module test_sim;
reg clk;
wire [7:0]sigOut;
wire [7:0]carryWave0;
wire [7:0]carryWave1;
wire codeSource;
wire codeClk;
wire stClk;

FSK FSK(
	.clk (clk),
	.sigOut (sigOut),
	.carryWave0 (carryWave0),
	.carryWave1 (carryWave1),
	.codeSource (codeSource),
	.codeClk (codeClk),
	.stClk (stClk)
);

parameter clkper=100;

initial 
begin
	clk = 1'b0;
end

always
begin
	#(clkper / 2) clk=~clk;
end

endmodule

 

 

通过modelsim得到的仿真结果如下图

用verilog HDL实现数字基带信号的2FSK调制_第1张图片

这里需要注意一个细节,我在最后仿真的时候才看到的一个问题

用verilog HDL实现数字基带信号的2FSK调制_第2张图片

控制数字基带信号的时钟,codeClk,它的第一个上升沿并不是发生在codeClk的一个周期之后,而是半个周期。因此通过时钟上升沿来改变m序列的变化的话,就会产生调制后的信号发生相位突变。

所以在设置时钟的时候应该特别考虑时钟的起始位置,以及两个时钟的配合方式。这里通过把触发方式改为时钟下降沿来解决。

你可能感兴趣的:(用verilog HDL实现数字基带信号的2FSK调制)