Commit in hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25 on MAIN
HPSAPV25.java+553added 1.1
HPSDataProcessingModule.java+177added 1.1
HPSRTM.java+171added 1.1
HPSSVTHitDriver.java+194added 1.1
HPSSiSensorReadout.java+400added 1.1
+1495
5 added files
Initial commit - Simulation of time evolution of HPS SVT Signal

hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25
HPSAPV25.java added at 1.1
diff -N HPSAPV25.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSAPV25.java	5 Jan 2012 17:47:00 -0000	1.1
@@ -0,0 +1,553 @@
+
+package org.lcsim.hps.recon.tracking.apv25;
+
+//--- Java ---//
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+//--- org.lcsim ---//
+import org.lcsim.hps.recon.tracking.apv25.HPSAPV25.APV25Channel.APV25AnalogPipeline;
+import org.lcsim.util.aida.AIDA;
+
+//--- hps-java ---//
+import org.lcsim.hps.util.ClockSingleton;
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSAPV25.java,v 1.1 2012/01/05 17:47:00 omoreno Exp $
+ */
+public class HPSAPV25 {
+    
+    //--- APV25 parameters ---//
+    //------------------------//
+    
+    private static final double APV25_FRONT_END_GAIN = 100.0; // [mV/MIP]
+    private static final double APV25_NOISE_INTERCEPT_PEAK  =  36.0; // e- RMS
+    private static final double APV25_NOISE_INTERCEPT_DECON = 59.4; //e- RMS
+    private static final double APV25_NOISE_SLOPE_PEAK  = 246;  // e- rms/pF
+    private static final double APV25_NOISE_SLOPE_DECON = 396;  // e- rms/pF
+    
+    // Number of electron-hole pairs created by a min. ionizing particle 
+    // in 300 micrometers of Si
+    private static final int MIP = 25000;  // electron-hole pairs
+    
+    // Total number of channels ... I don't like how it is currently being
+    // implemented
+    private static final int SVT_CHANNELS = 13340;
+    
+    // Total number of channels per APV25 chip
+    private static final int APV25_CHANNELS = 128;
+   
+    // APV25 trigger bit
+    public static boolean triggerBit = false;
+    
+    // 
+    private int    apv25ShapingTime  = 35; // [ns] 
+    private String apv25Mode         = "multi-peak";
+    private int    apv25SamplingTime = 24;   // ns
+    public  int  apv25ClockCycle     = 0;
+
+    // APV25 Channel
+    private APV25Channel channel;
+
+    // Histograms
+    protected AIDA aida = AIDA.defaultInstance();
+    
+    /**
+     * Constructor
+     */
+    public HPSAPV25( )
+    {
+        // Create a single instance of an APV25 channel
+        channel = new APV25Channel();
+        
+    }
+    
+    
+    //--- Methods ---//
+    //---------------//
+    
+    /**
+     * Set the APV25 shaping time
+     * 
+     * @param shapingTime : APV25 shaping time
+     */
+    public void setShapingTime(int shapingTime)
+    {
+        apv25ShapingTime = shapingTime;
+    }
+    
+    /**
+     * Set the operating mode of the APV25 to either "peak", 
+     * "deconvolution", or "multi-peak".
+     * 
+     * @param mode : APV25 operating mode 
+     */
+    public void setAPV25Mode(String mode)
+    {
+        apv25Mode = mode;
+    }
+    
+    /**
+     * Set the time interval at which the shaper output is sampled
+     * 
+     * @param sampleTime : time interval
+     */
+    public void setSamplingTime(int sampleTime)
+    {
+        apv25SamplingTime = sampleTime;
+    }
+       
+    /**
+     * Return an instance of an APV25 channel. Currently, there is only a 
+     * single instance of the channel ( instead of 128 that the actual chip
+     * has).  However, the analog buffers of each channels are distinct and 
+     * are stored in a sorted map for later use.
+     *
+     * @return an instance of APV25Channel
+     */
+    public APV25Channel getChannel()
+    {
+        return channel;
+    }
+            
+    /**
+     * Inject charge into a channel and shape the signal.  The resulting 
+     * shaper signal is then sampled into the analog pipeline
+     * 
+     * @param charge   : Total charge being injected
+     * @param pipeline : Analog pipeline associated with a channel
+     */
+    public APV25AnalogPipeline injectCharge( double charge,
+                                             double noiseRMS,
+                                             APV25AnalogPipeline pipeline)
+    {
+        // Shape the injected charge
+        getChannel().shapeSignal(charge);
+        
+        // Sample the resulting shaper signal
+        return getChannel().sampleShaperSignal(pipeline, noiseRMS);
+    
+    }
+    
+    /**
+     * Increment the position of the trigger and writer pointers of all
+     * channels
+     * 
+     * @param analogPipelineMap : 
+     */
+    public void incrementAllPointerPositions( 
+            Map<Integer, APV25AnalogPipeline> analogPipelineMap )
+    {
+        // Loop through all of the channels and increment the position of
+        // all the trigger and writer pointers
+        for(Map.Entry<Integer, APV25AnalogPipeline> entry : analogPipelineMap.entrySet()){
+            entry.getValue().stepWritterPointer();
+            entry.getValue().stepTriggerPointer();
+        }
+        
+    }
+    
+    /**
+     * 
+     */
+    public int getSamplingTime()
+    {
+        return apv25SamplingTime;
+    }
+    
+        
+    /**
+     * Increment the APV25 clock cycle by one
+     */
+    public void stepAPV25Clock(){
+        apv25ClockCycle += 1;
+    }
+ 
+    /**
+     * 
+     */
+    public Map<Integer, double[]> APV25Multiplexer(
+                Map<Integer, APV25AnalogPipeline> analogPipelineMap )
+    { 
+        Map<Integer /* chip */, double[]> apv25Map 
+            = new HashMap<Integer, double[]>();
+        
+        // The address of the APV. There is only a single address for all
+        // chips 
+        double[] apv25Address = { 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0 };
+        
+        // Create the array which will contain the output format
+        double[] output = createOutputArray( apv25Address, -4.0 );
+
+        // Loop over all channels and readout the cells which the 
+        // trigger pointer points to
+        for(int channel = 1; channel <= SVT_CHANNELS; channel++ ){
+           
+            if( (channel%(APV25_CHANNELS)-1) == 0 && channel != 1 ){
+                
+                //--->
+//               System.out.println("Chip #: " + Math.floor(channel/APV25_CHANNELS) + ", channel: " + channel);
+                //--->
+                apv25Map.put((int) Math.floor(channel/APV25_CHANNELS), output);
+                output = createOutputArray(apv25Address, -4.0 );
+            }
+                    
+            // If the channel does not contain any data, move on to the next
+            // channel 
+            if(!analogPipelineMap.containsKey(channel)){
+                continue;
+            }
+            
+            output[(channel%APV25_CHANNELS + 12 )] 
+               += analogPipelineMap.get(channel).readOut()/APV25_FRONT_END_GAIN;
+        }
+                return apv25Map;
+    }
+    
+      /**
+         * 
+         */
+        private double[] createOutputArray( double[] address, double error ){
+            
+           // Create the array which will contain the output format. The array values
+            // will range from -4 microAmps to 4 microAmps.
+           double[] output = new double[141];
+           for( int index = 0; index < output.length; index++ ){
+               output[ index ] = -4.0;  // microAmps
+           }
+           
+           // Header
+           double[] header = { 4.0, 4.0, 4.0 };
+           
+           // Fill the array with the header, address and error bit and tick
+           System.arraycopy( header, 0, output, 0, 3);
+           output[ header.length + 1 ] = error;
+           System.arraycopy( address, 0, output, 4, 8);
+           output[ output.length - 1 ] = 4.0;
+
+           return output;
+        }
+        
+        //------------------------------------------//
+        //               APV25 Channel            //
+        //-----------------------------------------//
+        
+        public class APV25Channel {
+            
+            // Analog pipeline length
+            private static final int ANALOG_PIPELINE_LENGTH = 192;
+            // Analog pipeline
+            private APV25AnalogPipeline analogPipeline;
+            // Shaper signal
+            private APV25ShaperSignal shaperSignal;
+        
+            /**
+             * Constructor 
+             */
+            public APV25Channel(){} 
+
+            /**
+             * Shape the injected charge
+             * 
+             * @param charge 
+             */
+            private void shapeSignal(double charge)
+            {
+                shaperSignal = new APV25ShaperSignal(charge);
+            }
+            
+            /**
+             * Return the noise in electrons for a given strip capacitance
+             * 
+             * @param capacitance : strip capacitance in pF
+             * @return noise in electrons
+             */
+            public double computeNoise( double capacitance )
+            {
+                if( apv25Mode.equals("peak") 
+                    || apv25Mode.equals("multi-peak") ) 
+                    return APV25_NOISE_INTERCEPT_PEAK
+                       + APV25_NOISE_SLOPE_PEAK*capacitance;
+                else 
+                    return APV25_NOISE_INTERCEPT_DECON
+                       + APV25_NOISE_SLOPE_DECON*capacitance;
+            } 
+            
+            /**
+             * Sample the shaper signal and fill the analog pipeline.
+             * 
+             * @param channel : Channel number
+             */
+            private APV25AnalogPipeline sampleShaperSignal( 
+                        APV25AnalogPipeline pipeline, double noiseRMS ){
+                
+                // Set the analog pipeline corresponding to the channel
+                analogPipeline = pipeline;
+            
+                // Obtain the beam time
+                double beam_time = ClockSingleton.getTime();
+                
+                // Fill the analog pipeline starting with the cell to which 
+                // the writer pointer is pointing to.  Signals arriving within 
+                // the same bucket of length apv25SamplingTime will be shifted
+                // in time depending on when they arrive.
+                for(int cell = 0; cell < ANALOG_PIPELINE_LENGTH; cell++) {
+                
+                    // Time at which the shaper signal will be sampled
+                    int sample_time = cell*apv25SamplingTime 
+                        - ((int) beam_time)%apv25SamplingTime;
+                
+                    // Sample the shaper signal
+                    double sample 
+                       = shaperSignal.getAmplitudeAtTime(sample_time);
+                
+                    // Only add the value into the buffer if it is greater than
+                    // the noise threshold. Note that this isn't done within
+                    // the apv25, however, it will clean up the signal a bit
+                    // for simulation purposes
+                    // This should be done by the data processing module
+                    if( sample > (3*noiseRMS/MIP)*APV25_FRONT_END_GAIN) {
+                       analogPipeline.addToCell(cell, sample );
+                    }
+                }
+            
+                // Reset the overflow position
+                analogPipeline.resetOverflow();
+
+                return analogPipeline;
+            }
+            
+            //-----------------------------------//
+            //--- APV25 Shaper Signal ---//
+            //-----------------------------------//
+        
+            
+            /**
+             * 
+             */
+            private class APV25ShaperSignal {
+            
+                // Shaper signal maximum amplitude
+                private double maxAmp = 0;
+           
+                /**
+                 * Constructor
+                 * 
+                 * @param charge : input charge into the channel
+                 */
+                APV25ShaperSignal( double charge ){
+                
+                    maxAmp = (charge/MIP)*APV25_FRONT_END_GAIN;  // mV
+                    
+                    //--->
+//                    System.out.println("Maximum Amplitude: " + maxAmp);
+                    aida.histogram1D("Shaper Signal Max Amplitude", 100, 0, 500).fill(maxAmp);
+                    //--->
+                }
+  
+                /**
+                 * Get the amplitude at a time t
+                 * 
+                 * @param time : time at which the shaper signal is to be
+                 *               sampled
+                 */
+                private double getAmplitudeAtTime( double time ){
+
+                    return maxAmp*(time/apv25ShapingTime)*Math.exp( 
+                       1-(time/apv25ShapingTime));
+                }     
+            }
+            
+        
+            //-------------------------------------//
+            //---    APV25 Analog Pipeline      ---//
+            //-------------------------------------//
+            // Note that the buffer is modeled after a circular buffer
+        
+            public class APV25AnalogPipeline implements Iterable {
+          
+                private double[] pipeline;
+
+                public  int _trigger_pointer = 0;
+                public int _writer_pointer = 0;
+                int _trigger_latency = 100;
+                
+                int overflow_pos = 0;
+           
+            
+                /**
+                 * Constructor
+                 */
+                public APV25AnalogPipeline( ) {  
+                
+                    // Initialize the pipeline to the APV25 pipeline length
+                    pipeline = new double[ ANALOG_PIPELINE_LENGTH ];
+                
+                    // Initialize the position of the writter pointer to a
+                    // random position
+                    _writer_pointer 
+                       = (int)( Math.random()*( ANALOG_PIPELINE_LENGTH + 1 ));
+                
+                    // Set the position of the trigger pointer
+                    _trigger_pointer = _writer_pointer 
+                       - (int) Math.ceil(_trigger_latency/apv25SamplingTime );
+                
+                    if( _trigger_pointer < 0 ) 
+                        _trigger_pointer += ANALOG_PIPELINE_LENGTH;
+                }
+            
+                /**
+                 * Set the trigger latency
+                 * 
+                 * @param latency : trigger latency in [ns]
+                 */
+                public void setTriggerLatency( int latency ){
+                    _trigger_latency = latency;
+                }
+            
+                /**
+                 * Reset the overflow position to the beginning of the buffer
+                 */
+                public void resetOverflow( ){
+                    overflow_pos = 0;
+                }
+            
+                /**
+                 * Add a given value to the specified buffer cell
+                 * 
+                 * @param position : position of the buffer cell
+                 * @param element : value to be added at the given position
+                 */
+                private void addToCell( int position, double element ) {
+
+                    // Offset the position by the writter pointer position
+                    position += _writer_pointer;
+                
+                    // If the cell position is at the end begin writing at the 
+                    // beginning of the buffer until the trigger pointer 
+                    // position is reached
+                    if( position >= ANALOG_PIPELINE_LENGTH 
+                        && overflow_pos != _trigger_pointer ) {
+                        position = overflow_pos;
+                        overflow_pos++;
+                    } else if( position >= ANALOG_PIPELINE_LENGTH 
+                       && overflow_pos == _trigger_pointer ) return;
+                
+                    pipeline[ position ] 
+                       = pipeline[ position ] + element;                  
+                }
+            
+                /**
+                 * Clear the specified cell of all its values
+                 */
+                private void clearCell( int position ){ 
+                    pipeline[ position ] = 0;
+                }
+            
+                /**
+                 * Step the trigger pointer to the next position in the analog
+                 * pipeline
+                 */
+                private void stepTriggerPointer( ) {
+                
+                    // First clear the element to which the trigger used to 
+                    // point to of any signal information
+                    pipeline[ _trigger_pointer ] = 0;
+                
+                    // Increment the position of the trigger pointer to the next
+                    // cell in the buffer
+                    _trigger_pointer++;
+                
+                    if( _trigger_pointer >= ANALOG_PIPELINE_LENGTH ) 
+                        _trigger_pointer = 0;
+                }
+            
+                /**
+                 * Step the writer pointer to the next position in the analog
+                 * pipeline
+                 */
+                private void stepWritterPointer( ){
+                
+                    _writer_pointer++;
+                    if( _writer_pointer >= ANALOG_PIPELINE_LENGTH )
+                        _writer_pointer = 0;
+                }
+            
+                /**
+                 * 
+                 */
+                private double readOut( ){
+
+                    double pipelineValue = pipeline[ _trigger_pointer ];
+                    pipeline[ _trigger_pointer ] = 0;
+                    return pipelineValue;
+                }
+                
+                /**
+                 * 
+                 */
+                public void printAnalogPipeline()
+                {
+                    System.out.print("[ ");
+                   for(double element : pipeline ){
+                       System.out.print(element + ",");
+                   }
+                   System.out.println(" ]");
+                   System.out.println("");
+                }
+                
+                
+            
+                /**
+                 * 
+                 */
+                public Iterator<Double> iterator(){ 
+                    return new APV25AnalogPipelineIterator( );
+                }
+            
+                
+                //--------------------------------------//
+                //--- APV25 Analog Pipeline Iterator ---//
+                //--------------------------------------//
+                
+                /**
+                 * 
+                 */
+                private class APV25AnalogPipelineIterator 
+                implements Iterator<Double> {
+                
+                    private int index = 0;
+                
+                
+                    /**
+                     * Checks to see if the next element in the buffer exist
+                     */
+                    public boolean hasNext( ) {
+                        return index < ANALOG_PIPELINE_LENGTH;
+                    }
+                
+                
+                    /**
+                     * 
+                     */
+                    public Double next( ){ 
+                        if( !hasNext() ) throw new NoSuchElementException( );
+                        return pipeline[index++];
+                    }
+                
+                
+                    /**
+                     * 
+                     */
+                    public void remove( ) { 
+                        throw new UnsupportedOperationException(
+                            "Not Supported!");
+                    } 
+                }
+            }
+        }
+}

hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25
HPSDataProcessingModule.java added at 1.1
diff -N HPSDataProcessingModule.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSDataProcessingModule.java	5 Jan 2012 17:47:00 -0000	1.1
@@ -0,0 +1,177 @@
+package org.lcsim.hps.recon.tracking.apv25;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import org.lcsim.event.EventHeader;
+import org.lcsim.util.Driver;
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSDataProcessingModule.java,v 1.1 2012/01/05 17:47:00 omoreno Exp $
+ */
+public class HPSDataProcessingModule extends Driver {
+    
+    
+    SortedMap<Integer, Map<Integer, double[]>> samples;
+    Map<Integer, List<Double>> blocks;
+    
+    Integer sampleNumber = 1;
+    int numberOfSamples = 6;
+    
+    /**
+     * Constructor
+     */
+    public HPSDataProcessingModule()
+    {
+        // ... //
+        blocks = new HashMap<Integer, List<Double>>();
+        samples = new TreeMap<Integer, Map<Integer, double[]>>();
+    }
+    
+    /**
+     * 
+     */
+    public void addSample( Map<Integer, double[]> sample )
+    {
+        samples.put(sampleNumber, sample);
+       
+        //--->
+        System.out.println(this.getClass().getName() + ": Sample # " + sampleNumber + " added!");
+        //--->
+        
+        sampleNumber++;
+       
+    }
+    
+    /**
+     * 
+     */
+    
+    
+    /**
+     * 
+     */
+    public void createBlocks()
+    {
+        
+        // First iterate through all samples
+        Iterator sampleIterator = samples.keySet().iterator();
+        while(sampleIterator.hasNext()){
+
+            // Get a single sample of the APV25 output
+            Map<Integer, double[]> sample 
+               = samples.get((Integer) sampleIterator.next());
+            
+            //--->
+            System.out.println(this.getClass().getName() + ": Sample size:" + sample.size());
+            //--->
+            
+            // Loop through the avp25 digital sample
+            for(Map.Entry<Integer, double[]> entries : sample.entrySet()){
+
+                // Get the chip number minus 1
+                Integer chipN = entries.getKey();
+                
+                //--->
+//                System.out.println(this.getClass().getName() + ": Chip Number: " + chipN);
+                //--->
+                
+                double[] digitalData = entries.getValue();
+                
+                // Strip the digital sample of all header information
+                digitalData = Arrays.copyOfRange(digitalData, 12, digitalData.length-1);
+                
+                //--->
+//                System.out.println(this.getClass().getName() + ": Data Size: " + digitalData.length);
+                //--->
+                
+                // Loop through all channels and add to blocks
+                for(int index = 1; index <= digitalData.length; index++){
+
+                    int channelN = index+(chipN-1)*128;
+                    
+                    //--->
+//                    System.out.println(this.getClass().getName() + ": Channel Number: " + channelN );
+                    //--->
+                    
+                    // Check if map blocks has the channel
+                    if(!blocks.containsKey(channelN))
+                        blocks.put(channelN, new ArrayList<Double>(6));
+             
+                    List<Double> signal = blocks.get(channelN);
+                 
+                    signal.add(digitalData[index-1]);
+                                     
+                    blocks.put(channelN, signal);
+                }
+            }
+        }
+
+        //--->
+//        System.out.println(this.getClass().getName() + ": Number of blocks: " + blocks.size());
+        //--->
+        
+        //--->
+//        for(Map.Entry<Integer, List<Double>> entries : blocks.entrySet()){
+//            System.out.println(this.getClass().getName() + entries.getValue().toString());
+//        }
+        //--->
+        
+        // CLear all samples
+        samples.clear();
+        
+        // Reset the sample number
+        sampleNumber = 1;
+        
+    }
+    
+    /**
+     * 
+     */
+    public void findHits()
+    {
+        int nHits = 0;
+        
+        // Loop through all blocks
+        for(Map.Entry<Integer, List<Double>> entries : blocks.entrySet()){
+            
+            if(entries.getValue().get(3) >= 1640 ){
+                ++nHits;
+                System.out.println("Found a hit! There are now a total of " + nHits);
+            }
+            
+        }
+    }
+    
+    /**
+     * 
+     */
+    @Override
+    public void process(EventHeader event)
+    {
+        super.process(event);
+
+        // If 6 samples have been collected, block the samples together
+        // by channel
+        if(samples.size() == 6 ){
+            
+            //
+            createBlocks();
+
+            // Once blocks are created, find which blocks have a hit above
+            // threshold
+            findHits();
+            
+            // Once cuts have been applied, clear the blocks
+            blocks.clear();
+            
+        }
+    }
+}

hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25
HPSRTM.java added at 1.1
diff -N HPSRTM.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSRTM.java	5 Jan 2012 17:47:00 -0000	1.1
@@ -0,0 +1,171 @@
+
+package org.lcsim.hps.recon.tracking.apv25;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version  $Id: HPSRTM.java,v 1.1 2012/01/05 17:47:00 omoreno Exp $
+ */
+public class HPSRTM {
+    
+    private Map<Integer, double[]> analogData;
+    private Map<Integer, double[]> digitalData;
+
+    private static double INPUT_STAGE_GAIN = 2;
+    private static double RESISTOR_VALUE = 100; // Ohms
+    
+    double adcHighRef = 1000;   // mVolts
+    double adcLowRef = -1000;   // mVolts
+    double adcResolution = 0;  //bits
+    double adcVoltageResolution = 0; // Volts
+    int voltageIntervals;
+    
+    
+    /**
+     * Constructor
+     */
+    public HPSRTM(int bits)
+    {
+        // To do: In order to increase speed, HashMap should be initialized
+        // to a specified capacity
+        digitalData = new HashMap<Integer, double[]>();
+        
+        adcResolution = bits;
+        voltageIntervals = (int) Math.pow(2, bits);
+                System.out.println(voltageIntervals);
+
+        adcVoltageResolution 
+           =  (adcHighRef - adcLowRef)/voltageIntervals; // mV
+        
+        System.out.println(adcVoltageResolution);
+        
+    }
+    
+    //--- Methods ---//
+    //---------------//
+    
+    
+    /**
+     * 
+     * @param data 
+     */
+    public Map<Integer, double[]> digitize( Map<Integer, double[]> data )
+    {
+        analogData = data;
+
+        // Amplify the incoming analog signal
+        amplifySignal();
+        
+        // Loop over all apv25 analog signals and digitize them
+        for(Map.Entry<Integer, double[]> entry : analogData.entrySet()){
+            
+            // Aquire the amplified signal
+            double[] digitalSignal = entry.getValue();
+
+            // Digitize the apv25 output
+            for(int index = 0; index < digitalSignal.length; index++){
+                
+                digitalSignal[index]
+                   = Math.floor((digitalSignal[index] 
+                                    - adcLowRef)/adcVoltageResolution);
+            }
+
+            digitalData.put(entry.getKey(), digitalSignal);
+            
+//            System.out.println( "chip #: " + entry.getKey());
+//            System.out.print("[ ");
+//            for(double element : digitalSignal ){
+//                
+//                System.out.print(element + ",");
+//            }
+//            System.out.print(" ]");
+//            System.out.println("");
+        }
+
+        //--->
+        System.out.println(this.getClass().getName() + ": APV25 output has been digitized");
+        //--->
+        
+        return digitalData;
+    }
+    
+    /**
+     * 
+     */
+    public void amplifySignal()
+    {
+        
+        //--->
+        System.out.println(this.getClass().getName() + ": AmplyingSignal");
+        //--->
+        
+        // Loop over all apv25 analog data
+        for(Map.Entry<Integer, double[]> entry : analogData.entrySet() )
+        {
+            // Obtain the apv25 output
+            double[] apv25Output = entry.getValue();
+            
+            for(int index = 0; index < apv25Output.length; index++ ){
+                
+                // Convert input current to voltage
+                apv25Output[index] *= RESISTOR_VALUE;
+                
+                // Amplify the input signal
+                apv25Output[index] *= INPUT_STAGE_GAIN;
+            }
+
+            // Store the amplified APV25 output
+            analogData.put(entry.getKey(), apv25Output);
+            
+            // Loop over the array
+//            System.out.println( "chip #: " + entry.getKey());
+//            System.out.print("[ ");
+//            for(double element : signal ){
+//                
+//                System.out.print(element + ",");
+//            }
+//            System.out.print(" ]");
+//            System.out.println("");
+            
+        }
+    }
+    
+    /**
+     * 
+     */
+    public void setResolution( int bits )
+    {
+        adcResolution = bits;
+        
+ //       adcVoltageResolution 
+//           = Math.floor((adcHighRef - adcLowRef)/adcResolution)*1000;
+        
+    }
+    
+    /**
+     * 
+     */
+   public void printData()
+   {
+       
+       double[] data = digitalData.get("1");
+       System.out.println(data.length);
+       //double[] data = digitalData.get("1");
+       
+      // System.out.println("[ " + digitalData.size());
+       
+       
+//       for(double element : data )
+//       {
+//           System.out.println(element + ",");
+//       }
+       
+       System.out.println(" ]");
+   }
+    
+    
+    
+}

hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25
HPSSVTHitDriver.java added at 1.1
diff -N HPSSVTHitDriver.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSSVTHitDriver.java	5 Jan 2012 17:47:00 -0000	1.1
@@ -0,0 +1,194 @@
+
+package org.lcsim.hps.recon.tracking.apv25;
+
+
+//--- Java ---//
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+//--- org.lcsim ---//
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.IReadout;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiTrackerModule;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.SiDigitizer;
+import org.lcsim.util.Driver;
+
+
+//--- hps-java ---//
+import org.lcsim.hps.util.ClockSingleton;
+import org.lcsim.recon.tracking.digitization.sisim.config.SimTrackerHitReadoutDriver;
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSSVTHitDriver.java,v 1.1 2012/01/05 17:47:00 omoreno Exp $
+ */
+public class HPSSVTHitDriver extends Driver {
+  
+    
+    //
+    CDFSiSensorSim siSimulation;
+    HPSAPV25 apv25;
+    HPSSiSensorReadout siReadout;
+    HPSDataProcessingModule dpm;
+    
+    //
+    List<String> processPaths = new ArrayList<String>();
+    List<IDetectorElement> processDetectorElements 
+       = new ArrayList<IDetectorElement>();
+    List<String> readouts = new ArrayList<String>();
+    List<Integer> triggerTimeStamp = new ArrayList<Integer>();
+    
+    //
+    Set<SiSensor> processSensors = new HashSet<SiSensor>();
+    Set<SiTrackerModule> processModules = new HashSet<SiTrackerModule>();
+    
+    // Event number
+    int eventNumber;
+
+    /**
+     * Constructor
+     */
+    public HPSSVTHitDriver()
+    {
+        //--- Sensor Simulation ---//
+        //-------------------------//
+        siSimulation = new CDFSiSensorSim();
+    
+        //--- APV25 Simulation ---//
+        //------------------------//
+        apv25 = new HPSAPV25( );
+        // Set the APV25 Shaping time [ns]
+        apv25.setShapingTime(35);
+        // Set the APV25 operating mode
+        apv25.setAPV25Mode("multi-peak");
+        // Set the APV25 analog pipeline sampling time
+        apv25.setSamplingTime(24);
+        
+        //--- HPS Data Processing Module ---//
+        //----------------------------------//
+        dpm = new HPSDataProcessingModule();
+        add(dpm);
+        
+        //--- HPS Silicon Sensor Readout ---//
+        //-------------------//
+        siReadout = new HPSSiSensorReadout(siSimulation, apv25, dpm);
+        
+        //Specify the readouts to process
+        readouts.add("TrackerHits");
+        // Specify the detectors to process
+        processPaths.add("Tracker");
+    }
+    
+    /**
+     * Initialize whenever we have a new detector
+     * 
+     * @param detector : 
+     */
+    @Override
+    public void detectorChanged(Detector detector)
+    {
+        super.detectorChanged(detector);
+        
+        // Proces detectors specified by path, otherwise process the entire
+        // detector
+        IDetectorElement detectorElement = detector.getDetectorElement();
+        for(String detectorElementPath : processPaths ){
+            processDetectorElements.add(
+               detectorElement.findDetectorElement(detectorElementPath));
+        }
+        
+        if(processDetectorElements.isEmpty()) 
+            processDetectorElements.add(detectorElement);
+        
+        for(IDetectorElement dElement : processDetectorElements ){
+            processSensors.addAll(dElement.findDescendants(SiSensor.class));
+            processModules.addAll(
+               dElement.findDescendants(SiTrackerModule.class));
+        }
+    }
+    
+    /**
+     * 
+     */
+    @Override
+    public void startOfData()
+    {
+        // Set up readouts if they haven't been set
+        if(!readouts.isEmpty()){
+            super.add(new SimTrackerHitReadoutDriver(readouts));
+        }
+        
+        super.startOfData();
+        readouts.clear();
+        
+        eventNumber = 1;
+    }
+    
+    
+    /**
+     * 
+     */
+    @Override
+    public void process(EventHeader event)
+    {
+        super.process(event);
+     
+        // Output event number
+//        if( eventNumber%100 == 0){
+//            System.out.println("Now processing event " + eventNumber);
+//        }
+        
+        // This should be moved to clock singleton ... 
+        // If a sampling cycle has passed, increment the pointer positions of 
+        // all existing analog pipelines
+        if(ClockSingleton.getTime()%24 == 0 && eventNumber != 1){
+            apv25.incrementAllPointerPositions( 
+               HPSSiSensorReadout.analogPipelineMap );
+            apv25.stepAPV25Clock();
+        }
+        
+        // Increment the event number
+        ++eventNumber;
+        
+        // Loop over all sensors
+        for( SiSensor sensor : processSensors ){
+
+            // Readout the sensor
+            siReadout.readoutSensor(sensor);
+        }
+        
+        // If a trigger is recieved readout the APV25 and digitize all hits
+        if(HPSAPV25.triggerBit){
+            for(int sample = 0; sample < 6; sample++){
+                if(!triggerTimeStamp.contains(apv25.apv25ClockCycle + sample)){
+                    triggerTimeStamp.add(apv25.apv25ClockCycle + sample);
+                    //--->
+                    System.out.println(triggerTimeStamp.toString());
+                    //--->
+                }
+            }
+            HPSAPV25.triggerBit = false;
+        }
+        
+
+        
+        if(!triggerTimeStamp.isEmpty()){
+            if(triggerTimeStamp.contains(apv25.apv25ClockCycle)){
+                siReadout.readoutAPV25();
+                triggerTimeStamp.remove((Integer) apv25.apv25ClockCycle);
+                //--->
+                System.out.println(triggerTimeStamp.toString());
+                //--->
+            }
+        }
+    }
+}

hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25
HPSSiSensorReadout.java added at 1.1
diff -N HPSSiSensorReadout.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSSiSensorReadout.java	5 Jan 2012 17:47:00 -0000	1.1
@@ -0,0 +1,400 @@
+
+package org.lcsim.hps.recon.tracking.apv25;
+
+//--- Java ---//
+import hep.aida.ref.histogram.Profile1D;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+
+//--- apache ---//
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.distribution.BinomialDistribution;
+import org.apache.commons.math.distribution.BinomialDistributionImpl;
+import org.apache.commons.math.distribution.NormalDistribution;
+import org.apache.commons.math.distribution.NormalDistributionImpl;
+
+
+//--- org.lcsim ---//
+import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.math.probability.Erf;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeData;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeDataCollection;
+import org.lcsim.recon.tracking.digitization.sisim.SiSensorSim;
+import org.lcsim.util.aida.AIDA;
+
+//--- hps-java ---//
+import org.lcsim.hps.recon.tracking.apv25.HPSAPV25.APV25Channel.APV25AnalogPipeline;
+
+
+
+/**
+ *
+ * @author Omar Moreno <[log in to unmask]>
+ * @version $Id: HPSSiSensorReadout.java,v 1.1 2012/01/05 17:47:00 omoreno Exp $
+ */
+public class HPSSiSensorReadout {
+    
+    // # of strips per Si sensor
+    private static final int STRIPS_PER_SENSOR = 667;
+    
+    private HPSAPV25 apv25;
+    private SiSensorSim siSimulation;
+    private HPSRTM rtm;
+    private HPSDataProcessingModule dpm;
+    
+    private static Random random = new Random();
+    private static BinomialDistribution binomial 
+       = new BinomialDistributionImpl(1,1); 
+    private static NormalDistribution gaussian
+       = new NormalDistributionImpl(0.0,1.0);
+    
+    
+    private double noiseThreshold = 4;  // e- RMS
+    
+    // Initialize the map which will be used to associate a channel to 
+    // its respective analog pipeline.  The key value is determined using
+    // the following
+    //        sensorId*(# of strips per sensor) + channel number
+    public static Map<Integer /* channel */, 
+                      APV25AnalogPipeline> analogPipelineMap 
+       = new HashMap<Integer, APV25AnalogPipeline>();
+
+    //
+    public Map<Integer, double[]> analogData;
+    public Map<Integer, double[]> digitalData;
+    
+    //
+    protected AIDA aida = AIDA.defaultInstance();
+    public Profile1D pipe;
+    
+    
+    /**
+     * Constructor
+     */
+    public HPSSiSensorReadout(SiSensorSim siliconSimulation,
+                              HPSAPV25 apv,
+                              HPSDataProcessingModule datapm  )
+    {
+        // Set the sensor simulation
+        siSimulation = siliconSimulation;
+        
+        // Set the APV25 simulation
+        apv25 = apv;
+        
+        
+        // 
+        rtm = new HPSRTM(14);
+        
+        // Set the data processing module
+        dpm = datapm;
+        
+//        pipe = (Profile1D) aida.histogramFactory().createProfile1D("pipeline", 192, 0, 191);    
+    }
+    
+    /**
+     * 
+     * @param sensor 
+     */
+    public void makeRawHits(SiSensor sensor)
+    {
+        readoutSensor(sensor);
+    }
+    
+    /**
+     * 
+     */
+    public void readoutSensor(SiSensor sensor)
+    {
+        // Set the sensor to be used for the charge deposition simulation
+        siSimulation.setSensor(sensor);
+        // Perform the charge deposition simulation
+        Map<ChargeCarrier, SiElectrodeDataCollection> electrodeDataMap
+           = siSimulation.computeElectrodeData();
+        
+        // Loop over each charge carrier (electron or hole)
+        for(ChargeCarrier carrier : ChargeCarrier.values()){
+            
+            // If the sensor is capable of collecting the given charge carrier
+            // then obtain the electrode data for the sensor
+            if(sensor.hasElectrodesOnSide(carrier))
+            {   
+                SiElectrodeDataCollection electrodeDataCol 
+                   = electrodeDataMap.get(carrier);
+                
+                // If there is no electrode data available create a new 
+                // instance of electode data
+                if(electrodeDataCol == null){
+                    electrodeDataCol = new SiElectrodeDataCollection();
+                }
+                
+                // Obtain the electrodes to be readout
+                SiSensorElectrodes readoutElectrodes
+                   = sensor.getReadoutElectrodes(carrier);
+                
+                // Add noise hits to the electrodes
+                addNoise(electrodeDataCol, readoutElectrodes);
+                
+                // Loop over all channels
+                for(Integer channel : electrodeDataCol.keySet()){
+                   
+                    // Get the electrode data for this channel
+                    SiElectrodeData electrodeData 
+                       = electrodeDataCol.get(channel);
+                   
+                    // Get the charge in units of electrons
+                    double charge = electrodeData.getCharge();
+                    
+                    //---> Histogram <---//
+                    aida.histogram1D("Charge", 100,0 ,200000).fill(charge);
+                    
+                    // Get the RMS noise for this channel
+                    double noise 
+                       = apv25.getChannel().computeNoise(
+                            readoutElectrodes.getCapacitance(channel));
+                    
+                    // Check to see if an analog pipeline for this channel
+                    // exist.  If it doesn't, create one.
+                    Integer channelNumber
+                       = sensor.getSensorID()*STRIPS_PER_SENSOR + channel;
+                    
+                    if(!analogPipelineMap.containsKey(channelNumber)){
+                        
+                        //--->
+//                        System.out.println(this.getClass().getName() + ": Creating Pipeline for channel " + channelNumber.toString());
+                        //--->
+                        
+                        analogPipelineMap.put(channelNumber, 
+                           apv25.getChannel().new APV25AnalogPipeline());
+                    }
+                    
+                    //--->
+//                    System.out.println(this.getClass().getName() + ": The Channel Number is: " + channelNumber);
+                    //--->
+
+                    // Get the analog pipeline associated with this channel
+                    APV25AnalogPipeline pipeline 
+                       = analogPipelineMap.get(channelNumber);
+                    
+//                    System.out.println(this.getClass().getName() + ": Analog Map Size: " + analogPipelineMap.size());
+                    
+                    // Inject the charge into the APV25 amplifier chain
+                    pipeline = apv25.injectCharge(charge, noise, pipeline);
+                    // Store the analog pipeline for later use
+                    analogPipelineMap.put(channelNumber, pipeline);
+                   
+
+                    //----> 
+//                    if(channelKey.equals("5")){
+//                        Iterator<Double> pipelineIterator = pipeline.iterator();
+//                        int index = 0;
+//                        
+//                        //pipe = (Profile1D) aida.histogramFactory().createProfile1D("pipeline", 192, 0, 191);
+//                        
+//                       // pipeline.printAnalogPipeline();
+//                        while(pipelineIterator.hasNext()){
+//                                                             
+//                            pipe.fill(index, pipelineIterator.next());
+//                            index++;
+//                        }
+//                        index = 0;
+//                        
+//                    }
+                    //---->
+                }
+            }   
+        }
+        
+        siSimulation.clearReadout();
+    }
+    
+    /**
+     * 
+     */
+    public void readoutAPV25()
+    {
+        // Readout all apv25's
+        analogData 
+           = apv25.APV25Multiplexer(HPSSiSensorReadout.analogPipelineMap); 
+   
+        //--->
+        System.out.println(this.getClass().getName() + " : Analog Data Size: " + analogData.size());
+        //--->
+        
+       // Digitize all signals
+       digitalData = rtm.digitize(analogData);
+
+       // Buffer the samples for further processing
+       dpm.addSample(digitalData);
+       
+    }
+    
+    
+    /**
+     * 
+     * @param electrodeDataCol
+     * @param electrodes 
+     */
+    public void addNoise(SiElectrodeDataCollection electrodeDataCol, 
+                         SiSensorElectrodes electrodes)
+    {
+        // First add readout noise to the strips in the 
+        // SiElectrodeDataCollection.
+        
+        // Loop over the entries in the SiElectrodeDataCollection
+        for(Entry electrodeDatum : electrodeDataCol.entrySet()){
+            
+            // Get the channel number and electrode data for this entry
+            int channel = (Integer) electrodeDatum.getKey();
+            SiElectrodeData electrodeData 
+               = (SiElectrodeData) electrodeDatum.getValue();
+            
+            // Get the RMS noise for this channel in units of electrons
+            double noise 
+               = apv25.getChannel().computeNoise(
+                    electrodes.getCapacitance(channel));
+           
+            // Add readout noise to the deposited charge
+            int noiseCharge = (int) Math.round( random.nextGaussian()*noise);
+            electrodeData.addCharge(noiseCharge);
+        }
+        
+        // Find the number of strips that are not currently hit
+        int nElectrodes = electrodes.getNCells();
+        int nElectrodesEmpty = nElectrodes - electrodeDataCol.size();
+        
+        // Get the noise threshold in units of the noise charge
+
+        // Calculate how many channels should get noise hits
+        double integral = Erf.phic(noiseThreshold);
+        int nChannelsThrow = drawBinomial(nElectrodesEmpty, integral);
+        
+        // Now throw Gaussian randoms above the seed threshold and put signals
+        // on unoccupied channels
+        for(int ithrow = 0; ithrow < nChannelsThrow; ithrow++)
+        {
+            // Throw to get a channel number
+            int channel = random.nextInt(nElectrodes);
+            while(electrodeDataCol.keySet().contains(channel)){
+                channel = random.nextInt(nElectrodes);
+            }
+        
+            // Calculate the noise for this channel in units of electrons
+            double noise 
+               = apv25.getChannel().computeNoise(
+                    electrodes.getCapacitance(channel));
+        
+            // Throw Gaussian above threshold
+            int charge 
+               = (int) Math.round(drawGaussianAboveThreshold(integral)*noise);
+            
+            // Add the noise hit to the electrode data collection
+            electrodeDataCol.add(channel, new SiElectrodeData(charge));
+        }
+        
+        // Now throw to lower threshold on channels that neighbor hits until
+        // we are exhausted
+        
+        nChannelsThrow = 1;
+        while(nChannelsThrow > 0){
+            
+            // Get neighbor channels
+            Set<Integer> neighbors = new HashSet<Integer>();
+            for(int channel : electrodeDataCol.keySet())
+            {
+                neighbors.addAll(electrodes.getNearestNeighborCells(channel));
+            }
+            neighbors.removeAll(electrodeDataCol.keySet());
+            
+            nElectrodesEmpty = neighbors.size();
+            
+            integral = Erf.phic(noiseThreshold);
+            nChannelsThrow = drawBinomial(nElectrodesEmpty, integral);
+            
+            // Now throw Gaussian randoms above a threshold and put signals on
+            // unoccopied channels
+            for(int ithrow = 0; ithrow < nChannelsThrow; ithrow++)
+            {
+            
+                // Throw to get a channel number
+                List<Integer> neighborList = new ArrayList<Integer>(neighbors);
+
+                int channel 
+                   = neighborList.get(random.nextInt(nElectrodesEmpty));
+            
+                while(electrodeDataCol.keySet().contains(channel)){
+                    channel 
+                       = neighborList.get(random.nextInt(nElectrodesEmpty));
+            
+                }
+                
+                // Calculate the noise for this channel in units of electrons
+                double noise 
+                   = apv25.getChannel().computeNoise(
+                        electrodes.getCapacitance(channel));
+        
+                // Throw Gaussian above threshold
+                int charge 
+                   = (int) 
+                        Math.round(drawGaussianAboveThreshold(integral)*noise);
+            
+                // Add the noise hit to the electrode data collection
+                electrodeDataCol.add(channel, new SiElectrodeData(charge));
+            }
+        }
+    }
+    
+    /**
+     * 
+     */
+      public static int drawBinomial(int ntrials, double probability)
+    {
+        binomial.setNumberOfTrials(ntrials);
+        binomial.setProbabilityOfSuccess(probability);
+
+        int nsuccess = 0;
+        try
+        {
+            nsuccess = binomial.inverseCumulativeProbability(random.nextDouble());
+        } catch (MathException exception)
+        {
+            throw new RuntimeException("APV25 failed to calculate inverse cumulative probability of binomial!");
+        }
+        return nsuccess;
+    }
+      
+      
+      /**
+       * Return a random variable following normal distribution, but beyond
+       * threshold provided during initialization.
+       */
+    public static double drawGaussianAboveThreshold(double prob_above_threshold)
+    {
+        double draw, cumulative_probability;
+
+        draw = prob_above_threshold * random.nextDouble();
+        cumulative_probability = 1.0 - prob_above_threshold + draw;
+
+        assert cumulative_probability < 1.0 : "cumulProb=" + cumulative_probability + ", draw=" + draw + ", probAboveThreshold=" + prob_above_threshold;
+        assert cumulative_probability >= 0.0 : "cumulProb=" + cumulative_probability + ", draw=" + draw + ", probAboveThreshold=" + prob_above_threshold;
+
+        double gaussian_random = 0;
+        try
+        {
+            gaussian_random = gaussian.inverseCumulativeProbability(cumulative_probability);
+        } catch (MathException e)
+        {
+            System.out.println("MathException caught: " + e);
+        }
+
+        return gaussian_random;
+    }
+
+}
CVSspam 0.2.12


Use REPLY-ALL to reply to list

To unsubscribe from the LCD-CVS list, click the following link:
https://listserv.slac.stanford.edu/cgi-bin/wa?SUBED1=LCD-CVS&A=1