-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathheader.js
executable file
·184 lines (137 loc) · 4.58 KB
/
header.js
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
178
179
180
181
182
183
184
function mSEEDHeader(data) {
/* Class mSEEDHeader
*
* Container for the fixed header section
* of a miniSEED record
*/
this.sequenceNumber = data.toString("ascii", 0, 6);
this.dataQuality = data.toString("ascii", 6, 7);
this.encoding = null;
this.byteOrder = null;
this.timingQuality = null;
this.microSeconds = null;
this.recordLength = null;
this.sampleRate = null;
this.nFrames = null;
this.nBlockettes = data.readUInt8(39);
// Go over the mSEED blockette chain
this.readBlocketteChain(data);
// Only do big endian
if(!this.byteOrder) {
throw("Little endian byte order not supported.");
}
this.nSamples = data.readUInt16BE(30);
// Read the sample rate if unset by blockette 500
if(this.sampleRate === null) {
this.sampleRate = this.readSampleRate(data);
}
// Read the mSEED header bit flags
this.readBitFlags(data);
this.timingCorrection = data.readInt32BE(40);
this.readRecordStart(data);
this.end = this.start + 1E3 * (this.nSamples / this.sampleRate);
this.SetStreamId(data);
}
mSEEDHeader.prototype.readSampleRate = function(data) {
/* Function mSEEDHeader.readSampleRate
*
* Calculates the sample rate from the multiplication factor
*/
var sampleRateFactor = data.readInt16BE(32);
var sampleRateMult = data.readInt16BE(34);
// Calculate the sample rate from the factor and multiplier
if(sampleRateFactor > 0 && sampleRateMult > 0) {
return sampleRateMult * sampleRateFactor;
} else if(sampleRateFactor > 0 && sampleRateMult < 0) {
return -sampleRateFactor / sampleRateMult;
} else if(sampleRateFactor < 0 && sampleRateMult > 0) {
return -sampleRateMult / sampleRateFactor;
} else if(sampleRateFactor < 0 && sampleRateMult < 0) {
return 1 / (sampleRateFactor * sampleRateMult);
}
return null;
}
mSEEDHeader.prototype.readBitFlags = function(data) {
/* Function mSEEDHeader.readBitFlags
*
* Reads the mSEED header bit-flags
*/
this.flags = {
"activity": data.readUInt8(36),
"clock": data.readUInt8(37),
"quality": data.readUInt8(38)
}
}
mSEEDHeader.prototype.readBlocketteChain = function(data) {
/* Function mSEEDHeader.readBlocketteChain
*
* Reads the mSEED blockette chain and sets values
*/
var blocketteStart = data.readUInt16BE(46);
var blockette;
var blocketteCounter = 0;
// Run over the blockette chain
while(blocketteStart) {
blocketteCounter++;
blockette = data.readUInt16BE(blocketteStart);
switch(blockette) {
// Case of blockette 1000
case 1000:
this.encoding = data.readUInt8(blocketteStart + 4);
this.byteOrder = data.readUInt8(blocketteStart + 5);
this.recordLength = 1 << data.readUInt8(blocketteStart + 6);
break;
// Blockette 1001: read the microseconds and number of data frames
case 1001:
this.timingQuality = data.readUInt8(blocketteStart + 4);
this.microSeconds = data.readInt8(blocketteStart + 5);
this.nFrames = data.readUInt8(blocketteStart + 7);
break;
// Blockette 100: read the overruling sample rate
case 100:
this.sampleRate = data.readFloatBE(blocketteStart + 4);
break;
}
blocketteStart = data.readUInt16BE(blocketteStart + 2);
}
// Sanity check on the number of blockettes
if(blocketteCounter !== this.nBlockettes) {
throw("Number of blockettes does not match number encountered.");
}
}
mSEEDHeader.prototype.SetStreamId = function(data) {
/* Function mSEEDHeader.SetStreamId
*
* Reads and sets stream parameters
* according to the mSEED Manual
*/
// Read the stream identifiers and trim any padded white spaces
this.station = data.toString("ascii", 8, 13).trim();
this.location = data.toString("ascii", 13, 15).trim();
this.channel = data.toString("ascii", 15, 18).trim();
this.network = data.toString("ascii", 18, 20).trim();
}
mSEEDHeader.prototype.readRecordStart = function(data) {
/* Function mSEEDHeader.readRecordStart
*
* Reads record starttime from BTIME encoding
* according to the mSEED Manual
*/
// Get the record starttime truncated to miliseconds
// We cannot go under submilisecond precision
this.start = new Date(
data.readUInt16BE(20),
0,
1,
data.readUInt8(24),
data.readUInt8(25),
data.readUInt8(26),
(1E-1 * data.readUInt16BE(28)) | 0
).setDate(data.readUInt16BE(22));
// Apply timing correction (0.0001 seconds)
// We only have milisecond precision
if(!(this.flags.activity & 2)) {
this.start = this.start + ((1E-1 * this.timingCorrection) | 0);
}
}
module.exports = mSEEDHeader;