- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
However I must admit that if I enter:
h =[1 -.95] freqz(h) there is pre-emphasis(I will look at this discrepancy)- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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...- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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))
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK....Thank You Kaz for your quick reply!
I will check the implementation....- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page