《FPGA数字信号处理》基于FPGA数字信道化设计

本人FPGA小白,只关注FPGA具体功能实现。如以下描述有误,望评论区指正!以下内容,纯手打,严禁未经过同意擅自转载,谢谢!

1、50%信道重叠的数字信道化高效结构

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 仿真结果
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

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calmer_qaq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值