此信号处理项目,遇到很多难点:
- Matlab与FPGA之间的信息交互,包括四点:
- 如何将Matlab数据写成16进制txt格式
fid = fopen('e:/matlabr.txt','wt');
fprintf(fid,'%x\n',Sr1); %%x即表示十六进制存储
fclose(fid);
2. FPGA如何读取Matlab生成的txt文件
parameter NN=8000;
reg [31:0] datais[0:NN-1];
reg [31:0] datars[0:NN-1];
$readmemh("e:/matlabi.txt",datais);
$readmemh("e:/matlabr.txt",datars);
这一步是将matlabbi.txt和matlabr.txt文件里的数据写入datais和datars数组。
由于我模拟的是将数组里的数据,一拍一拍的输入,因此:
always @ (posedge clk2)begin
if(add_end)begin
datai <=0;
end
else begin
datai <= datais[i];
end
end
always @ (posedge clk2)begin
if(add_end)begin
datar<=0;
end
else begin
datar<=datars[i];
end
end
always @ (posedge clk2 or negedge rst_n)begin
if(rst_n==1'b0)begin
i<=0;
end
else if(i==NN)begin
i<=0;
end
else begin
i<=i+1;
end
end
assign add_end=i==NN-1;
3. PGA如何将Modesim仿真生成的波形数据保存成txt文件
always #20 j=j+1;
integer w_file;
initial w_file= $fopen("output_i.txt");
always@(j)
begin
$fdisplay(w_file,"%h",output_i);
if(j==(NN-1)) //定义需要保存的数据长短 NN=8000;
$stop;
end
通过这段代码,可以将变量output_i的内容写入output_i_i.txt。
若要存储多个变量,可以增加下面的代码
integer w_file1;
initial w_file1= $fopen("output_i_i.txt");
always@(j)
begin
$fdisplay(w_file1,"%h",output_i_i);
if(j==(NN-1))
$stop;
end
只不过w_file要改成w_file1,变量j可以通用。
4. Matlab如何读取FPGA生成的txt文件
fid=fopen('F:\lmx\dataprocess_top 1\output_i_part.txt','r');
for i=1:2000;
num(i)=fscanf(fid,’%x’,1) %这句话意思是从fid所指的文件以16进制方式读出一个数据
end
fclose(fid);
由于Matlab最多读取64位,默认32的数据,因此我96的数据无法正确读出。当位数比较低的时候,这段代码,亲测可用。
- CORDIC IP核的使用及注意事项
本次试验使用了CORDIC IP核的sin和cos函数,
详细使用方法,可以百度。粘贴复制一下。
- 定点小数的处理
比如我想知道1.5用5位二进制表示,其中第一位为符号位,第二三位为整数位,其余位为小数位,即为0011,最后一位1应乘2的负一次方,但当位数比较多的时候,就不好处理了,比如我想知道1.4856用32位二进制表示,其中第一位为符号位,第二三位为整数位,其余位为小数位。
可以使用如下的代码:
%%%%%%%
clear all;
innum=0.4856;
N=29;
if(innum>1)|(N==0)
disp('error');
retun;
end
count=0;
tempnum=innum;
record=zeros(1,N);
while(N)
count=count+1;%长度小于N
if(count>N)
N=0;
return;
end
tempnum=tempnum*2;%小数转换为二进制,乘2取整
if tempnum>1
record(count)=1;
tempnum=tempnum-1;
elseif(tempnum==1)
record(count)=1;
N=0;%stop loop
else
record(count)=0;
end
end
y=record;
%%%%%%%
- 补码与原码的转换
正数的补码和原码一样
负数的补码为正数原码,按位取反然后加1。
实际应用中,比如8位的数,F5,表示的是多少?
Hex2dec(‘f5’)-2^8 得到的即为对应的数字。
- 顺序代码的执行
自己没想到其他的好方法,用了状态机来实现。原Matlab代码如下
phase_in(k+1)=phase_in(k)+step;
if(phase_in(k+1)>pi)
phase_in(k+1)=phase_in(k+1)-2*pi;
else if(phase_in(k+1)<-pi)
phase_in(k+1)=phase_in(k+1)+2*pi;
end
end
Matlab仿真时需要先加减,得到结果之后再判断。因此是顺序执行的代码。
always @ (posedge clk or negedge rst_n) begin
if(rst_n==1'b0)begin
state<=S1;
end
else if(state==S1)begin
state<=S2;
end
else if(state==S2)begin
state<=S1;
end
else begin
state<=S1;
end
end
always @ (posedge clk or negedge rst_n) begin
if(rst_n==1'b0)begin
phase_in<=0;
end
else if(state==S1)begin
phase_in<=phase_in+STEP;
end
else if(state==S2)begin
if (phase_in[31]==0) begin
if(phase_in>PI)begin
phase_in <=phase_in-2*PI;
end
else begin
phase_in <= phase_in;
end
end
else if((phase_in<<1)<PI_M)begin
phase_in <= phase_in+2*PI;
end
else begin
phase_in<=phase_in;
end
end
end
always @ (*) begin
phase_in2= phase_in<<1;
end
. 补码的判断
FPGA中若与一个数进行比较,if判断语句中并不识别是不是符号数,需要先判断符号位。
比如,32位的数与PI进行比较。其中
parameter PI=32'b00110010010000111111011010101000; 第一位为符号位,第2,3位为整数位,其余为小数位
parameter PI_M=32'b10011011011110000001001010110000;//表示的为-pi的补码,并左移一位
always @ (posedge clk or negedge rst_n) begin
if(rst_n==1'b0)begin
phase_in<=0;
end
if (phase_in[31]==0) begin
if(phase_in>PI)begin
phase_in <=phase_in-2*PI;
end
else begin
phase_in <= phase_in;
end
end
else if((phase_in<<1)<PI_M)begin
phase_in <= phase_in+2*PI;
end
else begin
phase_in<=phase_in;
end
end
end
. IP核的例化
生成ip核后,可以再生成一个Verilog Test Fixture 文件,自动将接口进行例化。
九、Matlab生成MSK信号
clc;
clear all;
F0=0;Baut=200; %MSK信号带宽Baut/2,因此波特率为200时,带宽为100。
F1=-0.25*Baut;
F2=0.25*Baut;
Fs=125000; %采样率为12.5k
N=10*Baut;
Phase=0;
x = randint(N, 1, 2); %生成10s的0,1随机数
load LP120.mat;
for i=1:N
i
if x(i)==0;
F=F1;
else
F=F2;
end
for k=1:Fs/Baut;
Signal((i-1)*(Fs/Baut)+k)=exp(2*pi*k*1j*F/Fs+Phase);
end
if x(i)==0;
Phase=mod((Phase-pi/2),2*pi);
else
Phase=mod((Phase+pi/2),2*pi);
end
end
for k=1:N*Fs/200/50
k
S1(k)=Signal(k*50); %50倍抽取
end