目录
概述
原理
1.信号生成
2.功率计算
代码
仿真
上板验证
概述
本设计实现了复数正弦信号功率检测系统,该系统在EGO1平台上采用Xilinx Artix-7系列XC7A35T-1CSG324C FPGA。设计的主要目标是在信号频率固定的情况下,允许外部对信号幅度进行可变控制(范围从0.01到1)。最终,系统将检测到的信号功率以dBm为单位进行输出显示,其中满刻度为10dBm。
原理
1.信号生成
- 使用DDS核生成两路信号,一路cos信号,一路sin信号。初始信号数据宽度7,有符号数,因此最大值为64,满幅度值宽度为16,即32768。
- 通过matlab生成100个倍率保存到coe文件中,FPGA可以根据按键选择倍率,使信号幅度为32768*(0.01-1)。
2.功率计算
- 对两路信号采样10000个点,分别平方求和,再除以32768*32768归一化得到总功率。后面要转换成dbm,换算后刚好总功率就是平均功率,因此不用除10000。
- 将功率转换到dbm进行显示,公式为:
- 这里为了在数码管上显示,因此将计算的dbm值扩大100倍。
- 因为FPGA算log比较复杂,因此也通过matlab生成对应值,再进行查表。为了保存的lg值没有负数,因此计算1000lg(P*10)的值保存到coe文件中。
- 满足满刻度为10dbm和用于数码管的显示的dbm值的计算如下:
代码
1.生成ratedata和logdata的matlab代码
clc
close all
fid = fopen('ratedata.coe','w');
fprintf( fid,'memory_initialization_radix=16;\n');%生成索引
fprintf( fid, 'memory_initialization_vector =\n' );
N = 100;
r = [0:1:99];
s = 2^15/62*0.01*(1+r); %幅值比例
% r = [0:1:9999];
% s = 1000*log10(1+r); %1000lg转换表
z = round(s);
for k = 1:1:N
fprintf(fid,'%x;\n',z(k));
end
fclose(fid);
2.top模块
`timescale 1ns / 1ps
module top(
input sys_clk,rst,
input [7:0] sw,
output [7:0] an,sseg,sseg0
);
wire [3:0 ] dp;
wire [32:0] sum_power;
wire [15:0] i_signal,q_signal;
wire [12:0] dbmdata,t1000logdt;
wire [15:0] ratedt;
ila_0 ila1(
.clk (sys_clk ),
.probe0 (sum_power ),//33
.probe1 (i_signal ),
.probe2 (q_signal ),
.probe3 (dbmdata ),
.probe4 (sw )
);
ila_1 ila2(
.clk (sys_clk ),
.probe0 (ratedt ),//13
.probe1 (t1000logdt )//16
);
// key_select ukeyd_seg (
// sys_clk,
// rst,
// sw,
// );
display udisplay(
.clk (sys_clk ),
.reset (rst ),
.data (sum_power ),
.p_select (an ),
.sseg (sseg ),
.sseg0 (sseg0 ),
.dbm_data (dbmdata ),
.logdt (t1000logdt )
);
signal_source usgs(
.s_clk (sys_clk ),
.s_a (sw ),
.i_sig (i_signal ),
.q_sig (q_signal ),
.ratedt (ratedt )
);
Pow_cal_ctrl power_ins(
.s_clk (sys_clk ),
.i_signal (i_signal ),
.q_signal (q_signal ),
.sw (sw ),
.s_pow_sum (sum_power )
);
endmodule
两个ila核的设置
3.signal_source模块
`timescale 1ns / 1ps
module signal_source(
input s_clk,
input [7:0 ] s_a,
output [15:0] i_sig,q_sig,ratedt
);
reg [13:0] s_cnt = 0;
always @(posedge s_clk)
begin
if(s_cnt == 9999) //serve as the addr
s_cnt <= 'd0;
else
s_cnt <= s_cnt + 1;
end
reg s_syn_10ms;
always @(posedge s_clk)
begin
if(s_cnt == 101)
s_syn_10ms <= 1'b1;
else
s_syn_10ms <= 1'b0;
end
wire [6:0] s_srci,s_srcq;
wire svalid,cvalid;
src_i is(
.aclk (s_clk ), //: IN STD_LOGIC;
.m_axis_data_tvalid (svalid ), //: OUT STD_LOGIC;
.m_axis_data_tdata (s_srci ), //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
.m_axis_phase_tvalid ( ), //: OUT STD_LOGIC;
.m_axis_phase_tdata ( ) //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
src_q qc(
.aclk (s_clk ), //: IN STD_LOGIC;
.m_axis_data_tvalid (cvalid ), //: OUT STD_LOGIC;
.m_axis_data_tdata (s_srcq ), //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
.m_axis_phase_tvalid ( ), //: OUT STD_LOGIC;
.m_axis_phase_tdata ( ) //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
reg [15:0] temp_si,temp_sq,temp1,temp2;
wire [15:0] rate;
assign ratedt = rate;
always @ * begin //信号位宽扩展
if(s_srci[6])
temp1 = {9'b1_1111_1111,s_srci};
else
temp1 = {9'b0_0000_0000,s_srci};
if(s_srcq[6])
temp2 = {9'b1_1111_1111,s_srcq};
else
temp2 = {9'b0_0000_0000,s_srcq};
end
src_ratedata ins_ratedata(
.a (s_a ), //: IN STD_LOGIC_VECTOR(13 DOWNTO 0);
.clk (s_clk ), //: IN STD_LOGIC;
.qspo (rate ) //: OUT STD_LOGIC_VECTOR(12 DOWNTO 0)
);
always @ * begin
temp_si = temp1*rate;
temp_sq = temp2*rate;
end
assign i_sig = temp_si;
assign q_sig = temp_sq;
endmodule
i路DDS核的设置(未截图的部分默认设置)。q路只需要把output selection改成sine,其它的和i路设置一样。注意ip核名称。
rom核设置:
Depth是数据深度,rate的数据个数为100个,所以设置为128;logdata的个数为10000个,所以设置为16384。
Data Width是数据宽度,rate的为16,logdatade 宽度为13(最大值为4000,够用了)。
最后一步的路径要设置为对应的coe文件路径
4.Pow_cal_ctrl模块
`timescale 1ns / 1ps
module Pow_cal_ctrl(
input s_clk,
input [15:0] i_signal,
input [15:0] q_signal,
input [7:0 ] sw,
output [32:0] s_pow_sum
);
wire s_syn_flag;
reg s_syn_10ms;
reg [13:0] s_cnt = 0;
wire reset;
reg S_delay;
always@(posedge s_clk)
S_delay <= sw;
assign reset = S_delay ^ sw;
always @(posedge s_clk,posedge reset)
begin
if(s_cnt == 9999 || reset) //serve as the addr
s_cnt <= 'd0;
else
s_cnt <= s_cnt + 1;
end
always @(posedge s_clk)
begin
if(s_cnt == 101)
s_syn_10ms <= 1'b1;
else
s_syn_10ms <= 1'b0;
end
Pow_cal ins_pow_cal(
/*input */ . i_clk (s_clk ),
/*input */ . i_syn_10ms (s_syn_10ms ),
/*input [15:0] */ . i_di (i_signal ),
/*input [15:0] */ . i_dq (q_signal ),
. reset (reset ),
/*output */ . o_syn_flag (s_syn_flag ),
/*output reg [32:0]*/ . o_pow_sum (s_pow_sum )
);
endmodule
5.Pow_cal模块
`timescale 1ns / 1ps
module Pow_cal(
input i_clk ,
input i_syn_10ms ,
input [15:0] i_di ,
input [15:0] i_dq ,
input reset ,
output reg o_syn_flag ,
output reg [32:0] o_pow_sum
);
reg s_dsp_sel ;
reg [15:0] s_di_r0 ;
reg [15:0] s_dq_r0 ;
reg [11:0] s_syn_10ms = 0;
wire [47:0] s_pouti ;
wire [47:0] s_poutq ;
reg [31:0] sum_i,sum_q ;
reg s_ce = 0 ;
wire [32:0] s_adder_p ;
reg [32:0] s_pow_sum ;
always @(posedge i_clk)
begin
s_di_r0 <= i_di;
s_dq_r0 <= i_dq;
end
always @(posedge i_clk)
begin
if(i_syn_10ms)
s_dsp_sel <= 1'b0; //the first num per 10ms
else
s_dsp_sel <= 1'b1; //acc
end
genvar i;
generate
begin
for(i = 0;i < 12;i = i + 1)
begin
always @(posedge i_clk)
begin
if(0)
s_syn_10ms <= 0;
else begin
if(i == 0)
begin
s_syn_10ms[0] <= i_syn_10ms;
end
else
begin
s_syn_10ms[i] <= s_syn_10ms[i-1];
end
end
end
end
end
endgenerate
//**dsp mode : 0 -> A*B+C
//** : 1 -> A*B+P
//sum(i^2)_10ms
pow_cal_dsp ins_pow_cal_i(
.CLK (i_clk ), //: IN STD_LOGIC;
.SEL (s_dsp_sel ), //: IN STD_LOGIC_VECTOR(0 DOWNTO 0);endmodule
.A ({{2{s_di_r0[15]}},s_di_r0} ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
.B ({{2{s_di_r0[15]}},s_di_r0} ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
.C ('d0 ), //: IN STD_LOGIC_VECTOR(47 DOWNTO 0);
.P (s_pouti ) //: OUT STD_LOGIC_VECTOR(47 DOWNTO 0)
);
//sum(q^2)_10ms
pow_cal_dsp ins_pow_cal_q(
.CLK (i_clk ), //: IN STD_LOGIC;
.SEL (s_dsp_sel ), //: IN STD_LOGIC_VECTOR(0 DOWNTO 0);endmodule
.A ({{2{s_dq_r0[15]}},s_dq_r0} ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
.B ({{2{s_dq_r0[15]}},s_dq_r0} ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
.C ('d0 ), //: IN STD_LOGIC_VECTOR(47 DOWNTO 0);
.P (s_poutq ) //: OUT STD_LOGIC_VECTOR(47 DOWNTO 0)
);
//sum(i^2)_10ms + sum(q^2)_10ms
i_add_q ins_i_add_q(
.A (sum_i ), //: IN STD_LOGIC_VECTOR(31 DOWNTO 0);
.B (sum_q ), //: IN STD_LOGIC_VECTOR(31 DOWNTO 0);
.CLK (i_clk ), //: IN STD_LOGIC;
.CE (s_ce ), //: IN STD_LOGIC;
.S (s_adder_p ) //: OUT STD_LOGIC_VECTOR(32 DOWNTO 0)
);
always @(posedge i_clk)
begin
o_syn_flag <= 1'b0 ;
if(s_syn_10ms[3]) //the last number of acc mode(A*B+P)
begin
sum_i <= s_pouti[14+:32];
sum_q <= s_poutq[14+:32]; //等于除以2^14
s_ce <= 1'b1 ; //adder on
end
if(s_syn_10ms[6])
begin
s_ce <= 1'b0 ; //adder off,low pow mode
s_pow_sum <= s_adder_p ;
//o_syn_flag <= 1'b1 ; //last 1 clk
end
if(s_syn_10ms[11])
begin
o_pow_sum <= s_pow_sum >> 16; //再除以2^16
o_syn_flag <= 1'b1 ; //last 1 clk
end
end
endmodule
DSP核设置
adder核设置
6.display模块
`timescale 1ns / 1ps
module display(
input clk,reset,
input [32:0 ] data,
output reg [7:0 ] p_select,
output reg [7:0 ] sseg,sseg0,
output reg [12:0 ] dbm_data,
output [12:0 ] logdt
);
localparam N = 19,
scale = 3000;
reg dp;
reg [N-1:0 ] regN;
reg [7:0 ] hex_in;
reg [7:0 ] d_seg1,d_seg2,d_seg3,d_seg4,d_seg5,d_seg6,d_seg7,d_seg8;
reg [12:0 ] temp;
wire [12:0 ] log_data;
//对输入100 MHz/时钟进行分频(100 MHz/2^16)
always @(posedge clk, negedge reset) begin
if (!reset)
regN <= 0;
else
regN <= regN + 1;
end
src_logdata ins_logdata(
.a (data[15:0] ), //: IN STD_LOGIC_VECTOR(13 DOWNTO 0);
.clk (clk ), //: IN STD_LOGIC;
.qspo (log_data ) //: OUT STD_LOGIC_VECTOR(12 DOWNTO 0)
);
assign logdt = log_data;
//计算的dbm值是实际的100倍,为了显示数据保留2位小数
//x扩大10倍保证从表中查的功率为非负,计算时在减去扩大的倍数1000,1000lgx-1000-2000
always @ * begin
dbm_data = log_data-scale;
end
always @ * begin
if(dbm_data[12]) begin
temp = {1'b0,~dbm_data[11:0]}+1;
d_seg1 = temp % 10;
d_seg2 = (temp /10) % 10;
d_seg3 = (temp / 100) % 10;
d_seg4 = temp /1000;
d_seg5 = 8'b0000_1111;
d_seg6 = 8'b1111_1111;
d_seg7 = 8'b1111_1111;
d_seg8 = 8'b1111_1111;
end
else begin
d_seg1 = dbm_data % 10;
d_seg2 = (dbm_data /10) % 10;
d_seg3 = (dbm_data / 100) % 10;
d_seg4 = dbm_data /1000;
d_seg5 = 8'b1111_1111;
d_seg6 = 8'b1111_1111;
d_seg7 = 8'b1111_1111;
d_seg8 = 8'b1111_1111;
end
end
always @ * begin
if(!reset) begin
p_select = 0;
hex_in = 0;
dp = 0;
end else begin
case(regN[N-1:N-3]) //18:16
3'd0:begin
p_select = 8'b0000_0001;
hex_in = d_seg1;
dp = 0;
end
3'd1:begin
p_select = 8'b0000_0010;
hex_in = d_seg2;
dp = 0;
end
3'd2:begin
p_select = 8'b0000_0100;
hex_in = d_seg3;
dp = 1;
end
3'd3:begin
p_select = 8'b0000_1000;
hex_in = d_seg4;
dp = 0;
end
3'd4:begin
p_select = 8'b0001_0000;
hex_in = d_seg5;
dp = 0;
end
3'd5:begin
p_select = 8'b0000_0000;
hex_in = d_seg6;
dp = 0;
end
3'd6:begin
p_select = 8'b0000_0000;
hex_in = d_seg7;
dp = 1;
end
default:begin
p_select = 8'b0000_0000;
hex_in = d_seg8;
dp = 0;
end
endcase
end
end
always @ * begin
case (hex_in)
4'h0: sseg[6:0] = ~7'b0000001;
4'h1: sseg[6:0] = ~7'b1001111;
4'h2: sseg[6:0] = ~7'b0010010;
4'h3: sseg[6:0] = ~7'b0000110;
4'h4: sseg[6:0] = ~7'b1001100;
4'h5: sseg[6:0] = ~7'b0100100;
4'h6: sseg[6:0] = ~7'b0100000;
4'h7: sseg[6:0] = ~7'b0001111;
4'h8: sseg[6:0] = ~7'b0000000;
4'h9: sseg[6:0] = ~7'b0000100;
4'ha: sseg[6:0] = ~7'b0001000;
4'hb: sseg[6:0] = ~7'b1100000;
4'hc: sseg[6:0] = ~7'b0110001;
4'hd: sseg[6:0] = ~7'b1000010;
4'he: sseg[6:0] = ~7'b0110000;
4'hf: sseg[6:0] = 7'b000_0001; //4'hf,负号亮
default:sseg[6:0] = 7'b000_0000; //全不亮
endcase
sseg[7] = dp;
sseg0 = sseg;
end
endmodule
7.tb_top测试模块
`timescale 1ns / 1ps
module tb_top(
);
reg sys_clk,rst;
wire [7:0] d_seg,d_seg0,p_select;
reg [7:0] sw,rate;
initial
begin
sys_clk = 0;
sw = 0;
rst = 0;
#10 rst = 1;
end
always #5 sys_clk = ~sys_clk;
always #5000_00 begin
if(sw == 5)
sw = 0;
else
sw = sw + 1;
if(sw == 1)
rate = 9;
else if(sw == 2)
rate = 99;
else
rate =sw;
end
top utop(
.sys_clk (sys_clk ),
.rst (rst ),
.sw (rate ),
.an (p_select ),
.sseg (d_seg ),
.sseg0 (d_seg0 )
);
endmodule
仿真
上板验证
文章来源:https://www.toymoban.com/news/detail-827540.html
文章来源地址https://www.toymoban.com/news/detail-827540.html
到了这里,关于FPGA实现复信号功率计算的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!