Rev 197 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 195 | f9daq | 1 | /* | 
        
| 2 |    Name:           read_binary.cpp | 
        ||
| 3 |    Created by:     Stefan Ritt <stefan.ritt@psi.ch> | 
        ||
| 4 |    Date:           July 30th, 2014 | 
        ||
| 5 | |||
| 6 |    Purpose:        Example file to read binary data saved by DRSOsc. | 
        ||
| 7 | |||
| 8 |    Compile and run it with: | 
        ||
| 9 | |||
| 10 |       gcc -o read_binary read_binary.cpp | 
        ||
| 11 | |||
| 12 |       ./read_binary <filename> | 
        ||
| 13 | |||
| 14 |    This program assumes that a pulse from a signal generator is split | 
        ||
| 15 |    and fed into channels #1 and #2. It then calculates the time difference | 
        ||
| 16 |    between these two pulses to show the performance of the DRS board | 
        ||
| 17 |    for time measurements. | 
        ||
| 18 | |||
| 19 |    $Id: read_binary.cpp 22321 2016-08-25 12:26:12Z ritt $ | 
        ||
| 20 | */ | 
        ||
| 21 | |||
| 22 | #include <stdio.h> | 
        ||
| 23 | #include <fcntl.h> | 
        ||
| 24 | #include <unistd.h> | 
        ||
| 25 | #include <string.h> | 
        ||
| 26 | #include <math.h> | 
        ||
| 27 | |||
| 28 | typedef struct {  | 
        ||
| 29 | char tag[3];  | 
        ||
| 30 | char version;  | 
        ||
| 31 | } FHEADER;  | 
        ||
| 32 | |||
| 33 | typedef struct {  | 
        ||
| 34 | char time_header[4];  | 
        ||
| 35 | } THEADER;  | 
        ||
| 36 | |||
| 37 | typedef struct {  | 
        ||
| 38 | char bn[2];  | 
        ||
| 39 | unsigned short board_serial_number;  | 
        ||
| 40 | } BHEADER;  | 
        ||
| 41 | |||
| 42 | typedef struct {  | 
        ||
| 43 | char event_header[4];  | 
        ||
| 44 | unsigned int event_serial_number;  | 
        ||
| 45 | unsigned short year;  | 
        ||
| 46 | unsigned short month;  | 
        ||
| 47 | unsigned short day;  | 
        ||
| 48 | unsigned short hour;  | 
        ||
| 49 | unsigned short minute;  | 
        ||
| 50 | unsigned short second;  | 
        ||
| 51 | unsigned short millisecond;  | 
        ||
| 52 | unsigned short range;  | 
        ||
| 53 | } EHEADER;  | 
        ||
| 54 | |||
| 55 | typedef struct {  | 
        ||
| 56 | char tc[2];  | 
        ||
| 57 | unsigned short trigger_cell;  | 
        ||
| 58 | } TCHEADER;  | 
        ||
| 59 | |||
| 60 | typedef struct {  | 
        ||
| 61 | char c[1];  | 
        ||
| 62 | char cn[3];  | 
        ||
| 63 | } CHEADER;  | 
        ||
| 64 | |||
| 65 | /*-----------------------------------------------------------------------------*/ | 
        ||
| 66 | |||
| 67 | int main(int argc, const char * argv[])  | 
        ||
| 68 | { | 
        ||
| 69 |    FHEADER  fh; | 
        ||
| 70 |    THEADER  th; | 
        ||
| 71 |    BHEADER  bh; | 
        ||
| 72 |    EHEADER  eh; | 
        ||
| 73 |    TCHEADER tch; | 
        ||
| 74 |    CHEADER  ch; | 
        ||
| 75 | |||
| 76 | unsigned int scaler;  | 
        ||
| 77 | unsigned short voltage[1024];  | 
        ||
| 78 | double waveform[16][4][1024], time[16][4][1024];  | 
        ||
| 79 | float bin_width[16][4][1024];  | 
        ||
| 80 | int i, j, b, chn, n, chn_index, n_boards;  | 
        ||
| 81 | double t1, t2, dt;  | 
        ||
| 82 | char filename[256];  | 
        ||
| 83 | |||
| 84 | int ndt;  | 
        ||
| 85 | double threshold, sumdt, sumdt2;  | 
        ||
| 86 | |||
| 87 | if (argc > 1)  | 
        ||
| 88 | strcpy(filename, argv[1]);  | 
        ||
| 89 | else {  | 
        ||
| 90 | printf("Usage: read_binary <filename>\n");  | 
        ||
| 91 | return 0;  | 
        ||
| 92 |    } | 
        ||
| 93 | |||
| 94 |    // open the binary waveform file | 
        ||
| 95 | FILE *f = fopen(filename, "rb");  | 
        ||
| 96 | if (f == NULL) {  | 
        ||
| 97 | printf("Cannot find file \'%s\'\n", filename);  | 
        ||
| 98 | return 0;  | 
        ||
| 99 |    } | 
        ||
| 100 | |||
| 101 |    // read file header | 
        ||
| 102 | fread(&fh, sizeof(fh), 1, f);  | 
        ||
| 103 | if (fh.tag[0] != 'D' || fh.tag[1] != 'R' || fh.tag[2] != 'S') {  | 
        ||
| 104 | printf("Found invalid file header in file \'%s\', aborting.\n", filename);  | 
        ||
| 105 | return 0;  | 
        ||
| 106 |    } | 
        ||
| 107 | |||
| 108 | if (fh.version != '2') {  | 
        ||
| 109 | printf("Found invalid file version \'%c\' in file \'%s\', should be \'2\', aborting.\n", fh.version, filename);  | 
        ||
| 110 | return 0;  | 
        ||
| 111 |    } | 
        ||
| 112 | |||
| 113 |    // read time header | 
        ||
| 114 | fread(&th, sizeof(th), 1, f);  | 
        ||
| 115 | if (memcmp(th.time_header, "TIME", 4) != 0) {  | 
        ||
| 116 | printf("Invalid time header in file \'%s\', aborting.\n", filename);  | 
        ||
| 117 | return 0;  | 
        ||
| 118 |    } | 
        ||
| 119 | |||
| 120 | for (b = 0 ; ; b++) {  | 
        ||
| 121 |       // read board header | 
        ||
| 122 | fread(&bh, sizeof(bh), 1, f);  | 
        ||
| 123 | if (memcmp(bh.bn, "B#", 2) != 0) {  | 
        ||
| 124 |          // probably event header found | 
        ||
| 125 | fseek(f, -4, SEEK_CUR);  | 
        ||
| 126 | break;  | 
        ||
| 127 |       } | 
        ||
| 128 | |||
| 129 | printf("Found data for board #%d\n", bh.board_serial_number);  | 
        ||
| 130 | |||
| 131 |       // read time bin widths | 
        ||
| 132 | memset(bin_width[b], sizeof(bin_width[0]), 0);  | 
        ||
| 133 | for (chn=0 ; chn<5 ; chn++) {  | 
        ||
| 134 | fread(&ch, sizeof(ch), 1, f);  | 
        ||
| 135 | if (ch.c[0] != 'C') {  | 
        ||
| 136 |             // event header found | 
        ||
| 137 | fseek(f, -4, SEEK_CUR);  | 
        ||
| 138 | break;  | 
        ||
| 139 |          } | 
        ||
| 140 | i = ch.cn[2] - '0' - 1;  | 
        ||
| 141 | printf("Found timing calibration for channel #%d\n", i+1);  | 
        ||
| 142 | fread(&bin_width[b][i][0], sizeof(float), 1024, f);  | 
        ||
| 143 |          // fix for 2048 bin mode: double channel | 
        ||
| 144 | if (bin_width[b][i][1023] > 10 || bin_width[b][i][1023] < 0.01) {  | 
        ||
| 145 | for (j=0 ; j<512 ; j++)  | 
        ||
| 146 | bin_width[b][i][j+512] = bin_width[b][i][j];  | 
        ||
| 147 |          } | 
        ||
| 148 |       } | 
        ||
| 149 |    } | 
        ||
| 150 | n_boards = b;  | 
        ||
| 151 | |||
| 152 |    // initialize statistics | 
        ||
| 153 | ndt = 0;  | 
        ||
| 154 | sumdt = sumdt2 = 0;  | 
        ||
| 155 | |||
| 156 |    // loop over all events in the data file | 
        ||
| 157 | for (n=0 ; ; n++) {  | 
        ||
| 158 |       // read event header | 
        ||
| 159 | i = (int)fread(&eh, sizeof(eh), 1, f);  | 
        ||
| 160 | if (i < 1)  | 
        ||
| 161 | break;  | 
        ||
| 162 | |||
| 163 | printf("Found event #%d %d %d\n", eh.event_serial_number, eh.second, eh.millisecond);  | 
        ||
| 164 | |||
| 165 |       // loop over all boards in data file | 
        ||
| 166 | for (b=0 ; b<n_boards ; b++) {  | 
        ||
| 167 | |||
| 168 |          // read board header | 
        ||
| 169 | fread(&bh, sizeof(bh), 1, f);  | 
        ||
| 170 | if (memcmp(bh.bn, "B#", 2) != 0) {  | 
        ||
| 171 | printf("Invalid board header in file \'%s\', aborting.\n", filename);  | 
        ||
| 172 | return 0;  | 
        ||
| 173 |          } | 
        ||
| 174 | |||
| 175 |          // read trigger cell | 
        ||
| 176 | fread(&tch, sizeof(tch), 1, f);  | 
        ||
| 177 | if (memcmp(tch.tc, "T#", 2) != 0) {  | 
        ||
| 178 | printf("Invalid trigger cell header in file \'%s\', aborting.\n", filename);  | 
        ||
| 179 | return 0;  | 
        ||
| 180 |          } | 
        ||
| 181 | |||
| 182 | if (n_boards > 1)  | 
        ||
| 183 | printf("Found data for board #%d\n", bh.board_serial_number);  | 
        ||
| 184 | |||
| 185 |          // reach channel data | 
        ||
| 186 | for (chn=0 ; chn<4 ; chn++) {  | 
        ||
| 187 | |||
| 188 |             // read channel header | 
        ||
| 189 | fread(&ch, sizeof(ch), 1, f);  | 
        ||
| 190 | if (ch.c[0] != 'C') {  | 
        ||
| 191 |                // event header found | 
        ||
| 192 | fseek(f, -4, SEEK_CUR);  | 
        ||
| 193 | break;  | 
        ||
| 194 |             } | 
        ||
| 195 | chn_index = ch.cn[2] - '0' - 1;  | 
        ||
| 196 | fread(&scaler, sizeof(int), 1, f);  | 
        ||
| 197 | fread(voltage, sizeof(short), 1024, f);  | 
        ||
| 198 | |||
| 199 | for (i=0 ; i<1024 ; i++) {  | 
        ||
| 200 |                // convert data to volts | 
        ||
| 201 | waveform[b][chn_index][i] = (voltage[i] / 65536. + eh.range/1000.0 - 0.5);  | 
        ||
| 202 | |||
| 203 |                // calculate time for this cell | 
        ||
| 204 | for (j=0,time[b][chn_index][i]=0 ; j<i ; j++)  | 
        ||
| 205 | time[b][chn_index][i] += bin_width[b][chn_index][(j+tch.trigger_cell) % 1024];  | 
        ||
| 206 |             } | 
        ||
| 207 |          } | 
        ||
| 208 | |||
| 209 |          // align cell #0 of all channels | 
        ||
| 210 | t1 = time[b][0][(1024-tch.trigger_cell) % 1024];  | 
        ||
| 211 | for (chn=1 ; chn<4 ; chn++) {  | 
        ||
| 212 | t2 = time[b][chn][(1024-tch.trigger_cell) % 1024];  | 
        ||
| 213 | dt = t1 - t2;  | 
        ||
| 214 | for (i=0 ; i<1024 ; i++)  | 
        ||
| 215 | time[b][chn][i] += dt;  | 
        ||
| 216 |          } | 
        ||
| 217 | |||
| 218 | t1 = t2 = 0;  | 
        ||
| 219 | threshold = 0.3;  | 
        ||
| 220 | |||
| 221 |          // find peak in channel 1 above threshold | 
        ||
| 222 | for (i=0 ; i<1022 ; i++)  | 
        ||
| 223 | if (waveform[b][0][i] < threshold && waveform[b][0][i+1] >= threshold) {  | 
        ||
| 224 | 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];  | 
        ||
| 225 | break;  | 
        ||
| 226 |             } | 
        ||
| 227 | |||
| 228 |          // find peak in channel 2 above threshold | 
        ||
| 229 | for (i=0 ; i<1022 ; i++)  | 
        ||
| 230 | if (waveform[b][1][i] < threshold && waveform[b][1][i+1] >= threshold) {  | 
        ||
| 231 | 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];  | 
        ||
| 232 | break;  | 
        ||
| 233 |             } | 
        ||
| 234 | |||
| 235 |          // calculate distance of peaks with statistics | 
        ||
| 236 | if (t1 > 0 && t2 > 0) {  | 
        ||
| 237 | ndt++;  | 
        ||
| 238 | dt = t2 - t1;  | 
        ||
| 239 | sumdt += dt;  | 
        ||
| 240 | sumdt2 += dt*dt;  | 
        ||
| 241 |          } | 
        ||
| 242 |       } | 
        ||
| 243 |    } | 
        ||
| 244 | |||
| 245 |    // print statistics | 
        ||
| 246 | printf("dT = %1.3lfns +- %1.1lfps\n", sumdt/ndt, 1000*sqrt(1.0/(ndt-1)*(sumdt2-1.0/ndt*sumdt*sumdt)));  | 
        ||
| 247 | |||
| 248 | return 1;  | 
        ||
| 249 | } | 
        ||
| 250 |