Conception de filtre FIR série
Description de la conception
Les paramètres de conception sont inchangés et cohérents avec les paramètres du filtre FIR parallèle. Autrement dit, pour les signaux d'entrée sinusoïdaux mixtes ayant des fréquences de 7.5 MHz et 250 KHz, après passage dans le filtre FIR, le signal haute fréquence à 7.5 MHz est filtré, ne laissant que le signal à 250 KHz.
输入频率: 7.5MHz 和 250KHz 采样频率: 50MHz 阻带: 1MHz-6MHz 阶数: 15 (N=15)
Dans la conception série, les 16 échantillons de données retardés sont traités séquentiellement par des opérations de multiplication et d'addition en répartition temporelle sur 16 cycles d'horloge, puis la valeur filtrée est émise sous la commande de l'horloge. Compte tenu de la symétrie des coefficients du filtre FIR, la période de calcul d'une valeur de sortie filtrée peut être réduite à 8 cycles. Dans la conception série, une seule opération de multiplication est effectuée par cycle, donc un seul multiplieur est nécessaire dans la conception. À ce stade, les données doivent être entrées de manière valide une fois tous les 8 cycles d'horloge. Cependant, pour garantir l'exactitude de la fréquence du signal de sortie, l'horloge de travail doit être 8 fois la fréquence d'échantillonnage, c'est-à-dire 400 MHz. L'avantage de cette méthode est une faible consommation de ressources, mais elle nécessite une fréquence de travail élevée et les données ne peuvent pas être émises en continu.
Conception série
Pour le code du module multiplieur utilisé dans la conception, reportez-vous au multiplieur de la conception pipeline précédente.
Pour une simulation pratique et rapide, le signe de multiplication peut également être utilisé directement*pour réaliser l'opération de multiplication. Une définition de macro SAFE_DESIGN est ajoutée dans la conception pour sélectionner le multiplieur à utiliser.
Les coefficients du filtre FIR peuvent être générés par MATLAB ; voir l'annexe pour plus de détails.
Exemple
>> Description : étude FIR avec technique série
>> V190403 : Fs:50Mhz, fstop:1-6Mhz, order:16, sys clk:400MHz
***********************************************************/
`define SAFE_DESIGN
module fir_serial_low(
input rstn,
input clk, // Horloge de travail du système, 400MHz
input en , // Signal de validité des données d'entrée
input [11:0] xin, // Données de signal d'entrée à fréquences mixtes
output valid, // Signal de validation des données de sortie
output [28:0] yout // Données de sortie
);
//retard de validation des données d'entrée
reg [11:0] en_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
en_r[11:0] <= 'b0 ;
end
else begin
en_r[11:0] <= {en_r[10:0], en} ;
end
end
//coefficient FIR
wire [11:0] coe[7:0] ;
assign coe[0] = 12'd11 ;
assign coe[1] = 12'd31 ;
assign coe[2] = 12'd63 ;
assign coe[3] = 12'd104 ;
assign coe[4] = 12'd152 ;
assign coe[5] = 12'd198 ;
assign coe[6] = 12'd235 ;
assign coe[7] = 12'd255 ;
//(1) Section de décalage des données d'entrée
reg [2:0] cnt ;
entier i, j ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
cnt <= 3'b0 ;
end
else if (en || cnt != 0) begin
cnt <= cnt + 1'b1 ; //comptage sur 8 cycles
end
end
reg [11:0] xin_reg[15:0];
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
for (i=0; i<16; i=i+1) begin
xin_reg[i] <= 12'b0;
end
end
else if (cnt == 3'd0 && en) begin //Lire les données valides une fois tous les 8 cycles
xin_reg[0] <= xin ;
for (j=0; j<15; j=j+1) begin
xin_reg[j+1] <= xin_reg[j] ; // Décalage de données
end
end
end
//(2) Les coefficients sont symétriques ; additionner la première et la dernière donnée des 16 registres à décalage
reg [11:0] add_a, add_b ;
reg [11:0] coe_s ;
wire [12:0] add_s ;
wire [2:0] xin_index = cnt>=1 ? cnt-1 : 3'd7 ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
add_a <= 13'b0 ;
add_b <= 13'b0 ;
coe_s <= 12'b0 ;
end
else if (en_r[xin_index]) begin //depuis en_r[1]
add_a <= xin_reg[xin_index] ;
add_b <= xin_reg[15-xin_index] ;
coe_s <= coe[xin_index] ;
end
end
assign add_s = {add_a} + {add_b} ;
//(3) Opération de multiplication, en utilisant un seul multiplicateur
reg [24:0] mout ;
`ifdef SAFE_DESIGN
wire en_mult ;
wire [3:0] index_mult = cnt>=2 ? cnt-1 : 4'd7 + cnt[0] ;
mult_man #(13, 12) u_mult_single //Instancier le multiplicateur pipeline auto-conçu
(.clk (clk),
.rstn (rstn),
.data_rdy (en_r[index_mult]), //Faites attention à la correspondance temporelle des données
.mult1 (add_s),
.mult2 (coe_s),
.res_rdy (en_mult),
.res (mout)
);
`else
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
mout <= 25'b0 ;
end
else if (|en_r[8:1]) begin
mout <= coe_s * add_s ; //Multiplication directe
end
end
wire en_mult = en_r[2];
`endif
//(4) Accumulation, 8 groupes de données de 25 bits -> 1 groupe de données de 29 bits
reg [28:0] sum ;
reg valid_r ;
//compteur d'activation de sortie mult
reg [4:0] cnt_acc_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
cnt_acc_r <= 'b0 ;
end
else if (cnt_acc_r == 5'd7) begin //Compter 8 cycles
cnt_acc_r <= 'b0 ;
end
else if (en_mult || cnt_acc_r != 0) begin //Tant que en est valide, le comptage continue
cnt_acc_r <= cnt_acc_r + 1'b1 ;
end
end
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
sum <= 29'd0 ;
valid_r <= 1'b0 ;
end
else if (cnt_acc_r == 5'd7) begin //Sortir la valeur filtrée au 8e cycle d'accumulation
sum <= sum + mout;
valid_r <= 1'b1 ;
end
else if (en_mult && cnt_acc_r == 0) begin //Initialisation
sum <= mout ;
valid_r <= 1'b0 ;
end
else if (cnt_acc_r != 0) begin //accumulation entre les cycles
sum <= sum + mout ;
valid_r <= 1'b0 ;
end
end
//Verrouiller les données de sortie valides sur le front d'horloge afin que le signal de sortie ne change pas trop fréquemment
reg [28:0] yout_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
yout_r <= 'b0 ;
end
else if (valid_r) begin
yout_r <= sum ;
end
end
assign yout = yout_r ;
//(5) Délai de validité des données de sortie ; autrement dit, écarter les 15 premières valeurs filtrées
reg [4:0] cnt_valid ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
cnt_valid <= 'b0 ;
end
else if (valid_r && cnt_valid != 5'd16) begin
cnt_valid <= cnt_valid + 1'b1 ;
end
end
assign valid = (cnt_valid == 5'd16) & valid_r ;
endmodule
testbench
Le banc de test est écrit comme suit. Sa fonction principale est de fournir en continu, sans interruption, les données du signal sinusoïdal mixte de 250KHz et 7.5MHz. Les données du signal mixte d'entrée peuvent également être générées par MATLAB ; voir l'annexe pour plus de détails.
Ici, la fréquence de travail est de 400MHz, mais les données d'entrée et le signal de validation des données d'entrée doivent tous deux être fournis à une fréquence de 50MHz.
Exemple
//entrée
reg clk ;
reg rst_n ;
reg en ;
reg [11:0] xin ;
//sortie
wire [28:0] yout ;
wire valid ;
parameter SIMU_CYCLE = 64'd1000 ;
parameter SIN_DATA_NUM = 200 ;
//=====================================
// Génération de l'horloge clk à 8*50MHz
localparam TCLK_HALF = (10_000 >>3);
initial begin
clk = 1'b0 ;
forever begin
# TCLK_HALF clk = ~clk ;
end
end
//============================
// réinitialiser et terminer
initial begin
rst_n = 1'b0 ;
# 30 rst_n = 1'b1 ;
# (TCLK_HALF * 2 * 8 * SIMU_CYCLE) ;
$finish ;
end
//=======================================
// lire les données cos dans le registre
reg [11:0] stimulus [0: SIN_DATA_NUM-1] ;
entier i ;
initial begin
$readmemh("../tb/cosx0p25m7p5m12bit.txt", stimulus) ;
en = 0 ;
i = 0 ;
xin = 0 ;
# 200 ;
forever begin
repeat(7) @(negedge clk) ; //Inactif pendant 7 cycles, fournir les données au 8e cycle
en = 1 ;
xin = stimulus[i] ;
@(negedge clk) ;
en = 0 ; //Le signal de validation des données d'entrée ne doit durer qu'un cycle
if (i == SIN_DATA_NUM-1) i = 0 ;
else i = i + 1 ;
end
end
fir_serial_low u_fir_serial (
.clk (clk),
.rstn (rst_n),
.en (en),
.xin (xin),
.valid (valid),
.yout (yout));
endmodule
Résultats de simulation
D'après les résultats de simulation de la figure ci-dessous, on peut voir que le signal après le filtre FIR ne contient qu'un seul signal basse fréquence (250KHz), et que le signal haute fréquence (7.5MHz) a été filtré. Pour obtenir une forme d'onde plus esthétique, les données filtrées après les 16 premiers échantillons sont prises comme sortie valide.

La forme d'onde agrandie localement est illustrée dans la figure ci-dessous. À ce moment, le signal de validation des données d'entrée en et le signal de validation des données de sortie valid sont des signaux impulsionnels de même période (50MHz), et ne sont pas valides en continu. Cependant, comme l'horloge de travail est de 400MHz, la sortie apparaîtra également comme un signal sinusoïdal d'une fréquence de 250KHz à une fréquence d'échantillonnage de 50MHz.

Annexe : Utilisation de MATLAB (identique à« Parallel FIR Filter Design »cohérent)
Générer les coefficients du filtre FIR
Ouvrez MATLAB, saisissez la commande dans la fenêtre de commande : fdatool.
La fenêtre suivante s'ouvrira alors. Configurez-la selon les paramètres du filtre FIR, comme indiqué ci-dessous.
La méthode d'implémentation FIR sélectionnée ici est la méthode des moindres carrés (Least-squares). Différentes méthodes d'implémentation produisent également des effets de filtrage différents.

Cliquez sur Fichier -> Exporter
Exportez les paramètres du filtre et stockez-les dans la variable coef, comme le montre la figure ci-dessous.

À ce moment, la variable coef doit être de type flottant. Multipliez-la par un certain facteur pour la mettre à l'échelle, puis prenez ses données approximatives en virgule fixe comme paramètres du filtre FIR dans la conception. Ici, le facteur d'échelle est 2048, et les résultats sont les suivants.

Générer le signal d'entrée mixte
Le code de référence pour générer le signal d'entrée mixte à l'aide de MATLAB est le suivant.
Le signal est une donnée en virgule fixe non signée d'une largeur de 12 bits, stockée dans le fichiercosx0p25m7p5m12bit.txt 。
Exemple
%=======================================================
% génération de données d'onde cos avec format hexadécimal txt
%=======================================================
fc = 0.25e6 ; %Fréquence centrale
fn = 7.5e6 ; %Fréquence du fouillis
Fs = 50e6 ; %Fréquence d'échantillonnage
T = 1/fc ; %Période du signal
Num = Fs * T ; %Nombre de points d'échantillonnage du signal par période
t = (0:Num-1)/Fs ; %Temps discret
cosx = cos(2*pi*fc*t) ; %Signal sinusoïdal de fréquence centrale
cosn = cos(2*pi*fn*t) ; %Signal de fouillis
cosy = mapminmax(cosx + cosn) ; %Amplitude étendue à (-1,1) plage
cosy_dig = floor((2^11-1) * cosy + 2^11) ; %Amplitude étendue à0~4095
fid = fopen('cosx0p25m7p5m12bit.txt', 'wt') ; %Écrire le fichier de données
fprintf(fid, '%x\n', cosy_dig) ;
fclose(fid) ;
%Forme d'onde dans le domaine temporel
figure(1);
subplot(121);plot(t,cosx);hold on ;
plot(t,cosn) ;
subplot(122);plot(t,cosy_dig) ;
%Forme d'onde dans le domaine fréquentiel
fft_cosy = fftshift(fft(cosy, Num)) ;
f_axis = (-Num/2 : Num/2 - 1) * (Fs/Num) ;
figure(5) ;
plot(f_axis, abs(fft_cosy)) ;
Téléchargement du code source
Téléchargement