Newer
Older
from builtins import range
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
from datetime import datetime
from .. import ChannelConverter, TimeseriesUtility
from ..TimeseriesFactoryException import TimeseriesFactoryException
from obspy.core import Stream
# For binlog, need to track previous volt/bin values.
h_prev = [99.999999, 999]
e_prev = [99.999999, 999]
z_prev = [99.999999, 999]
# Use seperate HEZ buffers to group binlog output by component.
Hbuf = []
Ebuf = []
Zbuf = []
class BinLogWriter(object):
"""BinLog writer.
"""
def __init__(self):
return
def write(self, out, timeseries, channels):
"""Write parsed timeseries info to binlog file.
Parameters
----------
out : file object
File object to be written to. Could be stdout.
timeseries : obspy.core.stream
Timeseries object with data to be written.
channels : array_like
Channels to be written from timeseries object.
"""
for channel in channels:
if timeseries.select(channel=channel).count() == 0:
raise TimeseriesFactoryException(
'Missing channel "%s" for output, available channels %s' %
(channel, str(TimeseriesUtility.get_channels(timeseries))))
stats = timeseries[0].stats
out.write(self._format_header(stats))
self._format_data(timeseries, channels)
if (len(Hbuf) + len(Ebuf) + len(Zbuf)) > 0:
out.write(' C Date Time DaySec Bin change'
' Voltage change\n')
out.write(''.join(Hbuf))
out.write('\n')
out.write(''.join(Ebuf))
out.write('\n')
out.write(''.join(Zbuf))
else:
out.write('*** No Bin Changes Found ***\n')
def _format_header(self, stats):
"""format headers for BinLog file
Parameters
----------
stats : List
An object with the header values to be written.
Returns
-------
str
A string formatted to be a single header line in a BinLog file.
"""
buf = []
observatory = stats.station
sttdate = stats.starttime.strftime("%d-%b-%y")
enddate = stats.endtime.strftime("%d-%b-%y")
buf.append('Bin Change Report: ' + observatory + ' Start Day: ' +
sttdate + ' End Day: ' + enddate + '\n\n')
return ''.join(buf)
def _format_data(self, timeseries, channels):
"""Format all data lines.
Parameters
----------
timeseries : obspy.core.Stream
Stream containing traces with channel listed in channels
channels : sequence
List and order of channel values to output.
Returns
-------
str
A string formatted to be the data lines in a BinLog file.
"""
# create new stream
timeseriesLocal = Stream()
# Use a copy of the trace so that we don't modify the original.
for trace in timeseries:
traceLocal = trace.copy()
if traceLocal.stats.channel == 'D':
traceLocal.data = \
ChannelConverter.get_minutes_from_radians(traceLocal.data)
# TODO - we should look into multiplying the trace all at once
# like this, but this gives an error on Windows at the moment.
# traceLocal.data = \
# numpy.round(numpy.multiply(traceLocal.data, 100)).astype(int)
timeseriesLocal.append(traceLocal)
traces = [timeseriesLocal.select(channel=c)[0] for c in channels]
starttime = float(traces[0].stats.starttime)
delta = traces[0].stats.delta
for i in range(len(traces[0].data)):
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
self._format_values(
datetime.utcfromtimestamp(starttime + i * delta),
(t.data[i] for t in traces))
return
def _format_values(self, time, values):
"""Format one line of data values.
Parameters
----------
time : datetime
Timestamp for values.
values : sequence
List and order of channel values to output.
Returns
-------
unicode
Formatted line containing values.
"""
tt = time.timetuple()
totalMinutes = int(tt.tm_hour * 3600 + tt.tm_min * 60 + tt.tm_sec)
timestr = '{0.tm_year:0>4d}-{0.tm_mon:0>2d}-{0.tm_mday:0>2d} ' \
'{0.tm_hour:0>2d}:{0.tm_min:0>2d}:{0.tm_sec:0>2d}' \
' ({1:0>5d})'. \
format(tt, totalMinutes)
# init volt/bin vals to dead
vdead = 99.999999
bdead = 999
vblist = [vdead, bdead, vdead, bdead, vdead, bdead]
# now "un-dead" the non-nans, format volts as float, bins as int
for idx, valx in enumerate(values):
if ~numpy.isnan(valx):
if idx == 0 or idx == 2 or idx == 4:
vblist[idx] = valx / 1000.
else:
vblist[idx] = int(valx)
if vblist[1] != 999 and h_prev[1] != 999 and vblist[1] != h_prev[1]:
Hbuf.append('{0: >3s} {1:>s} '
'{2: >4d} to {3: >4d} {4: >10.6f} to {5: >10.6f}\n'.
format('(H)', timestr, h_prev[1],
vblist[1], h_prev[0], vblist[0]))
if vblist[3] != 999 and e_prev[1] != 999 and vblist[3] != e_prev[1]:
Ebuf.append('{0: >3s} {1:>s} '
'{2: >4d} to {3: >4d} {4: >10.6f} to {5: >10.6f}\n'.
format('(E)', timestr, e_prev[1],
vblist[3], e_prev[0], vblist[2]))
if vblist[5] != 999 and z_prev[1] != 999 and vblist[5] != z_prev[1]:
Zbuf.append('{0: >3s} {1:>s} '
'{2: >4d} to {3: >4d} {4: >10.6f} to {5: >10.6f}\n'.
format('(Z)', timestr, z_prev[1],
vblist[5], z_prev[0], vblist[4]))
h_prev[0] = vblist[0]
h_prev[1] = vblist[1]
e_prev[0] = vblist[2]
e_prev[1] = vblist[3]
z_prev[0] = vblist[4]
z_prev[1] = vblist[5]
return
@classmethod
def format(self, timeseries, channels):
"""Get a BinLog formatted string.
Calls write() with a StringIO, and returns the output.
Parameters
----------
timeseries : obspy.core.Stream
Stream containing traces with channel listed in channels
channels : sequence
List and order of channel values to output.
Returns
-------
unicode
BinLog formatted string.
"""
out = StringIO()
writer = BinLogWriter()
writer.write(out, timeseries, channels)
return out.getvalue()