Forum Discussion
Pre-Emphasis with IIR Filter
Hello!
I want to do a classic Pre-Emphasis with VHDL. Normally this is implemented with an IIR-Filter. I tried to do this in VHDL with the following formula I found in the web: y(i)=x(i)-(x(i-1)*k) . "k" is a factor between 0.95....0.97. When I do this the higher frequencies of an audio-signal have to rise in the magnitude. In my case only all frequencies are attenuated...what am I doing wrong?? Here is my code: beginif (rst = '0') then
xi := (others => '0');
xi1 := (others => '0');
yn_tmp := (others => '0');
yn_tmp2 := (others => '0');
b0_var := ("01100001"); --97
div := ("01100100"); --100
elsif (clk'event and clk = '1') then
x <= input;
yn_tmp := xi1 * b0_var;
yn_tmp2 := yn_tmp / div;
yn := resize(xi, yn_tmp2'length) - yn_tmp2;
output <= resize(yn, output'length);
xi1 := resize(yn, xi1'length);
xi := x;
end if; Thanks for your help! Tobias
11 Replies
- Altera_Forum
Honored Contributor
I just modelled your equation in Matlab :
output is simply reduced by .95 at all frequenciesx = ; %impulse input k = .95; y(1)=0; for i = 2:1000 y(i)=x(i)-(x(i-1)*k); end fx = fftshift(fft(x)); fy = fftshift(fft(y)); plot(abs(fx));hold plot(abs(fy),'r') - Altera_Forum
Honored Contributor
However I must admit that if I enter:
h =[1 -.95] freqz(h) there is pre-emphasis(I will look at this discrepancy) - Altera_Forum
Honored Contributor
It is to do with my first assumption about y(1) = 0
If you put y(1) = x(1) it gets ok ...sorry So now your algorithm is correct after all. Let us check your implementation... - Altera_Forum
Honored Contributor
here is my first go:
note that Yn relates to Xi and Yn_tmp2 yet Yn_tmp2 relates to Xi1 Xi and Xi1 are same stage values.(only x is delayed at x <= input))elsif (clk'event AND clk = '1') then X <= Input; Yn_tmp := Xi1 * b0_var; Yn_tmp2 := Yn_tmp / div; Yn := resize(Xi, Yn_tmp2'length) - Yn_tmp2; Output <= resize(Yn, Output'length); Xi1 := resize(Yn, Xi1'length); Xi := X; end if; - Altera_Forum
Honored Contributor
OK....Thank You Kaz for your quick reply!
I will check the implementation.... - Altera_Forum
Honored Contributor
I tried this code and I think the pre-emphasis works. But the output-signal is very distorted in the higher frequencies and the lower frequencies are very attenuated. Here is the modified VHDL-code:
if (rst = '0') then
xi := (others => '0');
xi1 := (others => '0');
yn_tmp := (others => '0');
yn_tmp2 := (others => '0');
b0_var := ("01100001"); --97
div := ("01100100"); --100
elsif (clk'event and clk = '1') then
x <= input;
xi := x; --new value
yn_tmp := xi1 * b0_var;
yn_tmp2 := yn_tmp / div;
yn := resize(xi, yn_tmp2'length) - yn_tmp2;
output <= resize(yn, output'length);
xi1 := xi; --old value
end if; Normally the lower frequencies would go through without gain and the higher frequencies starting at 3 kHz have to be boosted with 6dB/octave.
- Altera_Forum
Honored Contributor
Frequencies below to Om=1.0644 rads are attenuated, so, frequencies above to Om=1.0644 rads are amplified almost two times for ones near to pi. Check you are using an enough bit size for output, a small one could cause your problem.
- Altera_Forum
Honored Contributor
Hi,
I don't see much code difference with regard to input stages. Remember the operator := means immediate assignment(no register). the only assignment for register is the operator <= (but I could be wrong as := may at times lead to register if its value updated at end of process but used on top, a rather mercky area that I avoid) Hence only "x" is one delay stage behind "input". The assignment <= on output is just a register on the output and doesn't come into calculation. I must also tell you that your filter is FIR not IIR as it depends on input stages only. In fact it is a type of differentiator(subtracts last sample from current, similar to one stage CIC comb). It is high pass filter Your current coeffs are [1 -.95] and this affects the dc gain so you need to adjust for gain control. Normally in high pass filters you target unity gain at Nguist, If you want unity dc gain in Matlab: h=[1 -.95]; h = h/sum(h) freqz(h) you will see 0dB at dc and 32B gain at high frequency. - Altera_Forum
Honored Contributor
If you are processing audio or speech, perhaps DC component is missing, it doesn't carry information. Direct implementation of pre-emphasis filter without DC unity gain normalization , implies just a 1 bit growth on output word size at highest frequency (pi).
Check this out:
nevertheless, normalization at Nyquist frequency is done, in this case, by h=[1 -0.97]; h=h/sum(abs(h)); so, there is not bit growth at output.library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; entity preemphasis is generic ( --Word size N: integer:=8; --Fractional bits M: integer:=7; --h for preemphasis filter h1: real:= 0.97 ); port ( --Input xn: in std_logic_vector(N-1 downto 0); --Output yn: out std_logic_vector(N downto 0); --Clock clk: in std_logic; --Reset reset_n: in std_logic ); end entity; architecture rtl of preemphasis is signal xn1: std_logic_vector(N-1 downto 0); signal mult_out: std_logic_vector(2*N-1 downto 0); signal coeff: std_logic_vector(N-1 downto 0); signal ynreg,sub_out: std_logic_vector(N downto 0); begin --Wired coeff h coeff<=std_logic_vector(to_signed(integer(round(h1*real(2**M))),N)); --Registers for x and y process(xn,clk,reset_n) begin if(reset_n='0') then xn1<=(others=>'0'); ynreg<=(others=>'0'); elsif(rising_edge(clk)) then xn1<=xn; ynreg<=sub_out; end if; end process; --Multiplier mult_out<=std_logic_vector(signed(xn1)*signed(coeff)); --Substract with sign extend sub_out<=std_logic_vector(signed(xn(N-1)&xn)-signed(mult_out(M+N downto M))); --Connects register to output yn<=ynreg; end architecture; - Altera_Forum
Honored Contributor
Hello!
this is my new version. i tried to solve the problem with the assignments.
I fixed the output, so that it has one more bit. The higher frequencies are ok now, but the lower frequencies are still very attenuated. For example a signal f=100Hz nearly disappears after the filter. The thing is that normally the frequencies below 3.18 kHz have to go through without any increase oder decrease. @parrado: Thank you for the code. I will check it out!!library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity PREemphase is Port ( Input : in signed (13 downto 0); Output : out signed (14 downto 0); CLK : in STD_LOGIC; RST : in STD_LOGIC ); end PREemphase; architecture verhalten of PREemphase is --signal X : signed (13 downto 0); signal Xi : signed (13 downto 0); signal Xi1 : signed (13 downto 0); begin filter: process(RST, CLK) --variable Xi : signed (13 downto 0); variable Yn : signed (21 downto 0); --variable Xi1 : signed (20 downto 0); variable Yn_tmp : signed (21 downto 0); variable Yn_tmp2 : signed (21 downto 0); variable b0_var : signed ( 7 downto 0); variable div : signed ( 7 downto 0); begin if (RST = '0') then --Xi := (others => '0'); --Xi1 := (others => '0'); Yn_tmp := (others => '0'); Yn_tmp2 := (others => '0'); b0_var := ("01100001"); --97 div := ("01100100"); --100 Yn := (others => '0'); elsif (clk'event AND clk = '1') then --X <= Input; Xi <= Input; --new value Yn_tmp := Xi1 * b0_var; Yn_tmp2 := Yn_tmp / div; Yn := resize(Xi, Yn'length) - Yn_tmp2; Output <= resize(Yn, Output'length); Xi1 <= Xi; --old value end if; end process; end verhalten;