DRS4 Forum
  DRS4 Discussion Forum, Page 23 of 46  Not logged in ELOG logo
ID Date Author Subjectdown
  52   Thu Mar 11 11:45:52 2010 Stefan RittReadout of DRS Data

Hao Huan wrote:

Hi Stefan,

    thanks to your help I can now successfully keep the Domino wave running at a stable frequency and maintain the channel cascading information in the Write Shift Register. (Since you told me WSR always reads and writes at the same time, I think I need to rewrite the information back every time after reading out from WSR to decide from which channel my data come, don't I?)

Yes you do. But if you have WSRLOOP=1 in the config register, this is done automatically. So the SR output is visible at the pin and will be fed back into the input.

Hao Huan wrote:

    However I'm still having difficulty in reading out from the DRS cells. I use the ROI readout mode and assume as long as I give a pulse on RSRLOAD the data will come out one by one. 

That's not correct. Have a look at Figure 14 of the datasheet. Do you see a single RSRLOAD pulse or many? There is only one RSRLOAD pulse to initialize the readout shift register, then the cells are clocked by SRCLK pulses. 

Hao Huan wrote:

Also I read in the datasheet that WSROUT will give RSR output when DWRITE is low. Sometimes I see some random bits from this output and sometimes I see all zero's. What is the reasonable output I should see from WSROUT, say, when I'm running in the transparent mode with DWRITE low? 

A single RSRLOAD pulse loads the RSR with a "1" at the domino stop position and "0" in all other places. A pulse on SRCLK shifts this "1" down the RSR. When it arrives at cell #1023, it will be visible for one clock cycle at WSROUT. The "double" functionality of WSROUT has the following background: Assume you use channel cascading 2x2048. Now the domino wave stopps in cell 1020 of the first channel for example. You have to read cells 1020,1021,1022,1024 of the first channel, then you continue with 0,1,2 on the second channel. But how do you know that you have to switch channels after the first four clock cycles? The SROUT output encodes the stop position (in this case 1020), but it needs 10 clock cycles before the information is available, so you don't have it after four cycles. That's where WSROUT comes into play: Since it outputs RSR bit by bit, it will show three "0", then a "1", when you are at cell 1023. Then you know that you have to switch channels immediately. That's why I output RSR via WSROUT if DWRITE is low.

 

  676   Thu Mar 22 14:36:01 2018 Phan Van ChuanRead the CalibrateWaveform

Helo
I'm building an application for reading waveforms from the DRS4 board to PC. However, I am having problems reading calibration data from EEPROM on DRS4 board. The calibration data is read through the function reference:
void DRSBoard :: ReadCalibration (void)
...
      ReadEEPROM (1, buf, 1024 * 32);
      for (i = 0; i <8; i ++)
         for (j = 0; j <1024; j ++) {
            fCellOffset [i] [j] = buf [(i * 1024 + j) * 2];
            fCellGain [i] [j] = buf [(i * 1024 + j) * 2 + 1] / 65535.0*0.4+0.7;
         }
      
      ReadEEPROM (2, buf, 1024 * 32);
      for (i = 0; i <8; i ++)
         for (j = 0; j <1024; j ++)
            fCellOffset2 [i] [j] = buf [(i * 1024 + j) * 2];
...
The Calibrate Waveform is performed by:
int DRSBoard::CalibrateWaveform(unsigned int chipIndex, unsigned char channel, unsigned short *adcWaveform, short *waveform, bool responseCalib, int triggerCell, bool adjustToClock, float threshold, bool offsetCalib)
.....
         for (j = 0; j < n_bins; j++) {
            value = adcWaveform[j] - fCellOffset[channel+chipIndex*9][(j*skip + triggerCell) % kNumberOfBins];
            value = value / fCellGain[channel+chipIndex*9][(j*skip + triggerCell) % kNumberOfBins];
            if (offsetCalib && channel != 8)
               value = value - fCellOffset2[channel+chipIndex*9][j*skip] + 32768;
...
. Because the calibration data reads incorrectly, the Calibrate Waveform does not do it.
Can read calibration data from EEPROM by any command via Oscilloscope application or DRS Command Line Interface application?
Thank you for your help!!!!

  677   Fri Mar 23 09:39:55 2018 Stefan RittRead the CalibrateWaveform

You don't have to read and calibrate the waveforms in your user code, but can rely on the DRS.cpp library to do that. Just look at the drs_exam.cpp program coming with the distribution. It uses the function b->GetWave() to retrieve the calibrated waveform. If you like, you can look into that function to learn how to apply the calibration, but I can tell you that it's a bit complicated. Since each event starts at an arbitrary stop cell in the DRS4, you have to "rotate" the calibration array. Then you do actually four calibrations in a row (cell, readout, gain and range).

Stefan

Phan Van Chuan wrote:

Helo
I'm building an application for reading waveforms from the DRS4 board to PC. However, I am having problems reading calibration data from EEPROM on DRS4 board. The calibration data is read through the function reference:
void DRSBoard :: ReadCalibration (void)
...
      ReadEEPROM (1, buf, 1024 * 32);
      for (i = 0; i <8; i ++)
         for (j = 0; j <1024; j ++) {
            fCellOffset [i] [j] = buf [(i * 1024 + j) * 2];
            fCellGain [i] [j] = buf [(i * 1024 + j) * 2 + 1] / 65535.0*0.4+0.7;
         }
      
      ReadEEPROM (2, buf, 1024 * 32);
      for (i = 0; i <8; i ++)
         for (j = 0; j <1024; j ++)
            fCellOffset2 [i] [j] = buf [(i * 1024 + j) * 2];
...
The Calibrate Waveform is performed by:
int DRSBoard::CalibrateWaveform(unsigned int chipIndex, unsigned char channel, unsigned short *adcWaveform, short *waveform, bool responseCalib, int triggerCell, bool adjustToClock, float threshold, bool offsetCalib)
.....
         for (j = 0; j < n_bins; j++) {
            value = adcWaveform[j] - fCellOffset[channel+chipIndex*9][(j*skip + triggerCell) % kNumberOfBins];
            value = value / fCellGain[channel+chipIndex*9][(j*skip + triggerCell) % kNumberOfBins];
            if (offsetCalib && channel != 8)
               value = value - fCellOffset2[channel+chipIndex*9][j*skip] + 32768;
...
. Because the calibration data reads incorrectly, the Calibrate Waveform does not do it.
Can read calibration data from EEPROM by any command via Oscilloscope application or DRS Command Line Interface application?
Thank you for your help!!!!

 

  393   Mon Nov 17 16:36:18 2014 Mickey ChiuRaspberry Pi drsosc does not exit properly

When running drsosc on a raspberry pi, it seems the exit doesn't seem to work at all.  This is true for the "exit" button on the window, or the file menu exit, or the "x" on the window.  I end up having to kill drsosc manually from the command line.  This wouldn't be such a bad thing except that it doesn't seem to store any settings when killed in this way.  I'm wondering if anyone else sees the same thing, or if there is a fix out there, before I go and delve into why.

  394   Tue Nov 25 14:06:34 2014 Stefan RittRaspberry Pi drsosc does not exit properly

Mickey Chiu wrote:

When running drsosc on a raspberry pi, it seems the exit doesn't seem to work at all.  This is true for the "exit" button on the window, or the file menu exit, or the "x" on the window.  I end up having to kill drsosc manually from the command line.  This wouldn't be such a bad thing except that it doesn't seem to store any settings when killed in this way.  I'm wondering if anyone else sees the same thing, or if there is a fix out there, before I go and delve into why.

Unfortunately I don't have a pi here right now, so I cannot reproduce your problem. I checked on a linux system and it worked fine with wxWidgets 3.0.1 and GTK2 2.20. The wxWidget library sends an wxID_EXIT event to DOFrame::OnExit, which then closes the window. The destructor of DOFrame then calls SaveConfig() to save the current settings. Maybe you can debug this.

/Stefan 

  631   Fri Oct 13 03:39:01 2017 Jonathan WapmanRaspberry Pi Connection Failure

I am currently attempting to use a raspberry pi to connect to the DRS 4 board. I whenever I try to use the DRS Command Line TOol, Revision 21435 to connect to the drs board, I get the error

"musb_open: libusb_open() error -3"

"USB successfully scanned, but no boards found"

"No DRS Boards Found".

I successfully compiled the libusb driver before compiling the drs software 5.0.6, and installed all other listed packages in the install instructions.

  632   Mon Oct 16 15:35:22 2017 Stefan RittRaspberry Pi Connection Failure

Have you tried as root? Maybe you miss some permissions.

Stefan

Jonathan Wapman wrote:

I am currently attempting to use a raspberry pi to connect to the DRS 4 board. I whenever I try to use the DRS Command Line TOol, Revision 21435 to connect to the drs board, I get the error

"musb_open: libusb_open() error -3"

"USB successfully scanned, but no boards found"

"No DRS Boards Found".

I successfully compiled the libusb driver before compiling the drs software 5.0.6, and installed all other listed packages in the install instructions.

 

  76   Wed May 5 22:30:50 2010 Ignacio Diéguez EstremeraRandom noise spec in datasheet

Hi,

According to DRS4's datasheet, the random noise is 0.35mVrms. Is this the input equivalent noise voltage? It is computed over the 0-950MHz frequency band?

Regards.

  77   Thu May 6 08:15:39 2010 Stefan RittRandom noise spec in datasheet

Ignacio Diéguez Estremera wrote:

Hi,

According to DRS4's datasheet, the random noise is 0.35mVrms. Is this the input equivalent noise voltage? It is computed over the 0-950MHz frequency band?

Regards.

You cannot compare the DRS4 noise directly with an amplifier for example. The noise mainly comes from variations of the charge injection into the storage cells, and some noise during the readout process, which happens in a completely different frequency domain than the sampling.

So what I did is to keep the inputs open, measure a 1024-bin waveform, and compute the RMS of this waveform. So I believe that this is kind of equivalent noise voltage from 1-950 MHz. It does not start from zero since very low frequency noise (like 50 Hz) just causes a baseline shift and does not influence the RMS, but this is not so important since in most applications people do an event-by-event baseline subtraction to get rid of low frequency noise in their apparatus. The 0.35 mV RMS also depend on the electronics around the chip. On our USB evaluation board the noise it typically smaller (0.31 mV RMS), while in some VME board we measure 0.42 mV RMS. If you do the perfect analog design around the chip, you can maybe push this maybe even lower.

  262   Tue Jun 18 14:19:39 2013 Stefan RittROOT program to decode binary data from DRSOsc

Please find attached a simple ROOT based program (http://root.cern.ch) to decode binary data from the DRSOsc program. It assumes that all four channels were recorded. If this is not the case, the program can be adjusted accordingly.

To use it, simply type (assuming that you have written a data file "test.dat" with DRSOsc):

root [0] .L decode.C+
Info in <TUnixSystem::ACLiC>: creating shared library /tmp/./decode_C.so
root [1] decode("test");
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
1927 events processed
"test.root" written
root [2] 

If you have turned on the clock on channel4 of the DRS4 evaluation board, it will produce a plot like this:
 
c1.gif 

 

/Stefan

Attachment 1: decode.C
#include <string.h>
#include <stdio.h>
#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include <iostream>

struct Header_t {
   char           event_header[4];
   unsigned int   serial_number;
   unsigned short year;
   unsigned short month;
   unsigned short day;
   unsigned short hour;
   unsigned short minute;
   unsigned short second;
   unsigned short millisecond;
   unsigned short reserved1;
   float time[1024];
};

struct Waveform_t {
   char           chn1_header[4];
   unsigned short chn1[1024];
   char           chn2_header[4];
   unsigned short chn2[1024];
   char           chn3_header[4];
   unsigned short chn3[1024];
   char           chn4_header[4];
   unsigned short chn4[1024];
};

void decode(char *filename) {
   Header_t header;
   Waveform_t waveform;
   Double_t t[1024], chn1[1024], chn2[1024], chn3[1024], chn4[1024];
   Int_t n;

   // open the binary waveform file
   FILE *f = fopen(Form("%s.dat", filename), "r");

   //open the root file
   TFile *outfile = new TFile(Form("%s.root", filename), "RECREATE");
   
   // define the rec tree
   TTree *rec = new TTree("rec","rec");
   rec->Branch("t", &t   ,"t[1024]/D");  
   rec->Branch("chn1", &chn1 ,"chn1[1024]/D");
   rec->Branch("chn2", &chn2 ,"chn2[1024]/D");
   rec->Branch("chn3", &chn3 ,"chn3[1024]/D");
   rec->Branch("chn4", &chn4 ,"chn4[1024]/D");
  
   // loop over all events in data file
   for (n=0 ; fread(&header, sizeof(header), 1, f) > 0; n++) {

      // decode time      
      for (Int_t i=0; i<1024; i++)
         t[i] = (Double_t) header.time[i];
      
      fread(&waveform, sizeof(waveform), 1, f);
      
      // decode amplitudes in mV
      for (Int_t i=0; i<1024; i++) {
         chn1[i] = (Double_t) ((waveform.chn1[i]) / 65535. - 0.5) * 1000;   
         chn2[i] = (Double_t) ((waveform.chn2[i]) / 65535. - 0.5) * 1000;   
         chn3[i] = (Double_t) ((waveform.chn3[i]) / 65535. - 0.5) * 1000;   
         chn4[i] = (Double_t) ((waveform.chn4[i]) / 65535. - 0.5) * 1000;   
      }
      rec->Fill();
   }
   
   // draw channel #4
   rec->Draw("chn4:t");
   
   // print number of events
   cout<<n<<" events processed"<<endl;
   cout<<"\""<<Form("%s.root", filename)<<"\" written"<<endl;
   
   // save and close root file
   rec->Write();
   outfile->Close();
}
  361   Wed Jul 30 17:05:06 2014 Stefan RittROOT program to decode binary data from DRSOsc

Stefan Ritt wrote:

Please find attached a simple ROOT based program (http://root.cern.ch) to decode binary data from the DRSOsc program. It assumes that all four channels were recorded. If this is not the case, the program can be adjusted accordingly.

To use it, simply type (assuming that you have written a data file "test.dat" with DRSOsc):

root [0] .L decode.C+
Info in <TUnixSystem::ACLiC>: creating shared library /tmp/./decode_C.so
root [1] decode("test");
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
1927 events processed
"test.root" written
root [2] 

If you have turned on the clock on channel4 of the DRS4 evaluation board, it will produce a plot like this:
 
c1.gif 

 

/Stefan

I updated this ROOT program for the new format used with the V5 boards. It's now called "read_binary.C". Usage stays the same. There is also a standalone C program "read_binary.cpp". Both are attached. 

Attachment 1: read_binary.C
/*
 
   Name:           read_binary.C
   Created by:     Stefan Ritt <stefan.ritt@psi.ch>
   Date:           July 30th, 2014
 
   Purpose:        Example program under ROOT to read a binary data file written 
                   by the DRSOsc program. Decode time and voltages from waveforms 
                   and display them as a graph. Put values into a ROOT Tree for 
                   further analysis.
 
                   To run it, do:
 
                   - Crate a file test.dat via the "Save" button in DRSOsc
                   - start ROOT
                   root [0] .L read_binary.C+
                   root [1] decode("test.dat");
 
*/
 

#include <string.h>
#include <stdio.h>
#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include "TGraph.h"
#include "TCanvas.h"
#include "Getline.h"

typedef struct {
  char           time_header[4];
  char           bn[2];
  unsigned short board_serial_number;
} THEADER;

typedef struct {
  char           event_header[4];
  unsigned int   event_serial_number;
  unsigned short year;
  unsigned short month;
  unsigned short day;
  unsigned short hour;
  unsigned short minute;
  unsigned short second;
  unsigned short millisecond;
  unsigned short reserved1;
  char           bs[2];
  unsigned short board_serial_number;
  char           tc[2];
  unsigned short trigger_cell;
} EHEADER;

/*-----------------------------------------------------------------------------*/

void decode(char *filename) {
   THEADER th;
   EHEADER eh;
   char hdr[4];
   unsigned short voltage[1024];
   double waveform[4][1024], time[4][1024];
   float bin_width[4][1024];
   char rootfile[256];
   int i, j, ch, n, chn_index;
   double t1, t2, dt;

   // open the binary waveform file
   FILE *f = fopen(Form("%s", filename), "r");
   if (f == NULL) {
      printf("Cannot find file \'%s\'\n", filename);
      return;
   }

   //open the root file
   strcpy(rootfile, filename);
   if (strchr(rootfile, '.'))
      *strchr(rootfile, '.') = 0;
   strcat(rootfile, ".root");
   TFile *outfile = new TFile(rootfile, "RECREATE");
   
   // define the rec tree
   TTree *rec = new TTree("rec","rec");
   rec->Branch("t1", time[0]     ,"t1[1024]/D");  
   rec->Branch("t2", time[1]     ,"t2[1024]/D");  
   rec->Branch("t3", time[2]     ,"t3[1024]/D");  
   rec->Branch("t4", time[3]     ,"t4[1024]/D");  
   rec->Branch("w1", waveform[0] ,"w1[1024]/D");
   rec->Branch("w2", waveform[1] ,"w2[1024]/D");
   rec->Branch("w3", waveform[2] ,"w3[1024]/D");
   rec->Branch("w4", waveform[3] ,"w4[1024]/D");
   
   // create canvas
   TCanvas *c1 = new TCanvas();
   
   // create graph
   TGraph *g = new TGraph(1024, (double *)time[0], (double *)waveform[0]);

   // read time header
   fread(&th, sizeof(th), 1, f);
   printf("Found data for board #%d\n", th.board_serial_number);

   // read time bin widths
   memset(bin_width, sizeof(bin_width), 0);
   for (ch=0 ; ch<5 ; ch++) {
      fread(hdr, sizeof(hdr), 1, f);
      if (hdr[0] != 'C') {
         // event header found
         fseek(f, -4, SEEK_CUR);
         break;      
      }
      i = hdr[3] - '0' - 1;
      printf("Found timing calibration for channel #%d\n", i+1);
      fread(&bin_width[i][0], sizeof(float), 1024, f);
   }

   // loop over all events in data file
   for (n=0 ; n<5 ; n++) {
      // read event header
      i = fread(&eh, sizeof(eh), 1, f);
      if (i < 1)
         break;
         
      printf("Found event #%d\n", eh.event_serial_number);

      // reach channel data
      for (ch=0 ; ch<5 ; ch++) {
         i = fread(hdr, sizeof(hdr), 1, f);
         if (i < 1)
            break;
         if (hdr[0] != 'C') {
            // event header found
            fseek(f, -4, SEEK_CUR);
            break;      
         }
         chn_index = hdr[3] - '0' - 1;
         fread(voltage, sizeof(short), 1024, f);
         
         for (i=0 ; i<1024 ; i++) {
            // convert data to volts
            waveform[chn_index][i] = (voltage[i] / 65536. - 0.5);
            
            // calculate time for this cell
            for (j=0,time[chn_index][i]=0 ; j<i ; j++)
              time[chn_index][i] += bin_width[chn_index][(j+eh.trigger_cell) % 1024];            
         }
      }
    
      // align cell #0 of all channels
      t1 = time[0][(1024-eh.trigger_cell) % 1024];
      for (ch=1 ; ch<4 ; ch++) {
         t2 = time[ch][(1024-eh.trigger_cell) % 1024];
         dt = t1 - t2;
         for (i=0 ; i<1024 ; i++)
            time[ch][i] += dt;
      }

      // fill root tree
      rec->Fill();
      
      // fill graph
      for (i=0 ; i<1024 ; i++)
         g->SetPoint(i, time[0][i], waveform[0][i]);
      
      // draw graph and wait for user click
      g->Draw("ACP");
      c1->Update();
      gPad->WaitPrimitive();
   }

   // print number of events
   printf("%d events processed, \"%s\" written.\n", n, rootfile);
   
   // save and close root file
   rec->Write();
   outfile->Close();
}
Attachment 2: read_binary.cpp
/*
   Name:           read_binary.cpp
   Created by:     Stefan Ritt <stefan.ritt@psi.ch>
   Date:           July 30th, 2014

   Purpose:        Example file to read binary data saved by DRSOsc.
 
   Compile and run it with:
 
      gcc -o read_binary read_binary.cpp
 
      ./read_binary <filename>

   This program assumes that a pulse from a signal generator is split
   and fed into channels #1 and #2. It then calculates the time difference
   between these two pulses to show the performance of the DRS board
   for time measurements.

   $Id: read_binary.cpp 21438 2014-07-30 15:00:17Z ritt $
*/

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <math.h>

typedef struct {
   char           time_header[4];
   char           bn[2];
   unsigned short board_serial_number;
} THEADER;

typedef struct {
   char           event_header[4];
   unsigned int   event_serial_number;
   unsigned short year;
   unsigned short month;
   unsigned short day;
   unsigned short hour;
   unsigned short minute;
   unsigned short second;
   unsigned short millisecond;
   unsigned short reserved1;
   char           bs[2];
   unsigned short board_serial_number;
   char           tc[2];
   unsigned short trigger_cell;
} EHEADER;

/*-----------------------------------------------------------------------------*/

int main(int argc, const char * argv[])
{
   THEADER th;
   EHEADER eh;
   char hdr[4];
   unsigned short voltage[1024];
   double waveform[4][1024], time[4][1024];
   float bin_width[4][1024];
   char rootfile[256];
   int i, j, ch, n, chn_index;
   double t1, t2, dt;
   char filename[256];

   int ndt;
   double threshold, sumdt, sumdt2;
   
   if (argc > 1)
      strcpy(filename, argv[1]);
   else {
      printf("Usage: read_binary <filename>\n");
      return 0;
   }
   
   // open the binary waveform file
   FILE *f = fopen(filename, "r");
   if (f == NULL) {
      printf("Cannot find file \'%s\'\n", filename);
      return 0;
   }

   // read time header
   fread(&th, sizeof(th), 1, f);
   printf("Found data for board #%d\n", th.board_serial_number);

   // read time bin widths
   memset(bin_width, sizeof(bin_width), 0);
   for (ch=0 ; ch<5 ; ch++) {
      fread(hdr, sizeof(hdr), 1, f);
      if (hdr[0] != 'C') {
         // event header found
         fseek(f, -4, SEEK_CUR);
         break;
      }
      i = hdr[3] - '0' - 1;
      printf("Found timing calibration for channel #%d\n", i+1);
      fread(&bin_width[i][0], sizeof(float), 1024, f);
   }
   
   // initialize statistics
   ndt = 0;
   sumdt = sumdt2 = 0;
   
   // loop over all events in the data file
   for (n= 0 ; ; n++) {
      // read event header
      i = fread(&eh, sizeof(eh), 1, f);
      if (i < 1)
         break;
      
      printf("Found event #%d\n", eh.event_serial_number);
      
      // reach channel data
      for (ch=0 ; ch<5 ; ch++) {
         i = fread(hdr, sizeof(hdr), 1, f);
         if (i < 1)
            break;
         if (hdr[0] != 'C') {
            // event header found
            fseek(f, -4, SEEK_CUR);
            break;
         }
         chn_index = hdr[3] - '0' - 1;
         fread(voltage, sizeof(short), 1024, f);
         
         for (i=0 ; i<1024 ; i++) {
            // convert data to volts
            waveform[chn_index][i] = (voltage[i] / 65536. - 0.5);
            
            // calculate time for this cell
            for (j=0,time[chn_index][i]=0 ; j<i ; j++)
               time[chn_index][i] += bin_width[chn_index][(j+eh.trigger_cell) % 1024];
         }
      }
      
      
      // align cell #0 of all channels
      t1 = time[0][(1024-eh.trigger_cell) % 1024];
      for (ch=1 ; ch<4 ; ch++) {
         t2 = time[ch][(1024-eh.trigger_cell) % 1024];
         dt = t1 - t2;
         for (i=0 ; i<1024 ; i++)
            time[ch][i] += dt;
      }
      
      t1 = t2 = 0;
      threshold = 0.3;
      
      // find peak in channel 1 above threshold
      for (i=0 ; i<1022 ; i++)
         if (waveform[0][i] < threshold && waveform[0][i+1] >= threshold) {
            t1 = (threshold-waveform[0][i])/(waveform[0][i+1]-waveform[0][i])*(time[0][i+1]-time[0][i])+time[0][i];
            break;
         }
      
      // find peak in channel 2 above threshold
      for (i=0 ; i<1022 ; i++)
         if (waveform[1][i] < threshold && waveform[1][i+1] >= threshold) {
            t2 = (threshold-waveform[1][i])/(waveform[1][i+1]-waveform[1][i])*(time[1][i+1]-time[1][i])+time[1][i];
            break;
         }
      
      // calculate distance of peaks with statistics
      if (t1 > 0 && t2 > 0) {
         ndt++;
         dt = t2 - t1;
         sumdt += dt;
         sumdt2 += dt*dt;
      }
   }
   
   // print statistics
   printf("dT = %1.3lfns +- %1.1lfps\n", sumdt/ndt, 1000*sqrt(1.0/(ndt-1)*(sumdt2-1.0/ndt*sumdt*sumdt)));
   
   return 1;
}

  747   Fri Mar 8 19:35:11 2019 Abaz KryemadhiROOT Macro for newest software

The older root macro did not work for me for data acquired with the newest software.

so for the newest software and multiple boards, I modified the read_binary.cpp into read_binary.C for those who like to use the root macro, see the attachment.  

 

Attachment 1: read_binary.C
/*
 
   Name:           read_binary.C
   Created by:     Stefan Ritt <stefan.ritt@psi.ch>
   Date:           July 30th, 2014
   Modified By:    Abaz Kryemadhi
   Date:           March 7th, 2019
 
   Purpose:        Example program under ROOT to read a binary data file written 
                   by the DRSOsc program. Decode time and voltages from waveforms 
                   and display them as a graph. Put values into a ROOT Tree for 
                   further analysis.
 
                   To run it, do:
 
                   - Crate a file test.dat via the "Save" button in DRSOsc
                   - start ROOT (type root)
                   root [0] .L read_binary.C+
                   root [1] decode("test.dat");
 
*/
 

#include <fcntl.h>
#include <unistd.h>
#include <math.h>


#include <string.h>
#include <stdio.h>
#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include "TGraph.h"
#include "TCanvas.h"
#include "Getline.h"
#include "TAxis.h"

typedef struct {
   char           tag[3];
   char           version;
} FHEADER;

typedef struct {
   char           time_header[4];
} THEADER;

typedef struct {
   char           bn[2];
   unsigned short board_serial_number;
} BHEADER;

typedef struct {
   char           event_header[4];
   unsigned int   event_serial_number;
   unsigned short year;
   unsigned short month;
   unsigned short day;
   unsigned short hour;
   unsigned short minute;
   unsigned short second;
   unsigned short millisecond;
   unsigned short range;
} EHEADER;

typedef struct {
   char           tc[2];
   unsigned short trigger_cell;
} TCHEADER;

typedef struct {
   char           c[1];
   char           cn[3];
} CHEADER;

/*-----------------------------------------------------------------------------*/

//int main(int argc, const char * argv[])
void decode(char *filename) {

   FHEADER  fh;
   THEADER  th;
   BHEADER  bh;
   EHEADER  eh;
   TCHEADER tch;
   CHEADER  ch;
   
   unsigned int scaler;
   unsigned short voltage[1024];
   double waveform[16][4][1024], time[16][4][1024];
   float bin_width[16][4][1024];
   int i, j, b, chn, n, chn_index, n_boards;
   double t1, t2, dt;
   //char filename[256];
   char rootfile[256];
   int ndt;
   double threshold, sumdt, sumdt2;
   double sum, baseline, max,amplitude1,amplitude2, amplitude3,amplitude4;
   
   // open the binary waveform file
   FILE *f = fopen(filename, "rb");
   if (f == NULL) {
      printf("Cannot find file \'%s\'\n", filename);
      return;
   }
   
   
    //open the root file
   strcpy(rootfile, filename);
   if (strchr(rootfile, '.'))
      *strchr(rootfile, '.') = 0;
   strcat(rootfile, ".root");
   TFile *outfile = new TFile(rootfile, "RECREATE");
   
   // define the rec tree
   TTree *rec = new TTree("rec","rec");
   rec->Branch("t1", time[0][0]     ,"t1[1024]/D");  
   rec->Branch("t2", time[0][1]     ,"t2[1024]/D");  
   rec->Branch("t3", time[0][2]     ,"t3[1024]/D");  
   rec->Branch("t4", time[0][3]     ,"t4[1024]/D");  
   rec->Branch("w1", waveform[0][0] ,"w1[1024]/D");
   rec->Branch("w2", waveform[0][1] ,"w2[1024]/D");
   rec->Branch("w3", waveform[0][2] ,"w3[1024]/D");
   rec->Branch("w4", waveform[0][3] ,"w4[1024]/D");
   rec->Branch("amplitude1", &amplitude1,"amplitude1/D");
   rec->Branch("amplitude2", &amplitude2,"amplitude2/D");
   rec->Branch("amplitude3", &amplitude3,"amplitude3/D");
   rec->Branch("amplitude4", &amplitude4,"amplitude4/D");
   // create canvas
   TCanvas *c1 = new TCanvas();
   
   // create graph
   TGraph *g = new TGraph(1024, (double *)time[0][0], (double *)waveform[0][0]);


   // read file header
   fread(&fh, sizeof(fh), 1, f);
   if (fh.tag[0] != 'D' || fh.tag[1] != 'R' || fh.tag[2] != 'S') {
      printf("Found invalid file header in file \'%s\', aborting.\n", filename);
      return;
   }
   
   if (fh.version != '2') {
      printf("Found invalid file version \'%c\' in file \'%s\', should be \'2\', aborting.\n", fh.version, filename);
      return;
   }

   // read time header
   fread(&th, sizeof(th), 1, f);
   if (memcmp(th.time_header, "TIME", 4) != 0) {
      printf("Invalid time header in file \'%s\', aborting.\n", filename);
      return;
   }

   for (b = 0 ; ; b++) {
      // read board header
      fread(&bh, sizeof(bh), 1, f);
      if (memcmp(bh.bn, "B#", 2) != 0) {
         // probably event header found
         fseek(f, -4, SEEK_CUR);
         break;
      }
      
      printf("Found data for board #%d\n", bh.board_serial_number);
      
      // read time bin widths
      memset(bin_width[b], sizeof(bin_width[0]), 0);
      for (chn=0 ; chn<5 ; chn++) {
         fread(&ch, sizeof(ch), 1, f);
         if (ch.c[0] != 'C') {
            // event header found
            fseek(f, -4, SEEK_CUR);
            break;
         }
         i = ch.cn[2] - '0' - 1;
         printf("Found timing calibration for channel #%d\n", i+1);
         fread(&bin_width[b][i][0], sizeof(float), 1024, f);
         // fix for 2048 bin mode: double channel
         if (bin_width[b][i][1023] > 10 || bin_width[b][i][1023] < 0.01) {
            for (j=0 ; j<512 ; j++)
               bin_width[b][i][j+512] = bin_width[b][i][j];
         }
      }
   }
   n_boards = b;
   
   // initialize statistics
   ndt = 0;
   sumdt = sumdt2 = 0;
   
   // loop over all events in the data file
   for (n=0 ; ; n++) {
      // read event header
      i = (int)fread(&eh, sizeof(eh), 1, f);
      if (i < 1)
         break;
      
      printf("Found event #%d %d %d\n", eh.event_serial_number, eh.second, eh.millisecond);
      
      // loop over all boards in data file
      for (b=0 ; b<n_boards ; b++) {
         
         // read board header
         fread(&bh, sizeof(bh), 1, f);
         if (memcmp(bh.bn, "B#", 2) != 0) {
            printf("Invalid board header in file \'%s\', aborting.\n", filename);
            return;
         }
         
         // read trigger cell
         fread(&tch, sizeof(tch), 1, f);
         if (memcmp(tch.tc, "T#", 2) != 0) {
            printf("Invalid trigger cell header in file \'%s\', aborting.\n", filename);
            return;
         }

         if (n_boards > 1)
            printf("Found data for board #%d\n", bh.board_serial_number);
         
         // reach channel data
         for (chn=0 ; chn<4 ; chn++) {
            
            // read channel header
            fread(&ch, sizeof(ch), 1, f);
            if (ch.c[0] != 'C') {
               // event header found
               fseek(f, -4, SEEK_CUR);
               break;
            }
            chn_index = ch.cn[2] - '0' - 1;
            fread(&scaler, sizeof(int), 1, f);
            fread(voltage, sizeof(short), 1024, f);
            
            for (i=0 ; i<1024 ; i++) {
               // convert data to volts
               waveform[b][chn_index][i] = (voltage[i] / 65536. + eh.range/1000.0 - 0.5);
               
               // calculate time for this cell
               for (j=0,time[b][chn_index][i]=0 ; j<i ; j++)
                  time[b][chn_index][i] += bin_width[b][chn_index][(j+tch.trigger_cell) % 1024];
            }
         }
         
         // align cell #0 of all channels
         t1 = time[b][0][(1024-tch.trigger_cell) % 1024];
         for (chn=1 ; chn<4 ; chn++) {
            t2 = time[b][chn][(1024-tch.trigger_cell) % 1024];
            dt = t1 - t2;
            for (i=0 ; i<1024 ; i++)
               time[b][chn][i] += dt;
         }
         
         t1 = t2 = 0;
         threshold = 0.3;
         
         // find peak in channel 1 above threshold
         for (i=0 ; i<1022 ; i++)
            if (waveform[b][0][i] < threshold && waveform[b][0][i+1] >= threshold) {
               t1 = (threshold-waveform[b][0][i])/(waveform[b][0][i+1]-waveform[b][0][i])*(time[b][0][i+1]-time[b][0][i])+time[b][0][i];
               break;
            }
         
         // find peak in channel 2 above threshold
         for (i=0 ; i<1022 ; i++)
            if (waveform[b][1][i] < threshold && waveform[b][1][i+1] >= threshold) {
               t2 = (threshold-waveform[b][1][i])/(waveform[b][1][i+1]-waveform[b][1][i])*(time[b][1][i+1]-time[b][1][i])+time[b][1][i];
               break;
            }
         
         // calculate distance of peaks with statistics
         if (t1 > 0 && t2 > 0) {
            ndt++;
            dt = t2 - t1;
            sumdt += dt;
            sumdt2 += dt*dt;
         }
     //Find baseline for channel 3 to get amplitude for ch3 
     sum=0.0;
      for (i=0 ; i<10; i++) {
         sum+=waveform[0][2][i];
       } 
       baseline=sum/10;
     //Find amplitude for channel 3 (this is example channel )
     max=-10000.0;
      for (i=0 ; i<1022; i++) {
         if (waveform[b][2][i]>max) {
            max=waveform[b][2][i];
       } 
      }
       amplitude3=max;
     // fill root tree
      rec->Fill();

  //Uncomment the following to see couple waveforms of voltage vs time
  /*   
      // fill graph
      for (i=0 ; i<1024 ; i++)
         g->SetPoint(i, time[b][2][i], waveform[b][2][i]);
      
      // draw graph and wait for user click
... 20 more lines ...
  727   Tue Jan 29 14:43:44 2019 Abaz KryemadhiROOT Macro for data acquired with the newest software

Hello,

Is there a root macro for decoding binary data acquired with the newest software for single board or multi-boards daisy chained?

Cheers,

Abaz

  730   Wed Jan 30 17:08:58 2019 Stefan RittROOT Macro for data acquired with the newest software

This one elog:361 should still work.

Stefan

Abaz Kryemadhi wrote:

Hello,

Is there a root macro for decoding binary data acquired with the newest software for single board or multi-boards daisy chained?

Cheers,

Abaz

 

  663   Fri Mar 2 18:08:55 2018 Steven BlockROI

Hello,

I have a question about how ROI works. From what I have read, it will only save data that ocurs some time [ta] dictated by the user after an event is triggered as well as a small time [tb] before the event. The technical manual seems to indicated that the deadtime assciated with operating in ROI mode can be reduced by the following factor: 

\frac{t_a + t_b }{\frac{N}{Sample Speed}} .

Where N is the number of points in the time window (ex. 2048 or 1024). Is it ok to describe this as:

\frac{N'}{N} 

Where N' is the number of samples in the ROI and N is the same as before.

For example, if I were running at 5Gsps (200ps between samples), only recording 1024 samples per event and I had an signal that lasted 2ns, that means the signal would last 10 samples. If I set the ROI to only save 20 samples around this signal, would my Deadtime go to:

\frac{10}{1024} * 30ns*1024 + 2\mu s = 2.3\mu s? (The second portion of this equation comes from a response I recieved earlier, but I just want to make sure I understand this concept properly)

I recognize that the caveat is that this would work only if the signal was detected during acquistion, which leads to my next question. If no signals were detected in the 1024*200ps time frame in ROI mode, would the DRS4 go dead for 32us (using the factor = 1 from above equation), or would it dump the earliest events in the buffer for the more recent ones until it detects a signal? 

Finally, I assume this functionality can only be utilized with custom electornics with the DRS4, not the evaulation/demo board, please let me know if this is the case. 

Best,

Steven

  664   Fri Mar 2 20:17:17 2018 Stefan RittROI

N'/N is correct. The 2 us "from the response you got from me" come from the fact that after readout, you have to start the DRS4 again. During this time, the power supply usually becomes slightly unstable, and it takes on the evaluation board about 2us to stabilize it again. Tha't why I add the 2 us. If you don't care about slight offset effect, or if you make a better power supply, you dead time would be 10*30ns = 300ns for 10 samples. Starting the DRS again will take one or two clock cycles from the FPGA, which might add another 30 ns or so, depending on how you program the FPGA. So the best you can achieve for 10 samples is maybe 330 ns, if you have a really good power supply (large capacitors).

You can achieve this functionality with the evaluation board, but you would have to make a special firmware for it.

Stefan

Steven Block wrote:

Hello,

I have a question about how ROI works. From what I have read, it will only save data that ocurs some time [ta] dictated by the user after an event is triggered as well as a small time [tb] before the event. The technical manual seems to indicated that the deadtime assciated with operating in ROI mode can be reduced by the following factor: 

\frac{t_a + t_b }{\frac{N}{Sample Speed}} .

Where N is the number of points in the time window (ex. 2048 or 1024). Is it ok to describe this as:

\frac{N'}{N}

Where N' is the number of samples in the ROI and N is the same as before.

For example, if I were running at 5Gsps (200ps between samples), only recording 1024 samples per event and I had an signal that lasted 2ns, that means the signal would last 10 samples. If I set the ROI to only save 20 samples around this signal, would my Deadtime go to:

\frac{10}{1024} * 30ns*1024 + 2\mu s = 2.3\mu s? (The second portion of this equation comes from a response I recieved earlier, but I just want to make sure I understand this concept properly)

I recognize that the caveat is that this would work only if the signal was detected during acquistion, which leads to my next question. If no signals were detected in the 1024*200ps time frame in ROI mode, would the DRS4 go dead for 32us (using the factor = 1 from above equation), or would it dump the earliest events in the buffer for the more recent ones until it detects a signal? 

Finally, I assume this functionality can only be utilized with custom electornics with the DRS4, not the evaulation/demo board, please let me know if this is the case. 

Best,

Steven

 

  665   Fri Mar 2 21:05:48 2018 Steven BlockROI

Great! That is very helpful. 

One more question. If no signals were detected in the 1024*200ps time frame in ROI mode, would the DRS4 go dead for 32us (or 30us depending on the supply)  for, or would it dump the earliest events in the buffer for the more recent ones until it detects a signal to readout? Or rather, does filling the buffer force a readout or can it dynamically shift out old data until it detects a signal to readout. 

Steven

Stefan Ritt wrote:

N'/N is correct. The 2 us "from the response you got from me" come from the fact that after readout, you have to start the DRS4 again. During this time, the power supply usually becomes slightly unstable, and it takes on the evaluation board about 2us to stabilize it again. Tha't why I add the 2 us. If you don't care about slight offset effect, or if you make a better power supply, you dead time would be 10*30ns = 300ns for 10 samples. Starting the DRS again will take one or two clock cycles from the FPGA, which might add another 30 ns or so, depending on how you program the FPGA. So the best you can achieve for 10 samples is maybe 330 ns, if you have a really good power supply (large capacitors).

You can achieve this functionality with the evaluation board, but you would have to make a special firmware for it.

Stefan

Steven Block wrote:

Hello,

I have a question about how ROI works. From what I have read, it will only save data that ocurs some time [ta] dictated by the user after an event is triggered as well as a small time [tb] before the event. The technical manual seems to indicated that the deadtime assciated with operating in ROI mode can be reduced by the following factor: 

\frac{t_a + t_b }{\frac{N}{Sample Speed}} .

Where N is the number of points in the time window (ex. 2048 or 1024). Is it ok to describe this as:

\frac{N'}{N}

Where N' is the number of samples in the ROI and N is the same as before.

For example, if I were running at 5Gsps (200ps between samples), only recording 1024 samples per event and I had an signal that lasted 2ns, that means the signal would last 10 samples. If I set the ROI to only save 20 samples around this signal, would my Deadtime go to:

\frac{10}{1024} * 30ns*1024 + 2\mu s = 2.3\mu s? (The second portion of this equation comes from a response I recieved earlier, but I just want to make sure I understand this concept properly)

I recognize that the caveat is that this would work only if the signal was detected during acquistion, which leads to my next question. If no signals were detected in the 1024*200ps time frame in ROI mode, would the DRS4 go dead for 32us (using the factor = 1 from above equation), or would it dump the earliest events in the buffer for the more recent ones until it detects a signal? 

Finally, I assume this functionality can only be utilized with custom electornics with the DRS4, not the evaulation/demo board, please let me know if this is the case. 

Best,

Steven

 

 

  675   Mon Mar 19 16:22:42 2018 Stefan RittROI

The DRS4 has an internal storage of 1024 capacitors. They work as a ring buffer, so at 5GSPS you can store 200ns wide signals. After 200ns, the first samples are overwritten by new samples, so you always have the last 200ns of samples stored. Once you trigger the DRS4, this buffer is frozen, and the readout of this buffer causes the dead time. No trigger, no dead time. Hope this answers your question.

Stefan

Steven Block wrote:

Great! That is very helpful. 

One more question. If no signals were detected in the 1024*200ps time frame in ROI mode, would the DRS4 go dead for 32us (or 30us depending on the supply)  for, or would it dump the earliest events in the buffer for the more recent ones until it detects a signal to readout? Or rather, does filling the buffer force a readout or can it dynamically shift out old data until it detects a signal to readout. 

Steven

Stefan Ritt wrote:

N'/N is correct. The 2 us "from the response you got from me" come from the fact that after readout, you have to start the DRS4 again. During this time, the power supply usually becomes slightly unstable, and it takes on the evaluation board about 2us to stabilize it again. Tha't why I add the 2 us. If you don't care about slight offset effect, or if you make a better power supply, you dead time would be 10*30ns = 300ns for 10 samples. Starting the DRS again will take one or two clock cycles from the FPGA, which might add another 30 ns or so, depending on how you program the FPGA. So the best you can achieve for 10 samples is maybe 330 ns, if you have a really good power supply (large capacitors).

You can achieve this functionality with the evaluation board, but you would have to make a special firmware for it.

Stefan

Steven Block wrote:

Hello,

I have a question about how ROI works. From what I have read, it will only save data that ocurs some time [ta] dictated by the user after an event is triggered as well as a small time [tb] before the event. The technical manual seems to indicated that the deadtime assciated with operating in ROI mode can be reduced by the following factor: 

\frac{t_a + t_b }{\frac{N}{Sample Speed}} .

Where N is the number of points in the time window (ex. 2048 or 1024). Is it ok to describe this as:

\frac{N'}{N}

Where N' is the number of samples in the ROI and N is the same as before.

For example, if I were running at 5Gsps (200ps between samples), only recording 1024 samples per event and I had an signal that lasted 2ns, that means the signal would last 10 samples. If I set the ROI to only save 20 samples around this signal, would my Deadtime go to:

\frac{10}{1024} * 30ns*1024 + 2\mu s = 2.3\mu s? (The second portion of this equation comes from a response I recieved earlier, but I just want to make sure I understand this concept properly)

I recognize that the caveat is that this would work only if the signal was detected during acquistion, which leads to my next question. If no signals were detected in the 1024*200ps time frame in ROI mode, would the DRS4 go dead for 32us (using the factor = 1 from above equation), or would it dump the earliest events in the buffer for the more recent ones until it detects a signal? 

Finally, I assume this functionality can only be utilized with custom electornics with the DRS4, not the evaulation/demo board, please let me know if this is the case. 

Best,

Steven

 

 

 

  59   Tue Mar 30 22:57:34 2010 Hao HuanROFS Configuration

Hi Stefan,

    according to the DRS4 datasheet, if we want an input range centered around U0, the ROFS should be 1.55V-U0. However when I read the codes of the evaluation board application, ROFS seems to be 1.6V-1.25*U0 where the coefficient 1.25 is said to come from sampling cell charge injection correction. Is it the right equation to use? What exactly does that charge injection correction mean?

    Thanks a lot.

 

  68   Thu Apr 15 13:48:40 2010 Stefan RittROFS Configuration

Hao Huan wrote:

Hi Stefan,

    according to the DRS4 datasheet, if we want an input range centered around U0, the ROFS should be 1.55V-U0. However when I read the codes of the evaluation board application, ROFS seems to be 1.6V-1.25*U0 where the coefficient 1.25 is said to come from sampling cell charge injection correction. Is it the right equation to use? What exactly does that charge injection correction mean?

    Thanks a lot.

 

1.55V-U0 is the theoretical values, but there are certain "dirt" effects like chip-to-chip variation and charge injection. The difference between various chips is easily 20-30mV, so there is not a single "correct" value. The formula 1.6V-1.25*U0 I developed for a special evaluation board, where it kind of worked better than the theoretical value, but I never made systematic studies. One should average over several chips and use some solid average there. Best is if you try both formulas and check what give you the better linearity.

ELOG V3.1.5-3fb85fa6