本人FPGA小白,只关注FPGA具体功能实现。如以下描述有误,望评论区指正!以下内容,纯手打,严禁未经过同意擅自转载,谢谢!
1、50%信道重叠的数字信道化高效结构
理想情况下,各信道的输出应该为:
经过推导,可得:
为了实现50%的信道重叠,故将正常结构下的D倍抽取更改为D/2倍抽取,且多项滤波结构的各信道滤波器系数需要进行2倍插值(插0)。
原型低通滤波器的通带截止频率Wk满足:
Wk = 2pi/D
2、matlab实现
%% -- 实现50%重叠的数字信道化
%% -- yk(m) = IDFT[Sk(m).hk(m)].(-1)^(km)
%% 系统参数
close all;
clear;
clc;
load orig_lpf_2.mat;
lpf = orig_lpf_2;
% 信道化前的系统参数
fs = 100e6;
N = 8192;
n_index = (0:N-1);
t = N/fs;
t_index = (0:1/fs:t-1/fs);%时间间隔
f_index = (0:fs/N:fs-fs/N);
f_shfit_index = (-fs/2:fs/N:fs/2-fs/N);
% 信道化后的系统参数
D = 32; % 信道数
fs_D = fs/D;
N_D = N/D;
n_index_D = (0:N_D-1);
t_D = N_D/fs_D;
t_index_D = (0:1/fs_D:t_D-1/fs_D);%时间间隔
f_index_D = (0:fs_D/N_D:fs_D-fs_D/N_D);
f_shfit_index_D = (-fs_D/2:fs_D/N_D:fs_D/2-fs_D/N_D);
win_D = hann(N_D);
%% 循环
% for fre = -50:0.5:50
%% 信号产生
fre = -40;
f = fre * 1e6;
sig = exp(1j*2*pi*f*t_index);% 32767*
% % sig = linspace(1,N,N);
sig_hex = sig * 32767;
fid = fopen('SampleData_I.dat','w');
fwrite(fid,real(sig_hex),'short');
fid = fopen('SampleData_Q.dat','w');
fwrite(fid,imag(sig_hex),'short');
fclose(fid);
% return;
%% 信号串并转换 (D/2倍抽取,多相结构)
if mod(length(lpf),D) ~= 0
disp("The LPF_coeff number is not a multiple of D");
return;
end
s_m_1 = reshape(sig,[D/2,length(sig)/(D/2)]);% D/2倍抽取
s_m = zeros(D/2,N/(D/2)); % 创建D行、N/D列的空矩阵
for i = 1:D/2
% s_m(i,:) = s_m_1(i,:);
s_m(i,:) = s_m_1(D/2-i+1,:);
end
s_m_dly = [zeros(D/2,1),s_m(:,1:end-1)];
h_m = reshape(lpf,[D,length(lpf)/D]);
h_m_zeros = zeros(size(h_m));
h_interp = reshape([h_m;h_m_zeros],[D,length(h_m)/2]);
sig_poly = [s_m;s_m_dly]; % D/2倍抽取
%% sh(m) = S(m) * h(m)
sh_m = zeros(D,N/(D/2)); % 创建D行、N/D列的空矩阵
for i=1:D
temp = conv(sig_poly(i,:),h_interp(i,:));
sh_m(i,:) = temp(1:N/(D/2));
end
%% FFT
y_m = zeros(D,N/D); % 创建D行、N/D列的空矩阵
for i=1:N/D
% y_m(:,i) = fft(sh_m(:,i));
y_m(:,i) = D.*ifft(sh_m(:,i));
end
%% y_out = y_m X (-1)^(km)
km = -ones(D,N/D);
for i = 0:D-1
for j = 0:length(km)-1
km(i+1,j+1) = power(-1,i*j);
end
end
y_out = y_m .* km;
y_out_w = y_out .* win_D'; % 加窗
y_out_fft = zeros(D,N/D); % 创建D行、N/D列的空矩阵
for i = 1:D
y_out_fft(i,:) = db(fftshift(abs(fft(y_out_w(i,:))))) ;
subplot(D/8,8,i);
plot(f_shfit_index_D,y_out_fft(i,:));
title(['Fre = ',num2str(fre),'MHz']);
xlabel(['信道 ',num2str(i-1)]);
axis([0-fs_D/2 fs_D/2-fs_D/N_D,-100,60]);
end
pause(0.5);
% end
32信道,采样率为100MHz,输入信号频率为-40MHz,matlab仿真结果如下,信号处于第19和20信号之间。
3、FPGA实现
FPGA中实现的结果如图所示,信号也处于第19、20信道之间。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/12/11 14:09:36
// Design Name:
// Module Name: DigitalChannelization_Top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module DigitalChannelization_Top #(
parameter CHANNEL = 32
)(
input clock,
input rst,
input [16*2-1:0] SampleData_IQ,
output reg [32*CHANNEL-1:0] SampleData_IQ_Channel,
output reg SampleDataValid_IQ_Channel
);
localparam ORIGIN_LPF_ORDER = 256;
//######## 输入数据D/2倍抽取
reg [15:0] cntr;
always @(posedge clock) begin
if(rst) begin
cntr <= 'b0;
end
else begin
if(cntr == CHANNEL/2-1) begin
cntr <= 'b0;
end
else begin
cntr <= cntr + 1'b1;
end
end
end
// reg [32*CHANNEL-1:0] SampleData_IQ_S2P; // 串并转换
reg [16*CHANNEL-1:0] SampleData_I_S2P; // 串并转换
reg [16*CHANNEL-1:0] SampleData_Q_S2P; // 串并转换
always @(posedge clock) begin
if(rst) begin
// SampleData_IQ_S2P <= 'b0;
SampleData_I_S2P <= 'b0;
SampleData_Q_S2P <= 'b0;
end
else begin
// SampleData_IQ_S2P <= SampleData_IQ_S2P << 32 | SampleData_IQ; // << 8
SampleData_I_S2P <= SampleData_I_S2P << 16 | SampleData_IQ[0*16+:16]; // I
SampleData_Q_S2P <= SampleData_Q_S2P << 16 | SampleData_IQ[1*16+:16]; // Q
end
end
reg [16*CHANNEL-1:0] SampleData_I_Parallel; // CHANNEL/2 抽取
reg [16*CHANNEL-1:0] SampleData_Q_Parallel; // CHANNEL/2 抽取
reg SampleData_Parallel_vld;
always @(posedge clock) begin
if(rst) begin
SampleData_I_Parallel <= 'b0;
SampleData_Q_Parallel <= 'b0;
SampleData_Parallel_vld <= 1'b0;
end
else begin
if(cntr == CHANNEL/2-1) begin
SampleData_I_Parallel <= SampleData_I_S2P;
SampleData_Q_Parallel <= SampleData_Q_S2P;
SampleData_Parallel_vld <= 1'b1;
end
else begin
SampleData_I_Parallel <= SampleData_I_Parallel;
SampleData_Q_Parallel <= SampleData_Q_Parallel;
SampleData_Parallel_vld <= 1'b0;
end
end
end
//######## 原型低通滤波器系数D倍抽取
wire [16*ORIGIN_LPF_ORDER-1:0] lpf_coeff;
Origin_LPF_Coeff #(
.LPF_ORDER ( ORIGIN_LPF_ORDER ),
.CHANNEL ( CHANNEL ),
.COE_FILE_PATH ( "../Origin_LPFCoeff.mem"))
Origin_LPF_Coeff (
.clock ( clock ),
.rst ( rst ),
.lpf_coeff ( lpf_coeff )
);
reg [16*ORIGIN_LPF_ORDER/CHANNEL-1:0] lpf_coeff_Channel [CHANNEL-1:0];
integer i;
always @(posedge clock) begin
if(rst) begin
for(i=0; i<CHANNEL; i=i+1) begin
lpf_coeff_Channel[i] <= 'b0;
end
end
else begin
for(i=0; i<CHANNEL; i=i+1) begin
lpf_coeff_Channel[i] <= lpf_coeff[(16*ORIGIN_LPF_ORDER/CHANNEL*i) +: (16*ORIGIN_LPF_ORDER/CHANNEL)];
end
end
end
//######## Convolver
genvar gen_i;
wire [15:0] conv_data_I [CHANNEL-1:0];
wire [15:0] conv_data_Q [CHANNEL-1:0];
wire [CHANNEL-1:0] conv_valid_I;
wire [CHANNEL-1:0] conv_valid_Q;
generate begin : Convolver
for(gen_i=0; gen_i<CHANNEL; gen_i=gen_i+1) begin : Instance
Convolver #(
.COE_NUM ( ORIGIN_LPF_ORDER/CHANNEL ))
Convolver_I (
.clock ( clock ),
.rst ( rst ),
.din ( SampleData_I_Parallel[gen_i*16+:16] ),
.dinValid ( SampleData_Parallel_vld ),
.coeff ( lpf_coeff_Channel[gen_i] ),
.dout ( conv_data_I [gen_i] ),
.doutValid ( conv_valid_I[gen_i] )
);
Convolver #(
.COE_NUM ( ORIGIN_LPF_ORDER/CHANNEL ))
Convolver_Q (
.clock ( clock ),
.rst ( rst ),
.din ( SampleData_Q_Parallel[gen_i*16+:16] ),
.dinValid ( SampleData_Parallel_vld ),
.coeff ( lpf_coeff_Channel[gen_i] ),
.dout ( conv_data_Q [gen_i] ),
.doutValid ( conv_valid_Q[gen_i] )
);
end
end
endgenerate
//######## IFFT
reg [32*CHANNEL-1:0] data_r;
reg dataValid_r;
//#### 将多相滤波后的并行数据倒序(FFT模块与多相滤波模块定义的并行数据顺序相反)
always @(posedge clock) begin
if(rst) begin
data_r <= 'b0;
dataValid_r <= 1'b0;
end
else begin
for(i=0; i<CHANNEL; i=i+1) begin
data_r[(32*i+16*0) +: 16] <= conv_data_I[i];
data_r[(32*i+16*1) +: 16] <= conv_data_Q[i];
// data_r[(32*(CHANNEL-i-1)+16*0) +: 16] <= conv_data_I[i]; // 倒序
// data_r[(32*(CHANNEL-i-1)+16*1) +: 16] <= conv_data_Q[i]; // 倒序
end
dataValid_r <= (&conv_valid_I) & (&conv_valid_Q);
end
end
wire [32*CHANNEL-1:0] ifft_dout;
wire ifft_doutValid;
fft_ifft_32_parallel ifft_32 (
.clock ( clock ),
.rst ( rst ),
.fft_sel ( 1'b1 ), // 0:FFT 1:IFFT
.din ( data_r ),
.dinValid ( dataValid_r ),
.dout ( ifft_dout ),
.doutValid ( ifft_doutValid)
);
//#### 将FFT后的并行数据倒序(FFT模块与多相滤波模块定义的并行数据顺序相反)
reg [32*CHANNEL-1:0] ifft_data;
reg ifft_dataValid;
always @(posedge clock) begin
if(rst) begin
ifft_data <= 'b0;
ifft_dataValid <= 1'b0;
end
else begin
for(i=0; i<CHANNEL; i=i+1) begin
ifft_data[32*i +: 32] <= ifft_dout[(32*i) +: 32];
// ifft_data[32*(CHANNEL-i-1) +: 32] <= ifft_dout[(32*i) +: 32]; // 倒序
end
ifft_dataValid <= ifft_doutValid;
end
end
//######## (-1)^(km)
reg flag; // (-1)^(km)
always @(posedge clock) begin
if(rst) begin
flag <= 1'b0;
end
else begin
if(ifft_dataValid) begin
flag <= ~flag;
end
else begin
flag <= flag;
end
end
end
always @(posedge clock) begin
if(rst) begin
SampleData_IQ_Channel <= 'b0;
SampleDataValid_IQ_Channel <= 1'b0;
end
else begin
if(ifft_dataValid) begin
for(i=0; i<CHANNEL; i=i+1) begin
if(flag) begin
if(i%2) begin // 奇数项
SampleData_IQ_Channel[(32*i+16*0) +: 16] <= -ifft_data[(32*i+16*0) +: 16];
SampleData_IQ_Channel[(32*i+16*1) +: 16] <= -ifft_data[(32*i+16*1) +: 16];
end
else begin
SampleData_IQ_Channel[(32*i+16*0) +: 16] <= ifft_data[(32*i+16*0) +: 16];
SampleData_IQ_Channel[(32*i+16*1) +: 16] <= ifft_data[(32*i+16*1) +: 16];
end
end
else begin
SampleData_IQ_Channel[(32*i+16*0) +: 16] <= ifft_data[(32*i+16*0) +: 16];
SampleData_IQ_Channel[(32*i+16*1) +: 16] <= ifft_data[(32*i+16*1) +: 16];
end
end
SampleDataValid_IQ_Channel <= 1'b1;
end
else begin
SampleData_IQ_Channel <= SampleData_IQ_Channel;
SampleDataValid_IQ_Channel <= 1'b0;
end
end
end
// #### Debug
wire [15:0] SampleData_CH_I [CHANNEL-1:0];
wire [15:0] SampleData_CH_Q [CHANNEL-1:0];
wire SampleDataValid_CH;
genvar j;
generate begin
for(j=0; j<CHANNEL; j=j+1) begin
assign SampleData_CH_I[j] = SampleData_IQ_Channel[(32*j+16*0)+:16];
assign SampleData_CH_Q[j] = SampleData_IQ_Channel[(32*j+16*1)+:16];
end
end
endgenerate
assign SampleDataValid_CH = SampleDataValid_IQ_Channel;
endmodule