Proton Calorimetry/Equipment/LeCroy

From PBTWiki
Jump to navigation Jump to search

This page needs to be updated with work completed in the 2018/2019 academic year.

LeCroy Scope Trace Conversion: Binary to ASCII

To convert .trc binary data to .txt data that is formatted similarly to the output files from a CAEN DT5751 digitiser:

  1. Copy contents of /unix/pbt/aknoetze/ConversionScripts to a new directory.
  2. Open trc2txt.py in a text editor.
    1. Change path to directory containing .trc data files by editing variable dirpath
    2. Change number of decimal points for each column by editing: np.savetxt(..., fmt=‘...’,...)
  3. Run trc2txt.py

Converted .txt files will be in the copied directory NEWASCII. These new files will possess the same file names as the original .txt files.

To concatenate the new data files together into one single file, while in the directory NEWASCII,type:

cat *.txt > OutputFileName.txt


Working with LeCroy Scope Trace Files in ROOT using the LeCroyData Class

The LeCroyData class is defined in SimpleLeCroyRoutines.C, which can be found at /unix/pbt/users/dwalker/LeCroy. The class is intended for use in interactive ROOT sessions, but can be used in compiled ROOT applets. Its public methods and their use are summarised below:

Method Signature Notes Example
LeCroyData::LeCroyData(std::string fileName); Constructor for the LeCroyData class. The string fileName must be a fully qualified path from the current working directory to the LeCroy binary format file to be loaded.

//Instantiating a new LeCroyData object

LeCroyData* lcd = new LeCroyData("../data/aug16/lecroy/C1Trace00000.trc");

int LeCroyData::getAcqCount(); Returns the number of acquisitions recorded in the file.

//Printing every trigger time in a LeCroy binary file

LeCroyData lcd("C1Trace00037.trc");

int n = lcd.getAcqCount();

for(int i = 0; i<n; i++){

std::cout.flush()<<lcd.getTriggerArray()[i]<<std::endl;

}

double* LeCroyData::getTriggerArray(); Returns a C-style array containing the time in ns at which each acquisition in the file was triggered, relative to the first trigger.
double* LeCroyData::getOffsetArray(); Returns a C-style array containing the time in ns between the start of each acquisition and the time of the trigger for that acquisition.
int LeCroyData::getPointsPerAcq(); Returns the number of data points (voltage / time pairs) recorded in each acquisition in the file.

//Plotting a single acquisition using ROOT's TGraph class

LeCroyData lcd("C1Trace00000.trc");

int acquisitionNumber = 0;

double* x = lcd.getAcqTime(acquisitionNumber);

double* y = lcd.getAcqWave(acquisitionNumber);

int n = lcd.getPointsPerAcq();

TGraph* gr = new TGraph(n, x, y);

gr->Draw();

double* LeCroyData::getAcqWave(int segment); Returns a C-style array of doubles. The array contains the voltages recorded by the scope in an acquisition with index "segment", which runs from zero to the number of acquisitions in the file.
double* LeCroyData::getAcqTime(int segment); Returns a C-style array of doubles. The array contains the time in ns of each data point in the acquisition indexed by "segment", relative to the trigger for that acquisition.
string LeCroyData::getTimestamp(); Returns a string describing the timestamp for the file as a date and a clock time. This time corresponds to the first trigger in the file and takes the format "d/m/yyyy @ hh:mm:ss.ssss".
double* LeCroyData::getSpectrum(); Returns a C-style array of doubles, where each entry is the ADC Counts calculated for an event.

//Create and display a histogram of the ADC Counts of pulses in a file

LeCroyData* lcd = new LeCroyData("C1Trace00000.trc");

TH1D* hist = new TH1D("hist", "LeCroyData Spectrum;ADC Counts;Number of Events", 350, 0, -1);

int n = lcd->getSpectrumSize();

double* s = lcd->getSpectrum();

for(int i = 0; i<n; i++){ hist->Fill(s[i]); }

hist->Draw();

double* LeCroyData::getSpectrumSize(); Returns the number of entries in LeCroyData::getSpectrum() (equal to the number of entries in LeCroyData::getSpectrumTime()) as an integer.
double* LeCroyData::getSpectrumTime(); Returns a C-style array of doubles, where each entry is the time in ns at which an event recorded in the spectrum occurred, with respect to the first trigger time in the file.

Additional methods are being added to handle the generation of spectra and improve access to timing data.

Log of Development in 2018/19 Academic Year

  • Created class for Caen data, and implemented methods to plot data as graphs and histograms
  • Plotted Caen data from Birmingham (26/11/18)
  • Experimented with integration parameters to plot histograms of LeCroy data from Birmingham (26/11/18)
    • Found that fixed pulse position assumption no longer entirely valid.
    • Best parameters were an offset of -120ns and a window of 150ns, with a maximum baseline sigma of 30.
    • Recovered good quality plots, however non-negligible number of entries centred around 0.
  • Updated method of loading multiple .trc files as assumption of sequentially named files is not valid. User has to input the filenames by hand given a directory.
  • Verified that writing histogram data to disk produces a list of energies and associated trigger times.
  • Updated raw and subtracted waveform plotting to correctly reflect position of trigger. Removed functionality to plot more than one pulse in favour of this, however the code to plot waveforms is now much simpler/faster.
  • Overhauled baseline subtraction method
    • Since pulse could be in anywhere within the acquisition window, we now first test the pre-trigger window, and if the baseline sigma test is failed, then the equivalent region at the end of the window is also tested before the acquisition is labelled as false.
    • Old version of code only kept the amount of the acquisition that resided in the pre-determined and constant integration window after baseline subtraction. This is no longer acceptable due to the varying position of the pulse, so after baseline subtraction, the full acquisition is stored, with a time axis that reflects the actual trigger position.
    • While more data-intensive, actual code for baseline subtraction has become simpler.
    • Maximum baseline sigma could then be restricted to 20 instead of 30.
    • Dynamic pulse location for integration
    • In attempt to solve “zero error”, implemented a method that searches each subtracted acquisition for the peak of the pulse, and then integrates 20ns before it, for the integration window specified by the user.
    • User now does not need to guess the integration offset relative to the trigger, but the code is probably slightly slower due to the extra looping over the dataset.
    • This did not appear to solve the “zero error” – suspected that such acquisitions simply contained no pulses. Need to plot raw waveform of such an acquisition to verify.
  • Zero Error Testing
    • By printing out the indices of pulses that produced negative energy (the erroneous events follow a Gaussian around zero, hence some integrals were negative), erroneous event waveforms were plotted.
    • It was found that such events simply had no pulse in them, the plots revealed only dark current/noise.
    • Implemented a method alongside baseline testing to also check if a negative value of pd was recorded in the pre-subtracted waveform, since dark current/noise takes distinctly positive values.
    • Now an acquisition must have a distinct region of dark current, and have recorded a negative value of pd in order to be labelled as “good”.
    • This fixed the zero error.
    • This has made the baseline test method clunkier, so the method could potentially use some refinement.
  • It’s possibly been found that in the messier data, the code outperforms the digitiser by filtering out sufficient pileup to produce cleaner peaks.
  • Each file typically labels ~10% of acquisitions as “bad”.
  • Moved good acquisition check to the plotting stage, such that bad acquisitions will also have an integral and be written to disk as well. This is to preserve the 1:1 ratio of tracker and calorimeter data.
  • Implemented method to plot Caen and LeCroy data onto same graph. By finding the ADC count with the highest frequency for both Caen and LeCroy data, scaling factors for the x and y axis were found. The Caen data was scaled and plot with the LeCroy data, giving an excellent match.
  • Improved ADC spectra of LeCroy by shortening the region over where the baseline sigma was evaluated (from 9/10 to 8/10), to reduce the chances of the pulse interfering with the calculation. This allowed for the maximum baseline sigma to be reduced from 20 to 5, giving a spectrum closer to that of the Caen ADC, with less noise and a similar number of acquisitions being labelled as “bad”.
  • It seems as though most pulses arrive at around -120ns. If so, and if the first baseline test is passed, any acquisitions with extra pulses towards the end of the acquisition will be labelled as good.
  • Wrote code to load and plot tracker data in a 2D histogram.
  • Added labels of good/bad acquisitions to text file output of LeCroy data.
  • Matched good LeCroy acquisitions and good tracker hits by matching LeCroy events to tracker events within a threshold of 500 + 3.42E-6*trackerTime. Needed a shifting threshold due to the clocks shifting further out of alignment.
  • Wrote code to output a list of matched event coordinates in X, Y, E space to a text file.
  • Wrote code to make 3D histograms of spatial hit distributions: XY, XE, YE. Expected results seen but need to work out how to create 4D plots (X, Y, E, Counts).
  • Initial attempt to match Caen and LeCroy energy spectra by minimisation of chi-square: Y-scale calculated as before, but an X-shift calculated by the smallest Chi-Square given in a certain range. Result was not a close match – need an X-scale not an X-shift.
  • Improved Chi-Square method by using approximate x scale factor, and then testing scale factors in re-binned Caen data +- 0.5% of the approximate factor in 0.1% steps, choosing the scale factor that gives the smallest chi-square.
  • Tested on all runs: some gave no change to the approximate scale factor, but some gave a small change of ~0.003.
  • The best chi-square is dependant on binning. Choose bin number to give an integer value within x-range. Instead of 500 bins, 550 bins were chosen for an x-range of 2200. Sets precedent for number of bins to choose.
  • Extended range to +- 1.5% in steps of 0.05% to improve resolution and because some chi-squares didn’t quite minimise previously. Typically takes 6-7 mins to complete.
  • After testing all runs with the extended test range, the average x scale factor was found to be:
  • Wrote code to calculate the y-scale factor by comparing the number of events in a specific range around the peak. Could not explain factor of 4 difference in the returned y-scale value.
  • Investigated a routine to find y-scale using a chi-square minimisation, however this was not possible. To evaluate the chi-square, one requires the comparison between two histograms with the same number of bins. However, the number of bins chosen affects the overall y-scale, so one cannot find a y-scale for the full resolution Caen digitiser data by re-binning into the same number of bins as the LeCroy.
  • That being said, despite errors messages when evaluating a chi-square with differently binned histograms, one does get a chi-square value returned. However, this result is not reliable. By minimising the chi-square for the x-scale using differently binned histograms, one gets a worse result (tested on run 7). Better to stick with peak counting to find the y-scale.
  • Wrote code to plot XY histograms but with the height of the bars being the average energy of particles in each bin. Plot filters bins with events less than a user-defined minimum (20 events works well).
  • Transformed average energy to average range using a power law found from Geant4 of proton range in water for energies between 4-40 MeV.
  • Wrote code to plot 2D number density histogram as a plane on top of the average range 3D histogram.