lcsim/src/org/lcsim/recon/vertexing/pixsim
diff -N FastAnalogElectronics.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ FastAnalogElectronics.java 10 Feb 2011 22:29:51 -0000 1.1
@@ -0,0 +1,349 @@
+package org.lcsim.recon.vertexing.pixsim;
+import java.util.*;
+import org.lcsim.event.*;
+import org.lcsim.event.base.*;
+
+
+/**
+ * @author Nick Sinev
+ */
+
+public class FastAnalogElectronics extends BasePixelElectronics
+{
+ int window = 1; // sensitive window expressed in clock intervals
+ int reset_int = 1; // number of BC between resets. Charge between resets is accumulated.
+
+ public FastAnalogElectronics()
+ {
+ this(IlcOption.NOMINAL);
+ }
+
+ public FastAnalogElectronics(IlcOption opt)
+ {
+ super();
+ name="FastAnalogElectronics";
+ option = opt;
+ if(option == IlcOption.SHORT_INT)
+ {
+ bunch_interval = cons.BunchIntervalA;
+ n_bunches = cons.NumberOfBunchesInTrainA;
+ }
+ if(option == IlcOption.LONG_INT)
+ {
+ bunch_interval = cons.BunchIntervalB;
+ n_bunches = cons.NumberOfBunchesInTrainB;
+ }
+ if(option == IlcOption.CLIC)
+ {
+ bunch_interval = cons.BunchIntervalC;
+ n_bunches = cons.NumberOfBunchesInTrainC;
+ window=n_bunches;
+ reset_int=window;
+ }
+ bunch_per_clock = 1;
+ clocks_per_bunch = 1;
+ clock_period = bunch_interval * bunch_per_clock;
+ useCDS = false;
+ addNoiseHits = false;
+ read_during_train = true;
+ }
+
+ int n_buffers = 1;
+ double train_duration = n_bunches * bunch_interval;
+ double bandwidth = 1.E7; // comparator bandwidth - define how many noise samples per second will be generated.
+
+
+ public void processSensor(IPixilatedSensor sens, int bc)
+ {
+ boolean sdebug = ((PixilatedSensor) sens).ddebug;
+ int acc_strt = bc-1;
+ int acc_end = bc+window;
+ if(bunch_per_clock > 1)
+ {
+ acc_strt = (int) Math.floor((double)(bc-1)/(double) bunch_per_clock);
+ acc_end = (int) Math.floor((double)(bc)/(double) bunch_per_clock) + window;
+ clock_period = bunch_interval * bunch_per_clock;
+ }
+ if(clocks_per_bunch > 1)
+ {
+ acc_strt = bc*clocks_per_bunch - 1;
+ acc_end = bc*clocks_per_bunch + window;
+ clock_period = bunch_interval/clocks_per_bunch;
+ }
+ int snr = sens.getNRows();
+ int snc = sens.getNColumns();
+ int nars = 0;
+ if(addNoiseHits) generateNoise(sens);
+ List<ActivePixel> sens_pixs = sens.getActivePixels();
+ for(ActivePixel pix:sens_pixs)
+ {
+ double dtf = 0.;
+ boolean first = true;
+ int prow = (int) (pix.row);
+ int pcol = (int) (pix.column);
+ int[] tstmps = new int[n_buffers];
+ int[] aadc = new int[n_buffers];
+ ResetInterval[] fri = new ResetInterval[n_buffers];
+ int buf = 0;
+ int acharge = 0;
+ List<ChargeTrain> ctrains = pix.getChargeTrains();
+ List<SimTrackerHit> simhits = new ArrayList<SimTrackerHit>();
+ int min_bc=n_bunches;
+ int max_bc = 0;
+ for(ChargeTrain ct:ctrains)
+ {
+ int ctbc = ct.getBeamCrossing();
+ if(ctbc < min_bc) min_bc=ctbc;
+ if(ctbc > max_bc) max_bc=ctbc;
+ double dt = ct.getTimeBin();
+ if(first)
+ {
+ dtf = dt;
+ first = false;
+ if(dt < 0.1e-10) System.out.println("Time bin in charge train is too small! :"+dt);
+ }
+ if(Math.abs(1. - dtf/dt) > 1.e-6)
+ {
+ System.out.println("Non-equal time bins in charge trains! Correct it!");
+ return;
+ }
+ } //end for(ChargeTrain ct:ctrains)
+ List<NoiseHit> n_hits = pix.noise_hits;
+ int nnhts = 0;
+ if((n_hits != null) && (!first))
+ {
+ nnhts = n_hits.size();
+ for(NoiseHit nh:n_hits)
+ {
+ int nbc = (int) Math.floor(nh.getTime()/bunch_interval);
+ if(nbc < min_bc) min_bc = nbc;
+ if(nbc > max_bc) max_bc = nbc;
+ }
+ }
+ if(!first)
+ {
+ int n_bns_pri = (int) Math.floor((reset_int*bunch_interval)/dtf) + 1;
+ if(n_bns_pri < 1)
+ System.out.println("n_bns_pri="+n_bns_pri+" from reset_int="+reset_int+" and bunch_int="+bunch_interval+"with dtf="+dtf);
+ Vector actrsts = new Vector();
+ for(int i=min_bc; i<max_bc+1; i++)
+ {
+ if(i%reset_int == 0)
+ {
+ boolean active = false;
+ ResetInterval ari = null;
+ double strtri = i*bunch_interval;
+ double endri = (i+reset_int)*bunch_interval;
+ for(ChargeTrain ct:ctrains)
+ {
+ double strttr = ct.getBeamCrossing() * bunch_interval;
+ double endtr = strttr + ct.getCharge().length * dtf;
+ if(((strttr >= strtri) && (strttr < endri)) || ((endtr >= strtri) && (endtr < endri))) active=true;
+ if(((strtri >= strttr) && (strtri < endtr)) || ((endri >= strttr) && (endri < endtr))) active=true;
+ }
+ if(active) ari= new ResetInterval(i,n_bns_pri);
+ if(n_hits != null)
+ {
+ for(NoiseHit nh:n_hits)
+ {
+ double nht = nh.getTime();
+ if((nht >= strtri) && (nht < endri))
+ {
+ if(ari != null) ari.addNoiseHit(nh);
+ else
+ {
+ ari = new ResetInterval(i,n_bns_pri);
+ ari.addNoiseHit(nh);
+ }
+ }
+ }
+ }
+ if(ari != null) actrsts.addElement(ari);
+ }
+ } // end for(int i=min_bc; i<max_bc+1; i++)
+ int narsts = actrsts.size();
+ for(int i=0; i<narsts; i++)
+ {
+ ResetInterval ari = (ResetInterval) actrsts.get(i);
+ int rbc = ari.getBunchCrossing();
+ double strtri = rbc*bunch_interval;
+ double endri = (rbc+reset_int)*bunch_interval;
+ for(ChargeTrain ct:ctrains)
+ {
+ boolean active = false;
+ double strttr = ct.getBeamCrossing() * bunch_interval;
+ double endtr = strttr + ct.getCharge().length * dtf;
+ if(((strttr >= strtri) && (strttr < endri)) || ((endtr >= strtri) && (endtr < endri))) active=true;
+ if(((strtri >= strttr) && (strtri < endtr)) || ((endri >= strttr) && (endri < endtr))) active=true;
+ if(active)
+ {
+ short[] chbns = ct.getCharge();
+ SimTrackerHit shit = ct.getSimTrackerHit();
+ ari.addSimHit(shit);
+ double toff = strttr - strtri;
+ int boff = (int) Math.floor(toff/dtf);
+ for(int j=0; j<chbns.length; j++)
+ {
+ int k = j+boff;
+ if((k>=0) && (k<n_bns_pri)) ari.addCharge(chbns[j],k);
+ }
+ }
+ }
+ } // end for(int i=0; i<narsts; i++)
+ for(int i=0; i<narsts; i++)
+ {
+ ResetInterval ari = (ResetInterval) actrsts.get(i);
+ int rbc = ari.getBunchCrossing();
+ double strtri = rbc*bunch_interval;
+ double endri = (rbc+reset_int)*bunch_interval;
+ List<NoiseHit> no_hts = ari.getNoiseHits();
+ nnhts = no_hts.size();
+ int[] nht_bns = null;
+ double tf = 0.;
+ if(nnhts > 0)
+ {
+ nht_bns=new int[nnhts];
+ for(int j=0; j<nnhts; j++)
+ {
+ tf = no_hts.get(j).getTime()-strtri;
+ nht_bns[j]=(int) Math.floor(tf/dtf);
+ }
+ }
+ boolean fired = false;
+ int act_thr = (int) (pixel_threshold * adc_scale + noise_level * rnd.nextGaussian());
+ int asig = 0;
+ int[] chacc = ari.getCharge();
+ for(int j=0; j<chacc.length; j++)
+ {
+ if(nnhts > 0)
+ {
+ for(int k=0; k<nnhts; k++)
+ {
+ if(j==nht_bns[k])
+ {
+ tf = strtri + j*dtf;
+ if(buf<n_buffers)
+ {
+ int tstm = (int) Math.floor(tf/clock_period);
+ tstmps[buf]=tstm;
+ fri[buf] = ari;
+ buf++;
+ }
+ }
+ }
+ }
+ asig+=chacc[j];
+ if(!fired && (asig >= act_thr))
+ {
+ fired=true;
+ tf = strtri + j*dtf+dtf*((double)(act_thr-asig+chacc[j])/(double)chacc[j]);
+ if(buf<n_buffers)
+ {
+ int tstm = (int) Math.floor(tf/clock_period);
+// System.out.println("tf= "+tf+" tstm="+tstm+" asig="+asig+" chacc[j]="+chacc[j]);
+ tstmps[buf]=tstm;
+ fri[buf]=ari;
+ buf++;
+ }
+ }
+ } // end for(int j=0; j<chacc.length; j++)
+ double sig = (double) asig + noise_level * rnd.nextGaussian();
+ if(buf > 0) aadc[buf-1] = (int) (Math.floor(sig/adc_scale));
+ } // for(int i=0; i<narsts; i++)
+ }
+ for(int i=0; i<buf; i++)
+ {
+ int tstm = tstmps[i];
+ ResetInterval ari = fri[i];
+ if((tstm>=acc_strt) && (tstm <= acc_end))
+ {
+ short[] adc = new short[3];
+ adc[0]=(short) aadc[i];
+ adc[1]=(short) (tstm>>16);
+ adc[2]=(short) (tstm & 0x7fff);
+ long cellid = sens.getCellID(prow,pcol);
+ RawTrackerHit rhit = new BaseRawTrackerHit(bc,cellid,adc,ari.getSimHits(),sens.getParent());
+ sens.addRawHit(rhit);
+ }
+ }
+ } // end for(ActivePixel pix:sens_pixs)
+ } // end function processSensor(IPixilatedSensor sens, int bc)
+
+
+ private void generateNoise(IPixilatedSensor sens)
+ {
+ int snr = sens.getNRows();
+ int snc = sens.getNColumns();
+ int np = snc*snr;
+ double thr = pixel_threshold * adc_scale;
+ double ttnf = thr/noise_level;
+ double abtpr = erprob.getProbability(ttnf);
+ int nnhits = (int) (np * bandwidth * train_duration * abtpr);
+ System.out.println("Generating "+nnhits+" noise hits for sensor with "+np+" pixels");
+ for(int hn = 0; hn < nnhits; hn++)
+ {
+ double nht = train_duration * rnd.nextDouble();
+ short nhr = (short) Math.floor(snr * rnd.nextDouble());
+ short nhc = (short) Math.floor(snc * rnd.nextDouble());
+ int npid = ActivePixel.id(nhr,nhc);
+ boolean newap = true;
+ List<ActivePixel> pixels = sens.getActivePixels();
+ for(ActivePixel ap:pixels)
+ {
+ if(ap.ID == npid)
+ {
+ newap = false;
+ ap.addNoiseHit(new NoiseHit(nht));
+ }
+ }
+ if(newap)
+ {
+ ActivePixel nap = new ActivePixel();
+ nap.row = nhr;
+ nap.column = nhc;
+ nap.addNoiseHit(new NoiseHit(nht));
+ sens.addActivePixel(nap);
+ }
+ }
+ }
+
+ private class ResetInterval
+ {
+ int BC=0;
+ int[] charge = null;
+ List<NoiseHit> noise_hits = new ArrayList<NoiseHit>();
+ List<SimTrackerHit> simhits = new ArrayList<SimTrackerHit>();
+
+ public ResetInterval(int bc, int nbins)
+ {
+ BC = bc;
+ charge = new int[nbins];
+ for(int i=0; i<nbins; i++) charge[i]=0;
+ }
+
+ public void addCharge(short ch, int ind)
+ {
+ if((ind >=0) && (ind<charge.length)) charge[ind]+=ch;
+ }
+
+ public void addNoiseHit(NoiseHit nh)
+ {
+ noise_hits.add(nh);
+ }
+
+ public void addSimHit(SimTrackerHit sh)
+ {
+ if(!simhits.contains(sh)) simhits.add(sh);
+ }
+
+ public List<SimTrackerHit> getSimHits() { return simhits; }
+
+ public List<NoiseHit> getNoiseHits() { return noise_hits; }
+
+ public int[] getCharge() { return charge; }
+
+ public int getBunchCrossing() { return BC; }
+
+ }
+
+}