-- Tyler Lutz; July 26, 2011; -- Constant Fraction Timing Discriminator; --Input->digital signal from ASIC, time from onboard clock; --Output->calculated time of arrival of pulse based on intersection of an attenuated version of the pulse (to 30%) and a delayed version of the same pulse; ------------------------------------------------------------------------- --((o))--((o))--((o))--((o))--((o))--((o))--((o))--((o))--((o))--((o))-- ------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; entity fitting_etc_CFD is port( pulse: in std_logic_vector (0 to 11); --assumed that ASIC readout is in parallel(?), and if not it is easy to parallelize serial input clk: in std_logic; OCFD: out std_logic_vector (0 to 11); --Output for constant fraction discrimination timing calculation OTEST: out std_logic_vector (0 to 11); --for simulating miscellaneous calculations end fitting_etc_CFD; -- ==I==I==I==I==I==I==I==I==I==I==I== -- architecture Herjolfssen7 of fitting_etc_CFD is begin process(clk) variable accsec: integer :=0; --"seconds" or any other arbitrary time unit, to be adjusted based on the frequency of clock used. type gaul is array(natural range <>) of integer; --define unconstrained array type variable pulsebit: gaul (0 to 11); --pulse is converted later to an integer for calculation purposes; this is an intermediate step variable multithreshold: gaul (0 to 2); --stores our three constant threshold values for the multithresh mode variable pulsar: integer:=0; -- intergized value of incoming pulse constant savescope: integer:=100; --scope size of CFD delay memory and base line averager (here, last 1000 data points) variable pulsarsave: gaul (0 to savescope+4); --allows us to delay the pulse (the 10^10 is totally arbitrary) variable letop: integer:=0; constant delay: integer:=4; --delay length for CFD (150-200 ps = 4 using our clock specs (see testbench)) variable eventprint: gaul (0 to 4); --array output, listing arrival time against event number variable eventprintread: gaul (0 to 3); --"scratchpaper" variable variable inhibit_cfd: integer:=0; --ditto -- ==I==I==I==I==I==I==I==I==I==I==I== -- begin if clk'event and clk='1' then --program loops at clock rising edge letop:=(letop+1)mod 50;--1000000; --slow down clock to 10MHz if letop=0 then accsec:=(accsec+1) mod 2**12; --our stopwatch --our oscilloscope data is converted to decimal stored in 'pulsar': for j in 0 to 11 loop -- intigerizing the input pulse; logic vector to binary array to integer(pulsar) if pulse(j)='0' then pulsebit(j):=1; --binary array elsif pulse(j)='1' then pulsebit(j):=0; end if; if j=0 then pulsar:=pulsebit(0); --a clever way to reinitialize the summand 'pulsar' else pulsar:= pulsar+(pulsebit(j))*(2**(j)); --actual binary to integer conversion end if; end loop; multithreshold(0):=11; --specify desired threshold values for multithreshold claculations multithreshold(1):=14; multithreshold(2):=17; if (pulsarmultithreshold(0)) and inhibit_cfd=0 then --first threshold "arms" the Constant Fraction Discrimination calculation -- multiply by ten to reduce truncation error if (((-30*pulsar/10+10*pulsarsave(delay)) > 0)) then --and ((-30*pulsarsave(1)/10+10*pulsarsave((delay+1))) < 0)) then --pulse attenuated to 30% (=3/10), inverted, and added to the delayed pulse ('delay' indicates length of delay, to be adjusted based on actual clock freq) eventprint(3):=accsec-delay; --time of zerocrossing recorded (delay time subtracted) inhibit_cfd:=1; end loop; end if; end if; -- _/__/___/____/_____/______/_______/________/_________/__________/___________/____________/_____________/______________/_______________/ tester:=eventprint(3); for v in 11 downto 0 loop --readout in parallel if tester>=(2**v) then OCFD(v)<='1'; tester:=tester -2**v; else OCFD(v)<='0'; end if; end loop; end if; end if; end process; end Herjolfssen7;