Commit in hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25 on MAIN | |||
HPSAPV25.java | +553 | added 1.1 | |
HPSDataProcessingModule.java | +177 | added 1.1 | |
HPSRTM.java | +171 | added 1.1 | |
HPSSVTHitDriver.java | +194 | added 1.1 | |
HPSSiSensorReadout.java | +400 | added 1.1 | |
+1495 |
Initial commit - Simulation of time evolution of HPS SVT Signal
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!"); + } + } + } + } +}
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(); + + } + } +}
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(" ]"); + } + + + +}
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()); + //---> + } + } + } +}
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; + } + +}
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