forked from bgamari/timetag-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimetag_bin.cpp
178 lines (151 loc) · 5.75 KB
/
timetag_bin.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// vim: set fileencoding=utf-8 noet :
/* timetag-tools - Tools for UMass FPGA timetagger
*
* Copyright © 2010 Ben Gamari
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/ .
*
* Author: Ben Gamari <[email protected]>
*/
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <boost/program_options.hpp>
#include "record.h"
namespace po = boost::program_options;
/*
*
* Temporally bins a photon stream
*
* Usage:
* bin_photons [--text] [BIN_LENGTH]
*
* Where BIN_LENGTH is the length of each bin in counter units.
*
* Input:
* A binary photon stream
*
* Output:
* A binary stream of bin_records or a textual representation if
* --text is given.
*
* Notes:
* We handle wrap-around here by simply keeping all times as 64-bit and
* assume that we wrap-around at most once. With 1 nanosecond clock units,
* this gives us 500 years of acquisition time.
*
*/
/*
* bin record format
*/
struct bin_record {
int chan_n;
uint64_t start_time;
unsigned int count;
unsigned int lost;
};
struct input_channel {
int chan_n;
count_t bin_start;
unsigned int count;
unsigned int lost; // IMPORTANT: This is not a count of lost photons, only
// potential sprees of lost photons
input_channel(int chan_n) :
chan_n(chan_n), bin_start(0), count(0), lost(0) { }
};
void print_text_bin(bin_record b) {
printf("%2d\t%10lu\t%5u\t%5u\n", b.chan_n, b.start_time, b.count, b.lost);
}
void print_bin(bin_record b) {
if (write(1, &b, sizeof(bin_record)) < (int) sizeof(bin_record))
throw new std::runtime_error("failed to write bin");
}
void handle_record(std::vector<input_channel>& chans, count_t bin_length, record& r,
std::function<void(bin_record)> print, bool with_zeros=true) {
std::bitset<4> channels = r.get_channels();
uint64_t time = r.get_time();
for (auto c=chans.begin(); c != chans.end(); c++) {
if (time >= (c->bin_start + bin_length)) {
uint64_t new_bin_start = (time / bin_length) * bin_length;
// First print photons in last bin
struct bin_record rec = { c->chan_n, c->bin_start, c->count, c->lost };
if (with_zeros || c->count > 0)
print(rec);
// Then print zero bins
if (with_zeros) {
for (uint64_t t=c->bin_start+bin_length; t < new_bin_start; t += bin_length) {
struct bin_record rec = { c->chan_n, t, 0, 0 };
print(rec);
}
}
// Then start our new bin
c->lost = 0;
c->count = 0;
c->bin_start = new_bin_start;
}
if (r.get_lost_flag())
c->lost++;
if (r.get_type() == record::type::STROBE && channels[c->chan_n])
c->count++;
}
}
int main(int argc, char** argv) {
count_t bin_length = 0;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "Display help message")
("bin-width", po::value<count_t>(&bin_length)->required(), "The desired bin width")
("text,t", "Produce textual representation instead of usual binary output")
("omit-zeros,z", "Omit empty bins");
po::positional_options_description pd;
pd.add("bin-width", 1);
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).options(desc).positional(pd).run(), vm);
po::notify(vm);
if (vm.count("help")) {
std::cout << desc << "\n";
return 0;
}
bool text = vm.count("text");
bool with_zeros = ! vm.count("omit-zeros");
std::vector<input_channel> chans = {
{ input_channel(0) },
{ input_channel(1) },
{ input_channel(2) },
{ input_channel(3) },
};
record_stream stream(stdin);
// Disable write buffering
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IOFBF, sizeof(record)*30);
/*
* We throw away the first photon to get the bin start times.
*/
{
record r = stream.get_record();
uint64_t time = r.get_time();
for (auto c=chans.begin(); c != chans.end(); c++)
c->bin_start = (time / bin_length) * bin_length;
}
std::function<void(struct bin_record)> print = text ? print_text_bin : print_bin;
while (true) {
try {
record r = stream.get_record();
handle_record(chans, bin_length, r, print, with_zeros);
} catch (end_stream e) { break; }
}
return 0;
}