OpenCores
URL https://opencores.org/ocsvn/pulse_processing_algorithm/pulse_processing_algorithm/trunk

Subversion Repositories pulse_processing_algorithm

[/] [pulse_processing_algorithm/] [MWD_programmable.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 panda_emc
-----------------------------------------------------------------------------------------------
2
--
3
--    Copyright (C) 2011 Peter Lemmens, PANDA collaboration
4
--              p.j.j.lemmens@rug.nl
5
--    http://www-panda.gsi.de
6
--
7
--    As a reference, please use:
8
--    E. Guliyev, M. Kavatsyuk, P.J.J. Lemmens, G. Tambave, H. Loehner,
9
--    "VHDL Implementation of Feature-Extraction Algorithm for the PANDA Electromagnetic Calorimeter"
10
--    Nuclear Inst. and Methods in Physics Research, A ....
11
--
12
--
13
--    This program is free software; you can redistribute it and/or modify
14
--    it under the terms of the GNU Lesser General Public License as published by
15
--    the Free Software Foundation; either version 3 of the License, or
16
--    (at your option) any later version.
17
--
18
--    This program is distributed in the hope that it will be useful,
19
--    but WITHOUT ANY WARRANTY; without even the implied warranty of
20
--    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
--    GNU Lesser General Public License for more details.
22
--
23
--    You should have received a copy of the GNU General Public License
24
--    along with this program; if not, write to the Free Software
25
--    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
26
--
27
-----------------------------------------------------------------------------------------------
28
-----------------------------------------------------------------------------------------------
29
-- Company:                     KVI (Kernfysisch Versneller Instituut  -- Groningen, The Netherlands    
30
-- Author:                      P.J.J. Lemmens
31
-- Design Name: mwd_programmable
32
-- Module Name: MWD_programmable.vhd
33
-- Description: moving-window deconvolution algorithm (MWD) with programmable 
34
--                                              filter-length (power of 2) and decay-correction parameter
35
--                                              Intended for use with 'slow' logarithmic-decaying pulses that 
36
--                                              occur for instance when a particle/photon strikes a photo-diode
37
-----------------------------------------------------------------------------------------------
38
library IEEE;
39
use IEEE.STD_LOGIC_1164.ALL;
40
use IEEE.STD_LOGIC_ARITH.ALL;
41
use IEEE.STD_LOGIC_SIGNED.ALL;
42
 
43
entity mwd_programmable is
44
        generic(        MAX_MWD_PWR             :       natural);
45
   Port (rst                                    : in  STD_LOGIC;
46
                        clk                                     : in  STD_LOGIC;
47
                        enable                          : in  STD_LOGIC;
48
                        program                         : in  std_logic;
49
                        mwd_pwr_in                      : in  std_logic_vector(7 downto 0);
50
                        data_in                         : in  STD_LOGIC_VECTOR;
51
                        correction_in           : in  STD_LOGIC_VECTOR;
52
                        data_out                                : out STD_LOGIC_VECTOR
53
                );
54
end mwd_programmable;
55
 
56
architecture Behavioral of mwd_programmable is
57
 
58
        constant        WIDTH                   : natural := data_in'length;
59
        constant        M_WIDTH         : natural := 18;                                                        -- Multiplier width ; xilinx MULT18x18_SIO
60
 
61
        component window_subtractor_programmable
62
                generic(        FORWARD         :       boolean;
63
                                        MAX_MWD_PWR     :       natural);
64
                Port (rst                               : in  STD_LOGIC;
65
                                clk                             : in  STD_LOGIC;
66
                                enable                  : IN    STD_LOGIC ;
67
                                program                 : in  STD_LOGIC;
68
                                window_pwr_in   : in  STD_LOGIC_VECTOR(7 downto 0);
69
                                data_in                 : in  STD_LOGIC_VECTOR;
70
                                data_out                        : out STD_LOGIC_VECTOR
71
                                );
72
        end component;
73
 
74
        component moving_average_programmable
75
                generic(MEM_PWR         : natural);
76
                port (rst                               : in    std_logic;
77
                                clk                             : in    std_logic;
78
                                enable                  : in  std_logic;
79
                                program                 : in  std_logic;
80
                                avg_pwr_in              : in  std_logic_vector(7 downto 0);
81
                                data_in                 : in  std_logic_vector;
82
                                data_out                        : out std_logic_vector
83
                        );
84
        end component;
85
 
86
----------------------------------------------------------------------------------------------------------
87
--The calculations of and with correction factor introduce interesting problems combined with
88
--the fact that the dedicated hardware multipliers in Xilinx Spartan III are 18/36bit wide(fixed)
89
--
90
--(1) As we have to multiply with a sum over (2^WINDOW_PWR) samples, the sum should be 
91
--(WIDTH+WINDOW_PWR)-bits wide. However if this width exceeds 18bit we will have to truncate the result,
92
--effectively dividing by (2^(lost#bits)). We can identify 3 situations where (WIDTH+WINDOW_PWR)<18,
93
--(WIDTH+WINDOW_PWR)=18 and (WIDTH+WINDOW_PWR)>18 that require different approaches making a generic and
94
--scalable solution all but impossible.
95
--
96
--(2) The correction factor on the other hand is a real number <1 which we want to convert to a usefull
97
--integer value in order to be able to do a cost-effective multiplication. In the given example/situation
98
--correction_factor = 0.69314718/tau = 0.69314718 / 1250 ~ 0.554517e-3. This allows for a multiplication
99
--by 2^28 while still remaining within 18bits (as 262143 is the max int in 18bit); result: 148852
100
--
101
----------------------------------------------------------------------------------------------------------
102
--
103
--Example for 16-bit data and a WINDOW_PWR of 6 (64 sample window):
104
--** ((WIDTH+WINDOW_PWR)= 16 + 6 = 22bit, fitting into 18bit means a loss of 4-bit equals a division by 16 !!
105
--** Correction factor multiplication (2) gives us a gain of 28-bit, thus effectively the PRODUCT will be 2^24 too high
106
--
107
--************************************************************
108
--**** the lower 24 bits should therefore be discarded !! ****
109
--************************************************************
110
--
111
----------------------------------------------------------------------------------------------------------
112
 
113
 
114
--      constant Fsmp   : real := 50.0e6;                                                                               -- Sample frequency 50MHz
115
--      constant tau    : real := (0.0000125    * Fsmp);                                                        -- calculate time-constant
116
--      constant ln2    : real := 0.69314718;                                                                   -- natural log of 2
117
--      constant correction_factor      : integer range 0 to (2**18 - 1) := integer((ln2/tau) * real(2**24));   -- decay correction weight*(2^24)
118
--      constant correction_factor      : std_logic_vector(17  downto 0) := conv_std_logic_vector(signed(148852), 18);
119
--      constant CORRECTION_FACTOR      : std_logic_vector(17  downto 0) := conv_std_logic_vector(74426, 18); -- = (ln(2)/tau) * 2^26)
120
        -- this should give a integer value of correction_factor=18607 which still fits
121
        -- within the 18bit (2^18=262144)... 2^27 is max !!
122
 
123
        signal rst_S                            : std_logic := '1';
124
        signal clk_S                            : std_logic := '0';
125
        signal enable_S                 : std_logic := '0';
126
        signal data_in_S                        : std_logic_vector(WIDTH - 1 downto 0) := (others => '0');
127
        signal program_S                        : std_logic := '0';
128
        signal mwd_pwr_S                        : std_logic_vector(7 downto 0)                           := x"05";
129
        signal diff_data_S              : std_logic_vector(WIDTH - 1 downto 0)           := (others => '0');
130
        signal decay_corr_S             : std_logic_vector(WIDTH - 1 downto 0)   := (others => '0');
131
        signal average_S                        : std_logic_vector(WIDTH - 1 downto 0)           := (others => '0');
132
        signal mult_sum_S                       : std_logic_vector(M_WIDTH - 1 downto 0) := (others => '0');
133
        signal factor_S                 : std_logic_vector(M_WIDTH - 1 downto 0) := conv_std_logic_vector(37213, M_WIDTH);
134
        signal product36                        : std_logic_vector(35 downto 0)                          := (others => '0');
135
        signal data_out_S                       : std_logic_vector(WIDTH - 1 downto 0)           := (others => '0');
136
 
137
-----------------------------------------------------------------------
138
 
139
        begin
140
 
141
                rdif : window_subtractor_programmable
142
                        generic map(FORWARD                     => true,
143
                                                        MAX_MWD_PWR             => MAX_MWD_PWR)
144
                        Port map(       rst                             => rst_S,
145
                                                        clk                             => clk_S,
146
                                                        enable                  =>      enable_S,
147
                                                        program                 => program_S,
148
                                                        window_pwr_in   => mwd_pwr_S,
149
                                                        data_in                 => data_in_S,
150
                                                        data_out                => diff_data_S
151
                                                );
152
 
153
                mwd_sample_sum : moving_average_programmable
154
                        generic map(MEM_PWR     =>      MAX_MWD_PWR)
155
                        port map(       rst                     => rst_S,
156
                                                        clk                     =>      clk_S,
157
                                                        enable          =>      enable_S,
158
                                                        program         => program_S,
159
                                                        avg_pwr_in      => mwd_pwr_S,
160
                                                        data_in         =>      data_in_S,
161
                                                        data_out                => average_S
162
                                                );
163
 
164
 
165
                rst_S                           <= rst;
166
                clk_S                           <= clk;
167
                enable_S                        <= enable;
168
                                        mwd_pwr_S       <= mwd_pwr_in;
169
                                        factor_S                <=      conv_std_logic_vector(conv_integer(correction_in), factor_S'length);
170
                program_S               <= program;             -- allready synced and single clock by flowcontrol
171
                data_in_S               <= data_in;
172
                data_out                        <= data_out_S;
173
 
174
--      program_proc : process (clk_S)
175
--              begin
176
--              if rising_edge(clk_S) then
177
----                    program_S               <= program;
178
--                      if (rst_S = '1') then
179
--                              mwd_pwr_S       <= x"05";
180
--                      else
181
--                              if (program = '1') then
182
--                                      if (mwd_pwr_in >= 2) and (mwd_pwr_in <= 6) then
183
--                                              mwd_pwr_S       <= mwd_pwr_in;
184
--                                      else
185
--                                              mwd_pwr_S       <= x"05";
186
--                                      end if;
187
--                                      factor_S                <=      conv_std_logic_vector(conv_integer(correction_in), factor_S'length);
188
--                              end if;
189
--                      end if;
190
--              end if;
191
--      end process;
192
 
193
-- all averages should be multiplied by  2^mwd_pwr (we really need a sum) but this generates overflows
194
-- instead we take the average and map it on 18 bit then we choose the fitting correction factor
195
 
196
                mult_sum_S      <= conv_std_logic_vector(conv_integer(average_S), M_WIDTH);
197
 
198
                --      READ explanation above  !!
199
                decay_corr_S(15 downto 0)                                                <= product36(35 downto 20);             -- WATCH IT !! 36bits !! not 32 !! scale it down 24 bits
200
                decay_corr_S(decay_corr_S'high downto 16) <= (others => '0');                                    --  
201
 
202
                decay_correction_proc : process(clk_S, rst_S)
203
                begin
204
                        if (clk_S'event and clk_S = '1') then
205
                                if (rst_S = '1') then
206
                                        product36               <= (others => '0');
207
                                        data_out_S              <= (others => '0');
208
                                else
209
                                        if (enable_S = '1') then
210
                                                product36       <= mult_sum_S * factor_S;
211
                                                data_out_S      <= diff_data_S + decay_corr_S;
212
                                        end if;
213
                                end if;
214
                        end if;
215
                end process;
216
 
217
end Behavioral;
218
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.