说明:本文为学习笔记,错误不可避免,全当交流。
以单频点信号为例,说明三阶拉格朗日插值的实现方法。
实现结构
假设输入序列为: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文章来源地址https://www.toymoban.com/news/detail-819750.html
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];文章来源:https://www.toymoban.com/news/detail-819750.html
endmodule
到了这里,关于Farrow结构的三阶拉格朗日插值matlab及FPGA实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!