URL
https://opencores.org/ocsvn/pulse_processing_algorithm/pulse_processing_algorithm/trunk
Subversion Repositories pulse_processing_algorithm
[/] [pulse_processing_algorithm/] [MWD_programmable.vhd] - Rev 2
Compare with Previous | Blame | View Log
----------------------------------------------------------------------------------------------- -- -- Copyright (C) 2011 Peter Lemmens, PANDA collaboration -- p.j.j.lemmens@rug.nl -- http://www-panda.gsi.de -- -- As a reference, please use: -- E. Guliyev, M. Kavatsyuk, P.J.J. Lemmens, G. Tambave, H. Loehner, -- "VHDL Implementation of Feature-Extraction Algorithm for the PANDA Electromagnetic Calorimeter" -- Nuclear Inst. and Methods in Physics Research, A .... -- -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU Lesser General Public License as published by -- the Free Software Foundation; either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU Lesser General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA -- ----------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------- -- Company: KVI (Kernfysisch Versneller Instituut -- Groningen, The Netherlands -- Author: P.J.J. Lemmens -- Design Name: mwd_programmable -- Module Name: MWD_programmable.vhd -- Description: moving-window deconvolution algorithm (MWD) with programmable -- filter-length (power of 2) and decay-correction parameter -- Intended for use with 'slow' logarithmic-decaying pulses that -- occur for instance when a particle/photon strikes a photo-diode ----------------------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_SIGNED.ALL; entity mwd_programmable is generic( MAX_MWD_PWR : natural); Port (rst : in STD_LOGIC; clk : in STD_LOGIC; enable : in STD_LOGIC; program : in std_logic; mwd_pwr_in : in std_logic_vector(7 downto 0); data_in : in STD_LOGIC_VECTOR; correction_in : in STD_LOGIC_VECTOR; data_out : out STD_LOGIC_VECTOR ); end mwd_programmable; architecture Behavioral of mwd_programmable is constant WIDTH : natural := data_in'length; constant M_WIDTH : natural := 18; -- Multiplier width ; xilinx MULT18x18_SIO component window_subtractor_programmable generic( FORWARD : boolean; MAX_MWD_PWR : natural); Port (rst : in STD_LOGIC; clk : in STD_LOGIC; enable : IN STD_LOGIC ; program : in STD_LOGIC; window_pwr_in : in STD_LOGIC_VECTOR(7 downto 0); data_in : in STD_LOGIC_VECTOR; data_out : out STD_LOGIC_VECTOR ); end component; component moving_average_programmable generic(MEM_PWR : natural); port (rst : in std_logic; clk : in std_logic; enable : in std_logic; program : in std_logic; avg_pwr_in : in std_logic_vector(7 downto 0); data_in : in std_logic_vector; data_out : out std_logic_vector ); end component; ---------------------------------------------------------------------------------------------------------- --The calculations of and with correction factor introduce interesting problems combined with --the fact that the dedicated hardware multipliers in Xilinx Spartan III are 18/36bit wide(fixed) -- --(1) As we have to multiply with a sum over (2^WINDOW_PWR) samples, the sum should be --(WIDTH+WINDOW_PWR)-bits wide. However if this width exceeds 18bit we will have to truncate the result, --effectively dividing by (2^(lost#bits)). We can identify 3 situations where (WIDTH+WINDOW_PWR)<18, --(WIDTH+WINDOW_PWR)=18 and (WIDTH+WINDOW_PWR)>18 that require different approaches making a generic and --scalable solution all but impossible. -- --(2) The correction factor on the other hand is a real number <1 which we want to convert to a usefull --integer value in order to be able to do a cost-effective multiplication. In the given example/situation --correction_factor = 0.69314718/tau = 0.69314718 / 1250 ~ 0.554517e-3. This allows for a multiplication --by 2^28 while still remaining within 18bits (as 262143 is the max int in 18bit); result: 148852 -- ---------------------------------------------------------------------------------------------------------- -- --Example for 16-bit data and a WINDOW_PWR of 6 (64 sample window): --** ((WIDTH+WINDOW_PWR)= 16 + 6 = 22bit, fitting into 18bit means a loss of 4-bit equals a division by 16 !! --** Correction factor multiplication (2) gives us a gain of 28-bit, thus effectively the PRODUCT will be 2^24 too high -- --************************************************************ --**** the lower 24 bits should therefore be discarded !! **** --************************************************************ -- ---------------------------------------------------------------------------------------------------------- -- constant Fsmp : real := 50.0e6; -- Sample frequency 50MHz -- constant tau : real := (0.0000125 * Fsmp); -- calculate time-constant -- constant ln2 : real := 0.69314718; -- natural log of 2 -- constant correction_factor : integer range 0 to (2**18 - 1) := integer((ln2/tau) * real(2**24)); -- decay correction weight*(2^24) -- constant correction_factor : std_logic_vector(17 downto 0) := conv_std_logic_vector(signed(148852), 18); -- constant CORRECTION_FACTOR : std_logic_vector(17 downto 0) := conv_std_logic_vector(74426, 18); -- = (ln(2)/tau) * 2^26) -- this should give a integer value of correction_factor=18607 which still fits -- within the 18bit (2^18=262144)... 2^27 is max !! signal rst_S : std_logic := '1'; signal clk_S : std_logic := '0'; signal enable_S : std_logic := '0'; signal data_in_S : std_logic_vector(WIDTH - 1 downto 0) := (others => '0'); signal program_S : std_logic := '0'; signal mwd_pwr_S : std_logic_vector(7 downto 0) := x"05"; signal diff_data_S : std_logic_vector(WIDTH - 1 downto 0) := (others => '0'); signal decay_corr_S : std_logic_vector(WIDTH - 1 downto 0) := (others => '0'); signal average_S : std_logic_vector(WIDTH - 1 downto 0) := (others => '0'); signal mult_sum_S : std_logic_vector(M_WIDTH - 1 downto 0) := (others => '0'); signal factor_S : std_logic_vector(M_WIDTH - 1 downto 0) := conv_std_logic_vector(37213, M_WIDTH); signal product36 : std_logic_vector(35 downto 0) := (others => '0'); signal data_out_S : std_logic_vector(WIDTH - 1 downto 0) := (others => '0'); ----------------------------------------------------------------------- begin rdif : window_subtractor_programmable generic map(FORWARD => true, MAX_MWD_PWR => MAX_MWD_PWR) Port map( rst => rst_S, clk => clk_S, enable => enable_S, program => program_S, window_pwr_in => mwd_pwr_S, data_in => data_in_S, data_out => diff_data_S ); mwd_sample_sum : moving_average_programmable generic map(MEM_PWR => MAX_MWD_PWR) port map( rst => rst_S, clk => clk_S, enable => enable_S, program => program_S, avg_pwr_in => mwd_pwr_S, data_in => data_in_S, data_out => average_S ); rst_S <= rst; clk_S <= clk; enable_S <= enable; mwd_pwr_S <= mwd_pwr_in; factor_S <= conv_std_logic_vector(conv_integer(correction_in), factor_S'length); program_S <= program; -- allready synced and single clock by flowcontrol data_in_S <= data_in; data_out <= data_out_S; -- program_proc : process (clk_S) -- begin -- if rising_edge(clk_S) then ---- program_S <= program; -- if (rst_S = '1') then -- mwd_pwr_S <= x"05"; -- else -- if (program = '1') then -- if (mwd_pwr_in >= 2) and (mwd_pwr_in <= 6) then -- mwd_pwr_S <= mwd_pwr_in; -- else -- mwd_pwr_S <= x"05"; -- end if; -- factor_S <= conv_std_logic_vector(conv_integer(correction_in), factor_S'length); -- end if; -- end if; -- end if; -- end process; -- all averages should be multiplied by 2^mwd_pwr (we really need a sum) but this generates overflows -- instead we take the average and map it on 18 bit then we choose the fitting correction factor mult_sum_S <= conv_std_logic_vector(conv_integer(average_S), M_WIDTH); -- READ explanation above !! decay_corr_S(15 downto 0) <= product36(35 downto 20); -- WATCH IT !! 36bits !! not 32 !! scale it down 24 bits decay_corr_S(decay_corr_S'high downto 16) <= (others => '0'); -- decay_correction_proc : process(clk_S, rst_S) begin if (clk_S'event and clk_S = '1') then if (rst_S = '1') then product36 <= (others => '0'); data_out_S <= (others => '0'); else if (enable_S = '1') then product36 <= mult_sum_S * factor_S; data_out_S <= diff_data_S + decay_corr_S; end if; end if; end if; end process; end Behavioral;