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 |