Ich möchte mehrere IIR-Filter auf einem FPGA mit VHDL implementieren. Der Filter ist für Audio. Ich beginne mit der Implementierung eines einzelnen Filters mit der folgenden Übertragungsfunktion:
Diese Übertragungsfunktion soll folgenden Frequenzgang haben:
Und sollte mit folgender Differenzengleichung realisierbar sein:
Ich habe versucht, den Filter mit den beiden folgenden Codeteilen zu implementieren:
library ieee;
use ieee.std_logic_1164.all;
use IEEE.numeric_std.all;
entity FILTER is
port (
GPIO : inout std_logic_vector(35 downto 0); --I/O
CLK_50 : inout std_logic; --50 MHz clock
CLK : in std_logic; --3.072 MHz clock
CHANNEL : in std_logic; --Channel select 48 kHz
data_left_in : in std_logic_vector(15 downto 0);
data_right_in : in std_logic_vector(15 downto 0);
data_left_out : out std_logic_vector(15 downto 0);
data_right_out : out std_logic_vector(15 downto 0)
);
end FILTER;
architecture behave of FILTER is
signal input_left : signed (15 downto 0);
signal input_right : signed (15 downto 0);
signal output_left : signed (15 downto 0);
signal output_right : signed (15 downto 0);
signal i_0_left : signed (15 downto 0);
signal i_0_right : signed (15 downto 0);
COMPONENT filter_class
port (
GPIO : inout std_logic_vector(35 downto 0); --I/O
CLK_50 : inout std_logic; --50 MHz clock
CLK : in std_logic; --Channel select 48 kHz
sample : in signed (15 downto 0); --filter input
sample_filtered : inout signed (15 downto 0); --filter output
b00 : in integer range -32768 to 32767; --filter coefficients
b01 : in integer range -32768 to 32767;
b02 : in integer range -32768 to 32767;
a01 : in integer range -32768 to 32767;
a02 : in integer range -32768 to 32767;
scaling : in integer range 0 to 16; --scaling for fixed point
gain : in integer range -32768 to 32767;
gain_scaling : in integer range 0 to 15
);
END COMPONENT;
begin
Filt_0_r : filter_class PORT MAP (GPIO(35 downto 0), CLK_50, NOT CHANNEL, input_right, i_0_right , 16384, 0, 0, 0, 0, 14, 1, 0); --no filtering
Filt_0_l : filter_class PORT MAP (GPIO(35 downto 0), CLK_50, CHANNEL, input_left, i_0_left, 16384, 0, -16384, -32113, 16081, 14, 1, 0); --filter with tf H1(z)
process (CHANNEL) --send output to DAC
begin
if RISING_EDGE(CHANNEL) then
input_left <= signed(data_left_in);
data_left_out <= std_logic_vector(i_0_left);
end if;
if FALLING_EDGE(CHANNEL) then
input_right <= signed(data_right_in);
data_right_out <= std_logic_vector(i_0_right);
end if;
end process;
end behave;
Und
library ieee;
use ieee.std_logic_1164.all;
use IEEE.numeric_std.all;
entity filter_class is
port (
GPIO : inout std_logic_vector(35 downto 0); --I/O
CLK_50 : inout std_logic; --50 MHz clock
CLK : in std_logic; --Channel select 48 kHz
sample : in signed (15 downto 0); --filter input
sample_filtered : inout signed (15 downto 0); --filter output
b00 : in integer range -32768 to 32767; --filter coefficients
b01 : in integer range -32768 to 32767;
b02 : in integer range -32768 to 32767;
a01 : in integer range -32768 to 32767;
a02 : in integer range -32768 to 32767;
scaling : in integer range 0 to 16; --scaling for fixed point
gain : in integer range -32768 to 32767;
gain_scaling : in integer range 0 to 15
);
end filter_class;
architecture behave of filter_class is
TYPE multipliers IS ARRAY (NATURAL RANGE <>) OF SIGNED (17 DOWNTO 0);
TYPE result IS ARRAY (NATURAL RANGE <>) OF SIGNED (35 DOWNTO 0);
signal y00 : signed (15 downto 0);
signal sum_1 : signed (37 downto 0);
signal samp : multipliers(0 to 5);
signal coef : multipliers(0 to 5);
signal resu : result(0 to 5);
signal channel_state : std_logic;
begin
process (CLK_50) --calculate filter
variable cnt : integer := 0;
variable flag : std_logic := '0';
begin
if RISING_EDGE(CLK_50) then
channel_state <= CLK;
if channel_state = '0' AND CLK = '1' then --if new sample
flag := '1';
elsif flag = '1' then --calculate
cnt := cnt + 1;
if cnt = 4 then --save coefficients in array
coef(0) <= to_signed(b00,18);
coef(1) <= to_signed(b01,18);
coef(2) <= to_signed(b02,18);
coef(3) <= to_signed(-a01,18);
coef(4) <= to_signed(-a02,18);
coef(5) <= to_signed(gain,18);
samp(5) <= resize(y00, 18);
end if;
if cnt = 29 then --reset count if all done
cnt := 0;
flag := '0';
elsif cnt > 5 AND cnt < 12 then
resu(cnt - 6) <= coef(cnt - 6) * samp(cnt - 6); --multiply coefficients and sample, and gain
elsif cnt = 12 then
sum_1 <= to_signed(0, 38); --reset filter sum
elsif cnt > 12 then
sum_1 <= sum_1 + resu(cnt - 8); --calculate sum
end if;
end if;
end if;
end process;
process (CLK)
variable y00_temp_1 : signed (37 downto 0);
variable y00_temp_2 : signed (37 downto 0);
variable sample_filtered_temp_1 : signed (35 downto 0);
begin
if RISING_EDGE(CLK) then
--delay line
samp(2) <= samp(1);
samp(1) <= samp(0);
samp(0) <= resize(sample, 18);
samp(4) <= samp(3);
samp(3) <= resize(y00, 18);
y00_temp_1 := sum_1; --set output
y00_temp_2 := shift_right(y00_temp_1, scaling); --divide by 2^14 for scaling
y00 <= y00_temp_2 (15 downto 0); --filter output
sample_filtered_temp_1 := shift_right(resu(5), gain_scaling); filter gain scaling
sample_filtered <= sample_filtered_temp_1 (15 downto 0); --filter output * gain
end if;
end process;
end behave;
Dies ist mein erster VHDL-Code, und es können viele Fehler auftreten.
Mit diesem Code funktioniert der Filter nicht.
Der rechte Kanalfilter funktioniert (nur Passthrough) und gibt 1/1 Ausgabe.
Der linke Filter funktioniert nicht und gibt unabhängig vom Eingangssignal nur Rauschen aus. Bei einem Inout-Signal von 1 kHz und 1 V Amplitude ist das Ausgangssignal zu sehen:
Die rote Wellenform ist der Ausgang des rechten Filters, die blaue ist der linke Filter.
Bei Verwendung eines niedrigeren Skalierungsfaktors, z. 2^15 oder 2^16, sieht die Ausgabe anders aus. Bei 2 ^ 16 ist die Ausgabe 0. Aus diesem Grund vermute ich, dass das Problem eine Art falsches Abschneiden des Signals ist.
Hat jemand eine Idee, was ich mit dem Filter falsch mache?
Ich verfolge nicht alles, was Sie tun, aber dieser Code sieht verdächtig aus:
if cnt = 29 then --reset count if all done
-- ...
elsif cnt > 12 then
sum_1 <= sum_1 + resu(cnt - 8); --calculate sum
end if;
Dieser Zweig wird für Werte von 13 bis 28 ausgeführt cnt
und generiert Indizes für das resu
Array von 5 bis 20, aber das Array hat nur Elemente für die Indizes 0 bis 5.
Es scheint mir, dass Sie wirklich möchten, dass das Zurücksetzen erfolgt, wenn cnt = 19
und die Indizes sein sollten resu(cnt - 13)
.
Auch ich habe Probleme, dem zu folgen, aber ein Vorschlag wäre, die Koeffizienten auf einige einfache Werte einzustellen und das Design zu simulieren, indem die mathematischen Ergebnisse untersucht werden. Arbeiten Sie sich dann bis zu den komplexeren Koeffizienten vor. Ohne eine vollständige numerische Analyse der Simulation kann man nicht wirklich sagen, was schief läuft.
Andi aka
Kaffee
Andi aka