FPGA Intellectual Property
PCI Express*, Networking and Connectivity, Memory Interfaces, DSP IP, and Video IP
6356 Discussions

Pre-Emphasis with IIR Filter

Altera_Forum
Honored Contributor II
2,932 Views

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: 

 

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 

 

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
0 Kudos
11 Replies
Altera_Forum
Honored Contributor II
951 Views

I just modelled your equation in Matlab : 

 

x = ; %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')  

 

output is simply reduced by .95 at all frequencies
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

However I must admit that if I enter: 

h =[1 -.95] 

freqz(h) 

 

there is pre-emphasis(I will look at this discrepancy)
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

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...
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

here is my first go: 

 

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;  

 

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))
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

OK....Thank You Kaz for your quick reply! 

 

I will check the implementation....
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

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.

0 Kudos
Altera_Forum
Honored Contributor II
951 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

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: 

 

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;  

 

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.
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

Hello! 

 

this is my new version. i tried to solve the problem with the assignments. 

 

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;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!!
0 Kudos
Altera_Forum
Honored Contributor II
951 Views

You can increase dc gain by rescaling the coeffs. 

 

The following scaling may be useful: 

h =[16 -15.5]. 

 

this should give you some 20dB more near dc. 

To implement that you need to multiply inpyt by 16, use shift by 4 bits instead of multiplication and thats why I chose this value. The other coeff will be -15.5 = 155/10. 

 

You can also avoid division by scaling 155/10 to ?/16 then just truncate 4 bits. 

 

But be warned that this gain could be too much for high frequencies and lead to clipping/overflow, in that case keep coming down.
0 Kudos
Reply