-
Notifications
You must be signed in to change notification settings - Fork 4
/
sos_filter_tb.vhd
130 lines (104 loc) · 5.46 KB
/
sos_filter_tb.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
LIBRARY ieee ;
USE ieee.NUMERIC_STD.all ;
USE ieee.std_logic_1164.all ;
use ieee.math_real.all;
use work.sos_filter_pkg.all;
library vunit_lib;
context vunit_lib.vunit_context;
entity sos_filter_tb is
generic (runner_cfg : string);
end;
architecture vunit_simulation of sos_filter_tb is
constant clock_period : time := 1 ns;
constant simtime_in_clocks : integer := 5000;
signal simulator_clock : std_logic := '0';
signal simulation_counter : natural := 0;
-----------------------------------
-- simulation specific signals ----
------------------------------
signal state_counter : integer := 0;
signal memory1 : real_array(0 to 1) := (others => 0.0);
signal memory2 : real_array(0 to 1) := (others => 0.0);
signal memory3 : real_array(0 to 1) := (others => 0.0);
signal fix_memory1 : fix_array(0 to 1) := (others => 0);
signal fix_memory2 : fix_array(0 to 1) := (others => 0);
signal fix_memory3 : fix_array(0 to 1) := (others => 0);
-- these gains were obtained with matlab using
-- [b,a] = cheby1(6, 1, 1/30);
-- [sos, g] = tf2sos(b,a, 'down',2)
constant b1 : real_array(0 to 2) := (1.10112824474792e-003 , 2.19578135597009e-003 , 1.09466577037144e-003);
constant b2 : real_array(0 to 2) := (1.16088276025753e-003 , 2.32172985621810e-003 , 1.16086054728631e-003);
constant b3 : real_array(0 to 2) := (42.4644359704529e-003 , 85.1798866651586e-003 , 42.7159465798333e-003) / 58.875768;
constant a1 : real_array(0 to 2) := (1.00000000000000e+000 , -1.97840025988718e+000 , 987.883963652581e-003);
constant a2 : real_array(0 to 2) := (1.00000000000000e+000 , -1.96191974906017e+000 , 967.208461633959e-003);
constant a3 : real_array(0 to 2) := (1.00000000000000e+000 , -1.95425095615658e+000 , 955.427665692536e-003);
constant fix_b1 : fix_array(0 to 2) := to_fixed(b1);
constant fix_b2 : fix_array(0 to 2) := to_fixed(b2);
constant fix_b3 : fix_array(0 to 2) := to_fixed(b3);
constant fix_a1 : fix_array(0 to 2) := to_fixed(a1);
constant fix_a2 : fix_array(0 to 2) := to_fixed(a2);
constant fix_a3 : fix_array(0 to 2) := to_fixed(a3);
signal filter_out : real := 0.0;
signal filter_out1 : real := 0.0;
signal filter_out2 : real := 0.0;
signal fix_filter_out : integer := 0;
signal fix_filter_out1 : integer := 0;
signal fix_filter_out2 : integer := 0;
signal real_filter_output : real := 0.0;
signal fixed_filter_output : real := 0.0;
signal filter_error : real := 0.0;
signal max_calculation_error : real := 0.0;
begin
------------------------------------------------------------------------
simtime : process
begin
test_runner_setup(runner, runner_cfg);
wait for simtime_in_clocks*clock_period;
check(max_calculation_error < 0.1, "calculation error is " & real'image(max_calculation_error));
test_runner_cleanup(runner); -- Simulation ends here
wait;
end process simtime;
simulator_clock <= not simulator_clock after clock_period/2.0;
------------------------------------------------------------------------
stimulus : process(simulator_clock)
--------------------------
procedure calculate_real_sos
(
signal memory : inout real_array;
input : in real;
signal output : inout real;
counter : in integer;
b_gains : in real_array;
a_gains : in real_array;
constant counter_offset : in integer
) is
begin
if counter = 0 + counter_offset then output <= input * b_gains(0) + memory(0); end if;
if counter = 1 + counter_offset then memory(0) <= input * b_gains(1) - output * a_gains(1) + memory(1); end if;
if counter = 2 + counter_offset then memory(1) <= input * b_gains(2) - output * a_gains(2); end if;
end calculate_real_sos;
--------------------------
--------------------------
constant filter_input : real := 1.0;
begin
if rising_edge(simulator_clock) then
simulation_counter <= simulation_counter + 1;
state_counter <= simulation_counter mod 5;
calculate_real_sos(memory1 , filter_input , filter_out , state_counter , b1 , a1 , 0);
calculate_real_sos(memory2 , filter_out , filter_out1 , state_counter , b2 , a2 , 1);
calculate_real_sos(memory3 , filter_out1 , filter_out2 , state_counter , b3 , a3 , 2);
------------------------------------------------------------------------
calculate_sos(fix_memory1 , to_fixed(filter_input) , fix_filter_out , state_counter , fix_b1 , fix_a1 , 0);
calculate_sos(fix_memory2 , fix_filter_out , fix_filter_out1 , state_counter , fix_b2 , fix_a2 , 1);
calculate_sos(fix_memory3 , fix_filter_out1 , fix_filter_out2 , state_counter , fix_b3 , fix_a3 , 2);
-- check values
real_filter_output <= filter_out2;
fixed_filter_output <= real(fix_filter_out2)/2.0**number_of_fractional_bits;
filter_error <= real_filter_output - fixed_filter_output;
if abs(filter_error) > max_calculation_error then
max_calculation_error <= abs(filter_error);
end if;
end if; -- rising_edge
end process stimulus;
------------------------------------------------------------------------
end vunit_simulation;