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 |