~awuerl/blitzortung-python/master

« back to all changes in this revision

Viewing changes to blitzortung/data.py

  • Committer: Andreas Würl
  • Date: 2012-01-29 15:34:23 UTC
  • Revision ID: git-v1:cdca5487c8322e426d0859349fa52643e0a47019
added python code from blitzortung-tracker-tools

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf8 -*-
 
2
 
 
3
'''
 
4
 
 
5
@author Andreas Würl
 
6
 
 
7
'''
 
8
 
 
9
import datetime, pytz
 
10
import math
 
11
import urllib
 
12
#import shapely.geometry
 
13
import pyproj
 
14
 
 
15
import geom
 
16
import files
 
17
 
 
18
class TimeRange(object):
 
19
 
 
20
  def __init__(self, endTime, deltaTime=datetime.timedelta(hours=2)):
 
21
    self.endTime = endTime
 
22
    self.startTime = endTime - deltaTime
 
23
 
 
24
  def __str__(self):
 
25
    return "['" + str(self.startTime) + "':'" + str(self.endTime) + "']"
 
26
 
 
27
  def getStartTime(self):
 
28
    return self.startTime
 
29
 
 
30
  def getEndTime(self):
 
31
    return self.endTime
 
32
 
 
33
  def getEndMinute(self):
 
34
    return self.getEndTime() - datetime.timedelta(minutes=1)
 
35
 
 
36
  def contains(self, time):
 
37
    return time >= self.getStartTime() and time <= self.getEndTime()
 
38
 
 
39
class TimeInterval(TimeRange):
 
40
 
 
41
  def __init__(self, endTime, deltaTime=datetime.timedelta(hours=1)):
 
42
    self.deltaTime = deltaTime
 
43
    TimeRange.__init__(self, self.roundTime(endTime), deltaTime)
 
44
 
 
45
  def __str__(self):
 
46
    return "['" + str(self.startTime) + "':'" + str(self.endTime) + "'," + str(self.deltaTime) + "]"
 
47
 
 
48
  def totalSeconds(self, time):
 
49
    ' return the total seconds of the given time or datetime (relative to midnight) '
 
50
 
 
51
    if isinstance(time, datetime.datetime):
 
52
      return time.hour * 3600 + time.minute * 60 + time.second
 
53
    elif isinstance(time, datetime.timedelta):
 
54
      return time.seconds + time.days * 24 * 3600
 
55
    else:
 
56
      raise Exception("unhandled type"+type(time))
 
57
 
 
58
  def roundTime(self, time):
 
59
    deltaSeconds = self.totalSeconds(self.deltaTime)
 
60
 
 
61
    seconds =  self.totalSeconds(time)
 
62
    seconds /= deltaSeconds
 
63
    seconds *= deltaSeconds
 
64
 
 
65
    if isinstance(time, datetime.datetime):
 
66
      return time.replace(hour = seconds/3600, minute= seconds / 60 % 60, second= seconds % 60, microsecond=0)
 
67
    else:
 
68
      return datetime.timedelta(seconds=seconds)
 
69
 
 
70
  def hasNext(self):
 
71
    return False
 
72
 
 
73
  def next(self):
 
74
    raise Exception(' no next interval ')
 
75
 
 
76
  def getCenterTime(self):
 
77
    return self.startTime + self.deltaTime / 2
 
78
 
 
79
class TimeIntervals(TimeInterval):
 
80
 
 
81
  def __init__(self, endTime, deltaTime=datetime.timedelta(minutes=15), totalDuration=datetime.timedelta(days=1)):
 
82
    TimeInterval.__init__(self, endTime, deltaTime)
 
83
 
 
84
    self.totalDuration = self.roundTime(totalDuration)
 
85
 
 
86
    self.startTime = self.endTime - self.totalDuration
 
87
 
 
88
  def hasNext(self):
 
89
    return self.startTime + self.deltaTime < self.endTime
 
90
 
 
91
  def next(self):
 
92
    if self.hasNext():
 
93
      self.startTime += self.deltaTime
 
94
      return self.startTime
 
95
    else:
 
96
      raise Exception('no more time intervals')
 
97
 
 
98
  def getEndTime(self):
 
99
    return self.startTime + self.deltaTime
 
100
 
 
101
class Point(object):
 
102
 
 
103
  __geod = pyproj.Geod(ellps='WGS84', units='m')
 
104
 
 
105
  def __init__(self, x, y):
 
106
    self.x = x
 
107
    self.y = y
 
108
 
 
109
  def __invgeod(self, other):
 
110
    return Point.__geod.inv(self.x, self.y, other.x, other.y)
 
111
 
 
112
  def distance(self, other):
 
113
    return self.__invgeod(other)[2]
 
114
 
 
115
  def azimuth(self, other):
 
116
    return self.__invgeod(other)[0]
 
117
 
 
118
class Event(Point):
 
119
 
 
120
  timeformat = '%Y-%m-%d %H:%M:%S.%f'
 
121
 
 
122
  def __init__(self, x, y, time):
 
123
    Point.__init__(self, x, y)
 
124
    if isinstance(time, datetime.datetime):
 
125
      self.time = time
 
126
      self.nanoseconds = 0
 
127
    elif isinstance(time, str):
 
128
      self.set_time_from_string(time)
 
129
      
 
130
  def set_time_from_string(self, time):
 
131
    self.nanoseconds = int(time[-3:])
 
132
    time = datetime.datetime.strptime(time[:-3], Event.timeformat)
 
133
    self.time = time.replace(tzinfo=pytz.UTC)
 
134
 
 
135
  def set_time(self, time):
 
136
    self.time = time
 
137
 
 
138
  def get_time(self):
 
139
    return self.time
 
140
 
 
141
  def set_nanoseconds(self, nanoseconds):
 
142
    self.nanoseconds = nanoseconds
 
143
 
 
144
  def get_nanoseconds(self):
 
145
    return self.nanoseconds
 
146
 
 
147
  def difference(self, other):
 
148
    return self.time - other.time
 
149
 
 
150
  def nanoseconds_difference(self, other):
 
151
    return self.nanoseconds - other.nanoseconds
 
152
 
 
153
class RawEvent(Event):
 
154
#2011-02-20 15:16:26.723987041 11.5436 48.1355 521 8 3125 -0.12 0.20 14
 
155
  def __init__(self, data = None):
 
156
    if data != None:
 
157
      fields = data.split(' ')
 
158
      Event.__init__(self, float(fields[2]), float(fields[3]), ' '.join(fields[0:2]))
 
159
      self.time = self.time + datetime.timedelta(seconds=1)
 
160
      if len(fields) >= 8:
 
161
        self.height = int(fields[4])
 
162
        self.numberOfSatellites = int(fields[5])
 
163
        self.samplePeriod = int(fields[6])
 
164
        self.amplitudeX = float(fields[7])
 
165
        self.amplitudeY = float(fields[8])
 
166
      else:
 
167
        raise Error("not enough data fields for raw event data '%s'" %(data))
 
168
 
 
169
  def __str__(self):
 
170
    return "%s%03d %.4f %.4f %d %d %d %.2f %.2f" %(self.time.strftime(Event.timeformat), self.get_nanoseconds(), self.x, self.y, self.height, self.numberOfSatellites, self.samplePeriod, self.amplitudeX, self.amplitudeY)
 
171
 
 
172
  def getXAmplitude(self):
 
173
    return self.amplitudeX
 
174
 
 
175
  def getYAmplitude(self):
 
176
    return self.amplitudeY
 
177
 
 
178
class Stroke(Event):
 
179
  '''
 
180
  classdocs
 
181
  '''
 
182
 
 
183
  def __init__(self, data = None):
 
184
    if data != None:
 
185
      ' Construct stroke from blitzortung text format data line '
 
186
      fields = data.split(' ')
 
187
      Event.__init__(self, float(fields[3]), float(fields[2]), ' '.join(fields[0:2]))
 
188
      if len(fields) >= 5:
 
189
        self.amplitude = float(fields[4][:-2])
 
190
        self.typeVal = int(fields[5])
 
191
        self.error2d = int(fields[6][:-1])
 
192
        if self.error2d < 0:
 
193
          self.error2d = 0
 
194
        self.stationcount = int(fields[7])
 
195
        self.participants = []
 
196
        if (len(fields) >=9):
 
197
          for index in range(8,len(fields)):
 
198
            self.participants.append(fields[index])
 
199
      else:
 
200
        raise Error("not enough data fields from stroke data line '%s'" %(data))
 
201
    self.height = 0.0
 
202
 
 
203
  def set_location(self, location):
 
204
    Point.__init__(self, location.x, location.y)
 
205
 
 
206
  def get_location(self):
 
207
    return self
 
208
 
 
209
  def get_height(self):
 
210
    return self.height
 
211
 
 
212
  def set_height(self, height):
 
213
    self.height = height
 
214
 
 
215
  def get_amplitude(self):
 
216
    return self.amplitude
 
217
 
 
218
  def set_amplitude(self, amplitude):
 
219
    self.amplitude = amplitude
 
220
 
 
221
  def get_type(self):
 
222
    return self.typeVal
 
223
 
 
224
  def set_type(self, typeVal):
 
225
    self.typeVal = typeVal
 
226
 
 
227
  def get_lateral_error(self):
 
228
    return self.error2d
 
229
 
 
230
  def set_lateral_error(self, error2d):
 
231
    self.error2d = error2d
 
232
 
 
233
  def get_station_count(self):
 
234
    return self.stationcount
 
235
 
 
236
  def set_station_count(self, stationcount):
 
237
    self.stationcount = stationcount
 
238
 
 
239
  def has_participant(self, participant):
 
240
    return self.participants.count(participant) > 0
 
241
 
 
242
  def is_detected_by_user(self):
 
243
    return False
 
244
 
 
245
  def __str__(self):
 
246
    return "%s%03d%s %.4f %.4f %d %.1f %d %.1f %d" %(self.time.strftime(Event.timeformat), self.get_nanoseconds(), self.time.strftime('%z'), self.x, self.y, self.height, self.amplitude, self.typeVal, self.error2d, self.stationcount)
 
247
 
 
248
class Histogram(object):
 
249
 
 
250
  def __init__(self, fileNames, time):
 
251
    data = files.StatisticsData(fileNames, time)
 
252
 
 
253
    while True:
 
254
 
 
255
      data.get()
 
256
 
 
257
      print time.getCenterTime(), data.getCount(), data.getMean(), data.getVariance()
 
258
 
 
259
      if not time.hasNext():
 
260
        break
 
261
 
 
262
      time.next()
 
263
 
 
264
class AmplitudeHistogram(object):
 
265
 
 
266
  def __init__(self, fileNames, time):
 
267
    data = files.HistogramData(fileNames, time)
 
268
 
 
269
    data.list()
 
270
 
 
271
class StrokesUrl:
 
272
 
 
273
  def __init__(self, baseurl):
 
274
    self.url = baseurl
 
275
 
 
276
  def add(self, name, value):
 
277
    self.url += '&' + str(name).strip() + '=' + str(value).strip()
 
278
 
 
279
  def readData(self):
 
280
    urlconnection = urllib.urlopen(self.url)
 
281
    data = urlconnection.read().strip()
 
282
    urlconnection.close()
 
283
    return data
 
284
 
 
285
  def get(self, timeInterval=None):
 
286
    strokes = []
 
287
    for line in self.readData().split('\n'):
 
288
      stroke = Stroke(line)
 
289
      if timeInterval==None or timeInterval.contains(stroke.get_time()):
 
290
        strokes.append(stroke)
 
291
    return strokes
 
292
 
 
293
class Strokes(StrokesUrl):
 
294
 
 
295
  def __init__(self, config):
 
296
    StrokesUrl.__init__(self, 'http://'+config.get('username')+':'+config.get('password')+'@blitzortung.tmt.de/Data/Protected/strikes.txt')
 
297
 
 
298
class ParticipantStrokes(StrokesUrl):
 
299
 
 
300
  def __init__(self, config):
 
301
    StrokesUrl.__init__(self, 'http://'+config.get('username')+':'+config.get('password')+'@blitzortung.tmt.de/Data/Protected/participants.txt')