Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

How to add Gaussian noise/any other noise to sine wave(using VHDL)?

Status
Not open for further replies.

Anwesa Roy

Member level 2
Joined
Feb 24, 2014
Messages
49
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
532
We need a noisy sine wave signal. We have generated the sine wave(using VHDL), but we cant figure out how to add noise to it. We are including the code for sine wave generation. Kindly mention how to add Gaussian/any other noise to it.
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;  --try to use this library as much as possible.

entity sine_wave is
port (clk :in  std_logic;
      data_out : out STD_LOGIC_VECTOR(7 downto 0)
      );
end sine_wave;

architecture Behavioral of sine_wave is
signal i : integer range 0 to 29:=0;
--type memory_type is array (0 to 29) of integer;
type memory_type is array (0 to 29) of std_logic_vector(7 downto 0); 
--ROM for storing the sine values generated by MATLAB.
signal sine : memory_type :=("01001101","01011101","01101100","01111010","10000111","10010000","10010111","10011010","10011010","10010111","10010000","10000111","01111010","01101100","01011101","01001101",
"00111101","00101110","00100000","00010011","00001010","00000011","00000000","00000000","00000011","00001010","00010011","00100000","00101110","00111101");
--hi
begin

process(clk)
begin
  --to check the rising edge of the clock signal
if(rising_edge(clk)) then     
data_out <= sine(i);
i <= i+ 1;
if(i = 29) then
i <= 0;
end if;
end if;
end process;

end Behavioral;

sine.png
 

Error: to_signed is not declared.

We are trying to incorporate noise in our signal using VHDL code.

Code:
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 07/28/2016 02:42:50 PM
-- Design Name: 
-- Module Name: Noise1 - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use IEEE.MATH_REAL.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Noise1 is
    Port ( a,b : in STD_LOGIC;
           
           c : out STD_LOGIC);
end Noise1;

architecture Behavioral of Noise1 is
signal rand_num: signed;
CONSTANT tempo : time := 20 ns;
begin

rdm : PROCESS
    VARIABLE seed1, seed2: positive;            
    VARIABLE rand: real;  
    VARIABLE rdm_rng : real := 419430.0; 
    VARIABLE rand_num_i : integer := 0;
    
    
BEGIN
    uniform(seed1, seed2, rand);
    rand_num_i  := integer(rand*rdm_rng) - 104858; -- rescaling
    rand_num <= to_signed(rand_num_i, 24);
    
    WAIT FOR tempo;
END PROCESS;

end Behavioral;


How should we declare rand_num.For now we have declared rand_num as "signal rand_num: signed;". Is there anything wrong in the declaration? When we run the program, we are getting an error that "to_signed is not declared".Do we need additional libraries to use the function to_signed()?...Actually we got a code snippet by an helpful user, now we are incorporating the code snippet in our program. The suggested code snippet is the following:

Code:
---------------------------------------
-- generates rdm numbers to simulate 
-- noise on the line
---------------------------------------
rdm : PROCESS
    VARIABLE seed1, seed2: positive;            
    VARIABLE rand: real;  
    VARIABLE rdm_rng : real := 419430.0; 
    VARIABLE rand_num_i : integer := 0;
BEGIN
    uniform(seed1, seed2, rand);
    rand_num_i  := integer(rand*rdm_rng) - 104858; -- rescaling
    rand_num <= to_signed(rand_num_i, 24);
    WAIT FOR tempo;
END PROCESS;
 

Re: Error: to_signed is not declared.

You commented the library to be included:

Code:
--use IEEE.NUMERIC_STD.ALL;
 

Re: Error: to_signed is not declared.

You commented the library to be included:

Code:
--use IEEE.NUMERIC_STD.ALL;

Sir we have uncommented the library "use IEEE.NUMERIC_STD.ALL;
". Now if we synthesize the code, the following errors are popping up, as shown by the screenshot:

noise1.png
 

Re: Error: to_signed is not declared.

Delete the following line:

use ieee.std_logic_arith.all;

dont just comment it out. Delete it and never ever ever use it again.
 

Re: Error: to_signed is not declared.

You'll notice that all VHDL experts suggest to use IEEE standard library numeric_std instead of outdated std_logic_arith and related libraries.

If you are however stuck with the legacy libraries for some reason, you have to use the respective type conversion functions, e.g. conv_signed() instead of to_signed().

- - - Updated - - -

P.S.: I agree that you should follow the suggestion by TrickyDicky if ever possible.

There are only few reasons to stay with the old libraries, one possible is that you are reusing a large number of components with std_logic_arith port signals and you don't want to edit it. A less convincing reason would be you found an outdated VHDL text book and don't want to buy a new one.
 

Re: Error: to_signed is not declared.

The other issue with this code is you are once again trying to synthesize math_real. Reals are NOT synthesizable. How many times does that need to be repeated to you?

The rand function is also not synthesizable. If you want to generated random bit sequences use a prbs (maximal length lfsr) to generate it.
 

The real issue is that the developer is attempting to develop the signal processing algorithm inside synthesizable VHDL.

Normally, Matlab/python/etc... would be used to do the algorithm work. Then some ad-hoc design to see how it scales in HW. Then some finite-precision work in Matlab/python/etc... to see how limited precision affects the algorithm. Then comes the work on the VHDL implementation and testbench.


Doing this allows you to create test vectors as large files, and load them in simulation. The actual design would only have input from the actual data source.

In some cases, you might need to have a step where you use an ad-hoc design to get accurate test data from the data source so the algorithm design can take front-end issues into account in the most accurate manner.


IMO, at this point the main reason to use numeric_std is because no one will yell at you if you use numeric_std.
 

We are trying to generate a noisy sine wave signal, that will be phase shifted three times to generate signals s1,s2,s3 and s4. For that we have created an array sine2 that will hold the noisy sine wave signal, and we will shift it according to our convenience by changing its index.

The problem is why is s1,s2,s3,s4 not starting from the beginning(ie from t=0)? and why is there relative gaps between the signal as visible from the figure. We need to remove that gap, and if posiible start it from t=0. Please help.

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;  --try to use this library as much as possible.

entity sine_wave is
 generic ( width : integer :=  4 ); 
port (clk :in  std_logic;
      random_num : out std_logic_vector (width-1 downto 0); 
      data_outa,data_outb,data_outc,data_outd : out STD_LOGIC_VECTOR(7 downto 0)
      );
end sine_wave;

architecture Behavioral of sine_wave is
signal data_out1,rand_temp1,noisy_signal,data_outb1,data_outc1,data_outd1, summation_signal : integer;
signal noisy_signal1,s1,s2,s3,s4 : STD_LOGIC_VECTOR(7 downto 0);
signal summation_signal1 : STD_LOGIC_VECTOR(11 downto 0);
signal i : integer :=0;
signal j : integer :=120;
signal k : integer :=40;
signal l : integer :=80;
signal ii,iii: integer :=0 ;
signal jj: integer :=30 ;
signal kk: integer :=60 ;
signal ll: integer :=90 ;
--type memory_type is array (0 to 29) of integer;
type memory_type is array (0 to 359) of std_logic_vector(7 downto 0); 
signal sine2 : memory_type;
--ROM for storing the sine values generated by MATLAB.
signal sine : memory_type :=(x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"01",x"01",
x"01",x"01",x"01",x"01",x"02",x"02",x"02",x"02",x"03",x"03",
x"03",x"04",x"04",x"04",x"04",x"05",x"05",x"05",x"05",x"06",
x"06",x"07",x"07",x"08",x"08",x"09",x"09",x"0a",x"0a",x"0b",
x"0b",x"0c",x"0c",x"0d",x"0d",x"0e",x"0e",x"0f",x"0f",x"10",
x"11",x"11",x"12",x"13",x"13",x"14",x"15",x"15",x"16",x"17",
x"18",x"18",x"19",x"1a",x"1b",x"1b",x"1c",x"1d",x"1e",x"1e",
x"1f",x"20",x"21",x"22",x"23",x"23",x"24",x"25",x"26",x"27",
x"28",x"29",x"2a",x"2b",x"2c",x"2d",x"2f",x"2f",x"30",x"31",
x"32",x"34",x"35",x"35",x"36",x"37",x"38",x"39",x"3a",x"3b",
x"3c",x"3c",x"3e",x"3f",x"40",x"41",x"42",x"43",x"44",x"45",
x"46",x"46",x"47",x"48",x"49",x"49",x"4a",x"4b",x"4c",x"4c",
x"4e",x"4f",x"4f",x"50",x"51",x"51",x"52",x"53",x"53",x"54",
x"55",x"55",x"56",x"57",x"57",x"58",x"58",x"59",x"59",x"5a",
x"5a",x"5b",x"5b",x"5c",x"5c",x"5d",x"5d",x"5e",x"5e",x"5f",
x"5f",x"5f",x"60",x"60",x"60",x"61",x"61",x"61",x"61",x"62",
x"62",x"62",x"62",x"63",x"63",x"63",x"63",x"63",x"63",x"64",
x"64",x"64",x"64",x"64",x"64",x"64",x"64",x"64",x"64",x"64",
x"64",x"64",x"64",x"64",x"64",x"64",x"63",x"63",x"63",x"63",
x"63",x"63",x"62",x"62",x"62",x"62",x"61",x"61",x"61",x"60",
x"60",x"60",x"5f",x"5f",x"5f",x"5e",x"5e",x"5d",x"5d",x"5c",
x"5c",x"5b",x"5b",x"5a",x"5a",x"59",x"59",x"58",x"58",x"57",
x"57",x"56",x"55",x"55",x"54",x"54",x"53",x"53",x"52",x"51",
x"51",x"50",x"4f",x"4f",x"4e",x"4d",x"4c",x"4c",x"4b",x"4a",
x"49",x"49",x"48",x"47",x"46",x"46",x"45",x"44",x"44",x"43",
x"42",x"41",x"41",x"40",x"3f",x"3e",x"3d",x"3c",x"3c",x"3b",
x"3a",x"39",x"38",x"37",x"36",x"35",x"35",x"34",x"33",x"32",
x"31",x"30",x"2f",x"2f",x"2e",x"2d",x"2c",x"2b",x"2a",x"29",
x"28",x"28",x"27",x"26",x"25",x"24",x"23",x"23",x"22",x"21",
x"20",x"1f",x"1e",x"1e",x"1d",x"1c",x"1b",x"1b",x"1a",x"19",
x"18",x"18",x"17",x"16",x"15",x"15",x"14",x"13",x"13",x"12",
x"11",x"11",x"10",x"0f",x"0f",x"0e",x"0d",x"0d",x"0c",x"0c",
x"0b",x"0b",x"0a",x"0a",x"09",x"09",x"08",x"08",x"07",x"07",
x"06",x"06",x"05",x"05",x"05",x"04",x"04",x"04",x"03",x"03",
x"03",x"02",x"02",x"02",x"02",x"01",x"01",x"01",x"01",x"01",
x"01",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00");
--hi
begin

process(clk)
variable rand_temp : std_logic_vector(width-1 downto 0):=(width-1 => '1',others => '0');
variable temp : std_logic := '0';
begin
  --to check the rising edge of the clock signal
if(rising_edge(clk)) then  

temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;

--data_out <= sine(i);
i <= i+ 1;
if(i = 359) then
i <= 0;
end if;

j <= j+ 1;
if(j = 359) then
j <= 0;
end if;

k <= k+ 1;
if(k = 359) then
k <= 0;
end if;

l <= l+ 1;
if(l = 359) then
l <= 0;
end if;

data_outa <= sine(i);

data_outb <= sine(j);
data_outc <= sine(k);
data_outd <= sine(l);


random_num <= rand_temp;
rand_temp1<=to_integer(unsigned(rand_temp));
data_out1<=to_integer(unsigned(sine(i)));
noisy_signal<=data_out1+rand_temp1;
noisy_signal1<= std_logic_vector(to_signed(noisy_signal,8));
--data_outb1 <= to_integer(unsigned(sine(j)));
--data_outc1 <= to_integer(unsigned(sine(k)));
--data_outd1 <= to_integer(unsigned(sine(l)));
--summation_signal <= data_outb1+data_outc1+data_outd1+noisy_signal;
--summation_signal1 <= std_logic_vector(to_signed(summation_signal,12));

--for ii in 0 to 359 loop
--   sine2(ii)<=noisy_signal1;
--   s1 <= sine2(ii);   
--  end loop;

sine2(ii)<=noisy_signal1;
     ii <= ii+ 1;
         if(ii = 359) then
         ii <=0;
         end if;

     s1 <= sine2(iii);
     iii <= iii+ 1;
     if(iii = 359) then
     iii <= 0;
     end if;

    s2 <= sine2(jj);
    jj <= jj+ 1;
    if(jj = 359) then
    jj <= 0;
    end if;
     s3 <= sine2(kk);
     kk <= kk+ 1;
     if(kk = 359) then
     kk <= 0;
     end if;
     s4 <= sine2(ll);
     ll <= ll+ 1;
     if(ll = 359) then
     ll <= 0;
     end if;

end if;
--data_outa <= sine(i);

--data_outb <= sine(j);
--data_outc <= sine(k);
--data_outd <= sine(l);

--data_out1<=to_integer(unsigned(sine(i)));
--random_num <= rand_temp;
--rand_temp1<=to_integer(unsigned(rand_temp));
--noisy_signal<=data_out1+rand_temp1;
--noisy_signal1<= std_logic_vector(to_signed(noisy_signal,8));
----data_outb1 <= to_integer(unsigned(sine(j)));
----data_outc1 <= to_integer(unsigned(sine(k)));
----data_outd1 <= to_integer(unsigned(sine(l)));
----summation_signal <= data_outb1+data_outc1+data_outd1+noisy_signal;
----summation_signal1 <= std_logic_vector(to_signed(summation_signal,12));

----for ii in 0 to 359 loop
----     sine2(ii)<=noisy_signal1;
----     s1 <= sine2(ii);   
----    end loop;

end process;



end Behavioral;

sineadd1.png
 

At t=0 your sine2 memory is uninitialized. sine2 memory is written 1 byte at a time on each clock cycle. So after 360 clk cycles sine2 will be fully written. In your simulation, check how sine2 memory is filled.

You need to initialize sine2 with random value the same way you did with sine memory.
 
At t=0 your sine2 memory is uninitialized. sine2 memory is written 1 byte at a time on each clock cycle. So after 360 clk cycles sine2 will be fully written. In your simulation, check how sine2 memory is filled.

You need to initialize sine2 with random value the same way you did with sine memory.

Sir Understood. But sir why is then a relative separation is there between the signals. Shouldnt they all start from the same instant after facing a particular delay(in this case after 360 clock cycles)?
 

iii, jj, kk and ll don't have the same initial value. This is why they are not in phase.

signal ii,iii: integer :=0 ;
signal jj: integer :=30 ;
signal kk: integer :=60 ;
signal ll: integer :=90 ;
 

iii, jj, kk and ll don't have the same initial value. This is why they are not in phase.

signal ii,iii: integer :=0 ;
signal jj: integer :=30 ;
signal kk: integer :=60 ;
signal ll: integer :=90 ;

Sir understood that the signals will have phase difference but why is s4 is starting earliest, then s3, then s2 and then s1

sineadd1.png
 

Because signal ll is the first to return to 0, then kk and so on...

Add these signals in the waveform window of the simulator and see by yourself.
 

I think the problem is that you still don't get that VHDL does everything in parallel and only the last assignment to a signal is kept.


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sine2(ii)<=noisy_signal1;  -- this is the noisy sine wave which is populated starting at index ii=0
ii <= ii+ 1;  -- increments ii
if(ii = 359) then  -- but this will reassign ii if ii=359
  ii <=0;
end if;
 
s1 <= sine2(iii); -- start outputting s1, but start at inedex iii=0, but this is done IN PARALLEL
                  -- with the above assignment for sine2(ii), so this becomes a pipeline of:
                  --   sine2(0) <= noisy_singal; -- assign new value to sine2(0)
                  --   s1       <= sine2(0); -- use old uninitialized value of sine2(0) to s1
                  -- until sine2(n) wraps back around to sine2(0) the memory array is uninitialized.
iii <= iii+ 1;
if(iii = 359) then
  iii <= 0;
end if;


Your problem boils down to not understanding VHDL scheduling mechanics and trying to use software execution as the basis of how you interpret and understand how the code "runs".
 

Code:
-- inside process
x <= x+1;
if (x = 359) then
  x <= 0;
end if;

if (y = 359) then
  y <= 0;
else
  y <= y+1;
end if;

The semantics of VHDL make the logic for x and y the same. The first version is less common and follows the "default"+"special case" style. the second version is more common and follows the "assign once per process" style.





For the application, which I still suspect isn't valid, I would use the 23b lfsr, with taps at bit 22 and bit 17. This allows you to generate 16 new bits per cycle easily. the 16 new inputs bits will be 22:7 xor'd with 17:2. This gives 4 new lfsr samples per cycle which can be summed into the waves as you see fit. This would give you different noise per wave.

However the simplified LFSR does give you the ability to precompute the noise. As you would expect, a generator with 4b of internal state and no external inputs will generate a sequence of length 16 at most. all 0's give all 0's as the next result, so the LFSR can generate a sequence of length 15 at most (for 4 bit).

You can generate 4 constants using a function -- one for 120 mod 15 shifts, one for 40 mod 15, and one for 80 mod 15. then you can initialize the lfsr state to these four value (at a sync reset) and generate the noise. This gets the weird "identical noise per waveform" property, which seems odd as well.

(LFSR's are not always made by xor'ing the top two bits. This method works for length 3, 4, 6, 7, 15, 60, 63, but not for most other lengths like 8, 16, 32, or 64. if you xor the 2 msb, you will get a sequence with a length based on the initial value. in some cases it can repeat much earlier.)
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top