5 added files
hps-java/src/main/java/org/lcsim/hps/recon/tracking/apv25
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
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
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
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
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