Le filtre FIR (réponse impulsionnelle finie) est un filtre à réponse impulsionnelle unitaire de longueur finie, également appelé filtre non récursif.
Les filtres FIR ont des caractéristiques phase-fréquence linéaires strictes, et leur réponse unitaire est finie, donc ce sont des systèmes stables et ils sont largement utilisés dans les communications numériques, le traitement d'images et d'autres domaines.
Principe du filtre FIR
Le filtre FIR est un filtre à réponse impulsionnelle unitaire de longueur finie. La structure de forme directe est la suivante :

Le filtre FIR est essentiellement la convolution du signal d'entrée avec la fonction de réponse impulsionnelle unitaire, exprimée comme suit :

Le filtre FIR présente les caractéristiques suivantes :
- (1) La réponse est une séquence de longueur finie.
- (2) La fonction système converge pour |z| > 0, tous les pôles sont en z=0, et il s'agit d'un système causal.
- (3) Structurellement, il est non récursif, sans rétroaction de la sortie vers l'entrée.
- (4) La réponse de phase du signal d'entrée est linéaire car les coefficients de la fonction de réponse h(n) sont symétriques.
- (5) Les différences de phase relatives entre les composantes fréquentielles du signal d'entrée sont également fixes.
- (6) La convolution dans le domaine temporel équivaut à une multiplication dans le domaine fréquentiel, donc cette convolution est équivalente au facteur de gain pour le filtrage de chaque composante fréquentielle du spectre. Certaines composantes fréquentielles sont conservées, tandis que d'autres sont atténuées, ce qui permet d'obtenir l'effet de filtrage.
Conception de filtre FIR parallèle
Description de la conception
L'entrée est un signal sinusoïdal mixte avec des fréquences de 7.5 MHz et 250 KHz. Après passage à travers le filtre FIR, le signal haute fréquence de 7.5 MHz est supprimé, et seul le signal de 250 KHz est conservé. Les paramètres de conception sont les suivants :
输入频率: 7.5MHz 和 250KHz 采样频率: 50MHz 阻带: 1MHz ~ 6MHz 阶数: 15(N-1=15)
D'après la structure du filtre FIR, lorsque l'ordre est de 15, l'implémentation nécessite 16 multiplicateurs, 15 additionneurs et 15 ensembles de registres à retard. Pour stabiliser les données du premier temps, un ensemble supplémentaire de registres à retard peut être utilisé, soit un total de 16 ensembles de registres à retard. En raison de la symétrie des coefficients du filtre FIR, le nombre de multiplicateurs peut être réduit de moitié, avec un total de 8 multiplicateurs.
La conception parallèle consiste à effectuer la multiplication et l'addition sur les 16 éléments de données retardés simultanément dans un cycle d'horloge, puis à sortir la valeur filtrée sous la commande de l'horloge. L'avantage de cette méthode est un court délai de filtrage, mais elle présente des contraintes de timing relativement élevées.
Conception parallèle
Pour le code du module multiplicateur utilisé dans cette conception, reportez-vous au multiplicateur de la conception en pipeline précédente.
Pour faciliter une simulation rapide, vous pouvez également utiliser directement le signe de multiplication*pour effectuer l'opération de multiplication. Une définition de macro SAFE_DESIGN est ajoutée dans la conception pour sélectionner le multiplicateur à utiliser.
Les coefficients du filtre FIR peuvent être générés par matlab ; voir l'annexe pour les détails.
Exemple
>> V201001 : Fs:50Mhz, fstop:1Mhz-6Mhz, ordre: 15
************************************************************/
`define SAFE_DESIGN
module fir_guide (
input rstn, // Réinitialisation, actif à l'état bas
input clk, // Fréquence de fonctionnement, c'est-à-dire fréquence d'échantillonnage
input en, // Signal de validité des données d'entrée
input [11:0] xin, // Données du signal d'entrée à fréquences mélangées
output valid, // Signal de validation des données de sortie
output [28:0] yout // Données de sortie, signal basse fréquence, soit 250KHz
);
//retard d'activation des données
reg [3:0] en_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
en_r[3:0] <= 'b0 ;
end
else begin
en_r[3:0] <= {en_r[2:0], en} ;
end
end
//(1) 16 ensembles de registres à décalage
reg [11:0] xin_reg[15:0];
reg [3:0] i, j ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
for (i=0; i<15; i=i+1) begin
xin_reg[i] <= 12'b0;
end
end
else if (en) begin
xin_reg[0] <= xin ;
for (j=0; j<15; j=j+1) begin
xin_reg[j+1] <= xin_reg[j] ; // Opération de décalage périodique
end
end
end
//Seuls 8 multiplicateurs sont nécessaires en raison de la symétrie des coefficients du filtre FIR
//(2) Les coefficients sont symétriques ; additionnez les première et dernière données des 16 registres à décalage
reg [12:0] add_reg[7:0];
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
for (i=0; i<8; i=i+1) begin
add_reg[i] <= 13'd0 ;
end
end
else if (en_r[0]) begin
for (i=0; i<8; i=i+1) begin
add_reg[i] <= xin_reg[i] + xin_reg[15-i] ;
end
end
end
//(3) 8 multiplicateurs
// Coefficients du filtre, déjà amplifiés par un certain facteur
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 ;
reg [24:0] mout[7:0];
`ifdef SAFE_DESIGN
// Multiplicateur pipeline
wire [7:0] valid_mult ;
genvar k ;
generate
for (k=0; k<8; k=k+1) begin
mult_man #(13, 12)
u_mult_paral (
.clk (clk),
.rstn (rstn),
.data_rdy (en_r[1]),
.mult1 (add_reg[k]),
.mult2 (coe[k]),
.res_rdy (valid_mult[k]), // Toutes les validations de sortie sont exactement identiques
.res (mout[k])
);
end
endgenerate
wire valid_mult7 = valid_mult[7] ;
`else
// Si les contraintes de timing ne sont pas strictes, vous pouvez directement utiliser le signe de multiplication
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
for (i=0 ; i<8; i=i+1) begin
mout[i] <= 25'b0 ;
end
end
else if (en_r[1]) begin
for (i=0 ; i<8; i=i+1) begin
mout[i] <= coe[i] * add_reg[i] ;
end
end
end
wire valid_mult7 = en_r[2];
`endif
//(4) Accumulation, 8 groupes de données de 25 bits -> 1 groupe de données de 29 bits
// Délai de validité des données
reg [3:0] valid_mult_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
valid_mult_r[3:0] <= 'b0 ;
end
else begin
valid_mult_r[3:0] <= {valid_mult_r[2:0], valid_mult7} ;
end
end
`ifdef SAFE_DESIGN
// Lors de l'addition, pipeline sur plusieurs cycles pour optimiser le timing
reg [28:0] sum1 ;
reg [28:0] sum2 ;
reg [28:0] yout_t ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
sum1 <= 29'd0 ;
sum2 <= 29'd0 ;
yout_t <= 29'd0 ;
end
else if(valid_mult7) begin
sum1 <= mout[0] + mout[1] + mout[2] + mout[3] ;
sum2 <= mout[4] + mout[5] + mout[6] + mout[7] ;
yout_t <= sum1 + sum2 ;
end
end
`else
// Calculer le résultat d'accumulation en une seule étape, mais en pratique le timing est très dangereux
reg signed [28:0] sum ;
reg signed [28:0] yout_t ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
sum <= 29'd0 ;
yout_t <= 29'd0 ;
end
else if (valid_mult7) begin
sum <= mout[0] + mout[1] + mout[2] + mout[3] + mout[4] + mout[5] + mout[6] + mout[7];
yout_t <= sum ;
end
end
`endif
assign yout = yout_t ;
assign valid = valid_mult_r[0];
endmodule
testbench
Le banc de test est écrit comme suit. Sa fonction principale est d'injecter en continu les données de signal mixte sinusoïdal de 250KHz et 7.5MHz sans interruption. Les données de signal mixte d'entrée peuvent également être générées par matlab ; voir l'annexe pour plus de détails.
Exemple
module test ;
//entrée
reg clk ;
reg rst_n ;
reg en ;
reg [11:0] xin ;
//sortie
wire valid ;
wire [28:0] yout ;
parameter SIMU_CYCLE = 64'd2000 ; // fréquence d'échantillonnage de 50MHz
parameter SIN_DATA_NUM = 200 ; // période de simulation
//=====================================
// génération de clk à 50MHz
localparam TCLK_HALF = 10_000;
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 * SIMU_CYCLE) ;
$finish ;
end
//=======================================
// lire les données de signal dans le registre
reg [11:0] stimulus [0: SIN_DATA_NUM-1] ;
entier i ;
initial begin
$readmemh("../tb/cosx0p25m7p5m12bit.txt", stimulus) ;
i = 0 ;
en = 0 ;
xin = 0 ;
# 200 ;
forever begin
@(negedge clk) begin
en = 1'b1 ;
xin = stimulus[i] ;
if (i == SIN_DATA_NUM-1) begin // Contrôle d'alimentation périodique des données
i = 0 ;
end
else begin
i = i + 1 ;
end
end
end
end
fir_guide u_fir_paral (
.xin (xin),
.clk (clk),
.en (en),
.rstn (rst_n),
.valid (valid),
.yout (yout));
endmodule
Résultats de simulation
D'après les résultats de simulation de la figure ci-dessous, le signal après le filtre FIR ne contient qu'un seul signal basse fréquence (250KHz), et le signal haute fréquence (7.5MHz) a été filtré. De plus, la forme d'onde de sortie est continue et peut être délivrée en continu.
Cependant, comme le montre le cercle rouge, le début de la forme d'onde est irrégulier. Zoomez sur cette partie.

Après avoir zoomé sur le début de la forme d'onde, comme le montre la figure ci-dessous, on peut voir que la période de la forme d'onde irrégulière, c'est-à-dire l'intervalle de temps entre les deux lignes verticales, est de 16 cycles d'horloge.
Comme les données sont entrées en série et que 16 ensembles de registres de retard sont utilisés dans la conception, le premier point normal après filtrage doit être retardé de 16 cycles d'horloge par rapport au premier moment de sortie des données filtrées. Autrement dit, le signal valid de sortie de données doit être retardé de 16 cycles d'horloge supplémentaires, ce qui rendra la forme d'onde de sortie plus parfaite.

Annexe : Utilisation de matlab
Génération des coefficients du filtre FIR
Ouvrez matlab, puis saisissez la commande dans la fenêtre de commande : fdatool.
Ensuite, la fenêtre suivante s'ouvrira ; définissez les paramètres en fonction du filtre FIR.
La méthode d'implémentation FIR sélectionnée ici est celle des moindres carrés (Least-squares). Différentes méthodes d'implémentation produisent différents effets de filtrage.

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 stade, la variable coef doit contenir des données à virgule flottante. Multipliez-la par un certain facteur pour l'amplifier, puis prenez ses données approximatives en virgule fixe comme paramètres du filtre FIR dans la conception. Ici, le facteur d'amplification est 2048, et les résultats sont les suivants.

Génération du 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 constitué de données non signées en virgule fixe d'une largeur de 12 bits, stockées dans un 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 dans une 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 à la plage (-1,1)
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 temporelle
figure(1);
subplot(121);plot(t,cosx);hold on ;
plot(t,cosn) ;
subplot(122);plot(t,cosy_dig) ;
%Forme d'onde fréquentielle
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