-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathfil_reader.cpp
More file actions
156 lines (144 loc) · 5.14 KB
/
Copy pathfil_reader.cpp
File metadata and controls
156 lines (144 loc) · 5.14 KB
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
#include <assert.h>
#include <fstream>
#include <iostream>
#include <math.h>
#include <vector>
#include "fil_reader.h"
using namespace std;
/*
ra and dec are stored in fil files as:
HHMMSS.S
This converts to the more-sane "number of hours with a fraction" format.
*/
double convertFromSigprocRaOrDec(double sigproc) {
bool negative = sigproc < 0;
double abs_val = fabs(sigproc);
int hours_or_degrees = floor(abs_val / 10000.0);
double remnant = abs_val - (hours_or_degrees * 10000.0);
int minutes = floor(remnant / 100.0);
double seconds = remnant - (minutes * 100.0);
double abs_answer = hours_or_degrees + (minutes / 60.0) + (seconds / 3600.0);
return negative ? -abs_answer : abs_answer;
}
/*
Opens a sigproc filterbank file for reading.
This class is not threadsafe.
*/
FilReader::FilReader(const string& filename) : FilterbankFileReader(filename),
file(filename, ifstream::binary) {
// Read the headers
// Note: this code will fail on big-endian systems.
// If this is not working, you may want to compare it to the code at:
// https://github.com/UCBerkeleySETI/blimpy/blob/master/blimpy/io/sigproc.py
string header_start = readString();
if (header_start != "HEADER_START") {
cerr << "The file " << filename << " did not start with HEADER_START. "
<< "Is it really a .fil file?\n";
exit(1);
}
while (true) {
string attr_name = readString();
cerr << "attr name: " << attr_name << endl;
if (attr_name == "telescope_id") {
telescope_id = readBasic<int>();
} else if (attr_name == "machine_id") {
readBasic<int>();
} else if (attr_name == "data_type") {
readBasic<int>();
} else if (attr_name == "barycentric") {
readBasic<int>();
} else if (attr_name == "pulsarcentric") {
readBasic<int>();
} else if (attr_name == "nbits") {
int nbits = readBasic<int>();
// We only handle 32-bit float data
assert(nbits == 32);
} else if (attr_name == "nsamples") {
num_timesteps = readBasic<int>();
} else if (attr_name == "nchans") {
num_channels = readBasic<int>();
} else if (attr_name == "nifs") {
readBasic<int>();
} else if (attr_name == "nbeams") {
readBasic<int>();
} else if (attr_name == "ibeam") {
readBasic<int>();
} else if (attr_name == "rawdatafile") {
readString();
} else if (attr_name == "source_name") {
source_name = readString();
} else if (attr_name == "az_start") {
readBasic<double>();
} else if (attr_name == "za_start") {
readBasic<double>();
} else if (attr_name == "tstart") {
tstart = readBasic<double>();
} else if (attr_name == "tsamp") {
tsamp = readBasic<double>();
} else if (attr_name == "fch1") {
fch1 = readBasic<double>();
} else if (attr_name == "foff") {
foff = readBasic<double>();
} else if (attr_name == "refdm") {
readBasic<double>();
} else if (attr_name == "period") {
readBasic<double>();
} else if (attr_name == "src_raj") {
src_raj = convertFromSigprocRaOrDec(readBasic<double>());
} else if (attr_name == "src_dej") {
src_dej = convertFromSigprocRaOrDec(readBasic<double>());
} else if (attr_name == "HEADER_END") {
break;
} else {
cerr << "unhandled attr name: " << attr_name << endl;
exit(1);
}
}
// We have finally figured out where the actual data starts.
data_start = file.tellg();
// Sometimes the number of timesteps isn't in the header, because the process writing
// the file didn't know how long it was going to be when it wrote the headers.
// So figure out the amount of data based on file size.
file.seekg(0, file.end);
long num_data_bytes = file.tellg() - data_start;
if (num_data_bytes % sizeof(float) != 0) {
cerr << "indivisible amount of data is " << num_data_bytes << " bytes\n";
exit(1);
}
long num_floats = num_data_bytes / sizeof(float);
if (num_floats % num_channels != 0) {
cerr << "we have " << num_floats << " which does not divide into " << num_channels
<< " frequencies\n";
exit(1);
}
long inferred_num_timesteps = num_floats / num_channels;
if (num_timesteps == 0) {
num_timesteps = inferred_num_timesteps;
} else if (num_timesteps != inferred_num_timesteps) {
cerr << "header num timesteps is " << num_timesteps
<< " but inferred num timesteps is " << inferred_num_timesteps << endl;
exit(1);
}
inferMetadata();
}
template <class T> T FilReader::readBasic() {
T answer;
file.read((char*)&answer, sizeof(answer));
return answer;
}
// Strings are encoded in filterbank headers as first a uint32 containing the string length,
// then the string data
string FilReader::readString() {
uint32_t num_bytes = readBasic<uint32_t>();
assert(num_bytes < 256);
vector<char> buffer(num_bytes);
file.read(&buffer[0], buffer.size());
string answer(buffer.begin(), buffer.end());
return answer;
}
// Loads the data in row-major order.
void FilReader::loadCoarseChannel(int i, FilterbankBuffer* buffer) const {
cerr << "TODO: implement FilReader::loadCoarseChannel\n";
exit(1);
}
FilReader::~FilReader() {}