说明:本文为学习笔记,错误不可避免,全当交流。
以单频点信号为例,说明三阶拉格朗日插值的实现方法。
实现结构
假设输入序列为:X(n)=[…,x(-1),x(0),x(1),x(2)]
以一个x(1)…x(10)的序列为例,说明x的计算与插值过程。
X的计算如图所示,计算出x按照上述结构即可实现插值。
matlab实现
% farrow结构三阶拉格朗日插值的算法 % y(k)=((c0*uk+c1)*uk+c2)*uk+c3; % 其中uk为分数间隔,C为滤波结果,非常适合用fpga实现。 % 可用于任意倍率(插值或抽取)的采样率变换。 close all; clear all;
fs = 1.5e3; fc = 1e2; t = 0:1/fs:1/fc; x = cos(2*pi*fc*t); % 系数 v0=[-1/6 1/2 -1/2 1/6]; v1=[1/2 -1 1/2 0 ]; v2=[-1/3 -1/2 1 -1/6]; v3=[0 1 0 0 ];
I=3; % 插值因子 D=2; % 抽取因子 step_factor=D/I;% 步进因子 k=1;%由第二个点开始,第一个点相等 lengthx=length(x); xbuf=zeros(4,1); ukbuf=zeros(1,round(length(x)*I/D));
yy4_1buf=zeros(1,round(I/D*lengthx+4)); yy4_2buf=zeros(1,round(I/D*lengthx+4)); yy4_3buf=zeros(1,round(I/D*lengthx+4)); yy4_4buf=zeros(1,round(I/D*lengthx+4));
yy3_1buf=zeros(1,round(I/D*lengthx+4)); yy3_2buf=zeros(1,round(I/D*lengthx+4)); yy3_3buf=zeros(1,round(I/D*lengthx+4)); pha=0; x=[x 0 0];%补充0 for i=1:1:length(x) %输入序列 %--序列移位 xbuf(4)=xbuf(3); xbuf(3)=xbuf(2); xbuf(2)=xbuf(1); xbuf(1)=x(i); %--滤波 c0=xbuf(1)*v0(1)+xbuf(2)*v0(2)+xbuf(3)*v0(3)+xbuf(4)*v0(4); c1=xbuf(1)*v1(1)+xbuf(2)*v1(2)+xbuf(3)*v1(3)+xbuf(4)*v1(4); c2=xbuf(1)*v2(1)+xbuf(2)*v2(2)+xbuf(3)*v2(3)+xbuf(4)*v2(4); c3=xbuf(1)*v3(1)+xbuf(2)*v3(2)+xbuf(3)*v3(3)+xbuf(4)*v3(4); %起始点重合 if(i==2) y(1)=x(1); end %进去两个数据后开始插值第一个点 if(i>2) pha = pha + 1; while pha >= step_factor pha = pha - step_factor; % 更新输出采样点后的相位 uk =pha ; ukbuf(k)=uk;
yy4_1=(c0*uk);%1 yy4_1buf(k)=yy4_1; yy4_2=(yy4_1); yy4_2buf(k)=yy4_2; yy4_3=(yy4_2+c1);%2 yy4_3buf(k)=yy4_3; yy4_4=(yy4_3); yy4_4buf(k)=yy4_4; yy4=yy4_4;
yy3_1=(yy4*uk);%3 yy3_1buf(k)=yy3_1; yy3_2=(yy3_1); yy3_2buf(k)=yy3_2; yy3_3=(yy3_2+c2);%4 yy3_3buf(k)=yy3_3; yy3_4=(yy3_3); yy3=yy3_4; yy2=((yy3*uk+c3));%5 k = k + 1; % 更新输出索引 y(k)=yy2; m=y(k); end end end
y=y(1:k-1); t1=(0:length(y)-1)/(fs*I/D); t = 0:1/fs:(1/fs)*17; plot(t,x,'--*',t1,y,'--o');
figure(2); subplot(211);%(x=行,列,计数) NFFT=length(x); FS=48*10^3; signal_I_window =x'.*hamming(NFFT); signal_I_window_FFT = fft(signal_I_window,NFFT)/NFFT; plot((-0.5:1/NFFT:0.5-1/NFFT)*(FS),20*log10(fftshift(abs(signal_I_window_FFT(1:NFFT))))); title('ContData ');
subplot(212);%(x=行,列,计数) NFFT=length(y); FS=48*10^3*I/D; signal_I_window =y'.*hamming(NFFT); signal_I_window_FFT = fft(signal_I_window,NFFT)/NFFT; plot((-0.5:1/NFFT:0.5-1/NFFT)*(FS),20*log10(fftshift(abs(signal_I_window_FFT(1:NFFT))))); title('ContData ');
执行结果
FPGA实现
实现结构与matlab相同,fir_core实现滤波器,mult_parallel实现uk的乘加。
C0滤波器的实现
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/06/25 08:45:58
// Design Name:
// Module Name: fir4_core
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fir4_core#(
parameter WIDTH = 16
)(
input i_sys_clk,
input i_reset_h,
input [2*WIDTH-1:0] din,//sfix16_en13 IQ·
output [2*WIDTH-1:0] dout
);
wire [15:0] Fn_mem [3 : 0];//sfix16_14
// assign Fn_mem[0] = 16'H1555;
// assign Fn_mem[1] = 16'HC000;
// assign Fn_mem[2] = 16'H4000;
// assign Fn_mem[3] = 16'HEAAB;
assign Fn_mem[0] = 16'HEAAB;
assign Fn_mem[1] = 16'H4000;
assign Fn_mem[2] = 16'HC000;
assign Fn_mem[3] = 16'H1555;
reg signed [2*WIDTH-1:0] Xn_mem [3 : 0];
wire signed [31:0] Mult_i_mem [3 : 0];//sfix32_en27
wire signed [31:0] Mult_q_mem [3 : 0];//sfix16_en13 MULTI sfix16_en14
wire signed [33:0] Sumi_mem1 ; //sfix34_en27
wire signed [33:0] Sumq_mem1 ;
// assign Xn_mem[0] = i_reset_h ? 32'd0 : din;
// genvar n;
// generate
// for (n=0; n < 6; n=n+1)begin: delayN
// shift_ram_N
// inst1_shift_ram_N(
// .A (0 ),
// .D ({Xn_mem[2],Xn_mem[1],Xn_mem[0]}),
// .SCLR (i_reset_h ),
// .CLK (i_sys_clk ),
// .Q ({Xn_mem[3],Xn_mem[2],Xn_mem[1]})
// );
always @(posedge i_sys_clk) begin
if(i_reset_h)begin
Xn_mem[0] <= 0 ;
Xn_mem[1] <= 0 ;
Xn_mem[2] <= 0 ;
Xn_mem[3] <= 0 ;
end
else begin
Xn_mem[0] <= din;
Xn_mem[1] <= Xn_mem[0] ;
Xn_mem[2] <= Xn_mem[1] ;
Xn_mem[3] <= Xn_mem[2] ;
end
end
// end
// endgenerate
genvar n1;
generate
for (n1=0; n1 <= 3; n1=n1+1)begin: mult_gen
mult_gen_16_16
insti_mult_gen_16_16(
.CLK (i_sys_clk ),
.A (Xn_mem[n1][15:0]), //(15 DOWNTO 0)
.B (Fn_mem[n1] ), //(15 DOWNTO 0)
.P (Mult_i_mem[n1] ) //(31 DOWNTO 0)
);
mult_gen_16_16
instq_mult_gen_16_16(
.CLK (i_sys_clk ),
.A (Xn_mem[n1][31:16]),//(15 DOWNTO 0)
.B (Fn_mem[n1] ), //(15 DOWNTO 0)
.P (Mult_q_mem[n1] ) //(31 DOWNTO 0)
);
end
endgenerate
wire j1;
assign j1=0;
Sum_4Data#(
.WIDTH (32 )
)
insti_Sum_4Data(
.clk (i_sys_clk ),
.rst (i_reset_h ),
.din_1 (Mult_i_mem[0] ),//32bit
.din_2 (Mult_i_mem[0+1] ),
.din_3 (Mult_i_mem[0+2] ),
.din_4 (Mult_i_mem[0+3] ),
.dout (Sumi_mem1 ) //34bit
);
Sum_4Data#(
.WIDTH (32 )
)
instq_Sum_4Data(
.clk (i_sys_clk ),
.rst (i_reset_h ),
.din_1 (Mult_q_mem[0] ),//32bit
.din_2 (Mult_q_mem[0+1] ),
.din_3 (Mult_q_mem[0+2] ),
.din_4 (Mult_q_mem[0+3] ),
.dout (Sumq_mem1 ) //34bit
);
assign dout[15:0] = Sumi_mem1[30 :15]; //sfix16_en13
assign dout[31:16] = Sumq_mem1[30: 15];
endmodule
mult_parallel模块的实现
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/06/26 15:17:47
// Design Name:
// Module Name: mult_parallel
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module mult_parallel(
input i_sys_clk,
input i_reset_h,
input signed [15:0] i_fir_c0,
input signed [15:0] i_fir_c1,
input signed [15:0] i_fir_c2,
input signed [15:0] i_fir_c3,
input signed [15:0] i_uk ,
output signed [15:0] o_mult_parallel,
output o_uk_valid
);
wire signed [31 : 0] w_mult_P_c0;
wire signed [15 : 0] w_mult_P16_c0;
wire signed [31 : 0] w_mult_P_c1;
wire signed [15 : 0] w_mult_P16_c1;
wire signed [31 : 0] w_mult_P_c2;
wire signed [15 : 0] w_mult_P16_c2;
wire signed [16 : 0] r_add_y1;
wire signed [16 : 0] r_add_y2;
wire signed [16 : 0] r_add_y3;
wire signed [15:0] r_fir_c1_d4;
wire signed [15:0] r_fir_c2_d9;
wire signed [15:0] r_fir_c3_d14;
wire signed [15:0] r_uk_d5;
wire signed [15:0] r_uk_d10;
assign w_mult_P16_c0 = w_mult_P_c0[29:14];
assign w_mult_P16_c1 = w_mult_P_c1[29:14];
assign w_mult_P16_c2 = w_mult_P_c2[29:14];
c_shift_ram_0 c_shift_ram_c0_inst (
.A ( 6'd2 ), // input wire [5 : 0] A
.D ( i_fir_c1 ), // input wire [15 : 0] D
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.Q ( r_fir_c1_d4 ) // output wire [15 : 0] Q
);
c_shift_ram_0 c_shift_ram_uk_c0_inst (
.A ( 6'd3 ), // input wire [5 : 0] A
.D ( i_uk ), // input wire [15 : 0] D
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.Q ( r_uk_d5 ) // output wire [15 : 0] Q
);
c_shift_ram_0 c_shift_ram_c1_inst (
.A ( 6'd7 ), // input wire [5 : 0] A
.D ( i_fir_c2 ), // input wire [15 : 0] D
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.Q ( r_fir_c2_d9 ) // output wire [15 : 0] Q
);
c_shift_ram_0 c_shift_ram_uk_c1_inst (
.A ( 6'd8 ), // input wire [5 : 0] A
.D ( i_uk ), // input wire [15 : 0] D
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.Q ( r_uk_d10 ) // output wire [15 : 0] Q
);
c_shift_ram_0 c_shift_ram_c2_inst (
.A ( 6'd12 ), // input wire [5 : 0] A
.D ( i_fir_c3 ), // input wire [15 : 0] D
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.Q ( r_fir_c3_d14 ) // output wire [15 : 0] Q
);
// always @(posedge i_sys_clk)
// begin
// r_fir_c1_d1 <= i_fir_c1 ;
// r_fir_c1_d2 <= r_fir_c1_d1;
// r_fir_c1_d3 <= r_fir_c1_d2;
// r_fir_c1_d4 <= r_fir_c1_d3;
// end
//-----------c0
mult_gen_16_16 mult_gen_c0_inst (
.CLK( i_sys_clk ), // input wire CLK
.A ( i_uk ), // input wire [15 : 0] A
.B ( i_fir_c0 ), // input wire [15 : 0] B
.P ( w_mult_P_c0 ) // output wire [31 : 0] P
);
c_addsub_16_16 c_addsub_16_16_c0 (
.A ( w_mult_P_c0[29:14] ), // input wire [15 : 0] A
.B ( r_fir_c1_d4 ), // input wire [15 : 0] B
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.S ( r_add_y1 ) // output wire [16 : 0] S
);
//----------c1
mult_gen_16_16 mult_gen_c1_inst (
.CLK( i_sys_clk ), // input wire CLK
.A ( r_uk_d5 ), // input wire [15 : 0] A
.B ( r_add_y1[15:0] ), // input wire [15 : 0] B
.P ( w_mult_P_c1 ) // output wire [31 : 0] P
);
c_addsub_16_16 c_addsub_16_16_c1 (
.A ( w_mult_P_c1[29:14] ), // input wire [15 : 0] A
.B ( r_fir_c2_d9 ), // input wire [15 : 0] B
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.S ( r_add_y2 ) // output wire [16 : 0] S
);
mult_gen_16_16 mult_gen_c2_inst (
.CLK( i_sys_clk ), // input wire CLK
.A ( r_uk_d10 ), // input wire [15 : 0] A
.B ( r_add_y2[15:0] ), // input wire [15 : 0] B
.P ( w_mult_P_c2 ) // output wire [31 : 0] P
);
c_addsub_16_16 c_addsub_16_16_c2 (
.A ( w_mult_P_c2[29:14] ), // input wire [15 : 0] A
.B ( r_fir_c3_d14 ), // input wire [15 : 0] B
.CLK ( i_sys_clk ), // input wire CLK
.CE ( 1'b1 ), // input wire CE
.S ( r_add_y3 ) // output wire [16 : 0] S
);
assign o_mult_parallel = r_add_y3[16:1];
endmodule
相关阅读
发表评论