Newer
Older
import collections
from typing import Dict, List, Optional

Jeremy M Fee
committed

Jeremy M Fee
committed
from obspy.core import UTCDateTime
from pydantic import BaseModel
from .. import pydantic_utcdatetime
from .MeasurementType import MeasurementType
class Measurement(BaseModel):
"""One angle and time measurement with optional residual.
Attributes
----------
measurement_type: type of measurement.
angle: measured angle, decimal degrees.
residual: residual at time of measurement.
time: when measurement was taken.
"""
measurement_type: MeasurementType
angle: float = 0

Jeremy M Fee
committed
time: Optional[UTCDateTime] = None
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
h: Optional[float] = None
e: Optional[float] = None
z: Optional[float] = None
f: Optional[float] = None
class AverageMeasurement(Measurement):
endtime: Optional[UTCDateTime] = None
def average_measurement(measurements: List[Measurement]) -> AverageMeasurement:
"""Calculate average from multiple measurements.
returns None if measurements is empty or None
otherwise returns Measurement
- using type from first measurement,
- with empty time,
- averaging all other values
"""
if len(measurements) == 0:
# no measurements to average
return None
starttime = safe_min([m.time.timestamp for m in measurements if m.time])
endtime = safe_max([m.time.timestamp for m in measurements if m.time])
measurement = AverageMeasurement(
measurement_type=measurements[0].measurement_type,
angle=safe_average([m.angle for m in measurements]),
residual=safe_average([m.residual for m in measurements]),
time=starttime and UTCDateTime(starttime) or None,
endtime=endtime and UTCDateTime(endtime) or None,
h=safe_average([m.h for m in measurements]),
e=safe_average([m.e for m in measurements]),
z=safe_average([m.z for m in measurements]),
f=safe_average([m.f for m in measurements]),
)
return measurement
def measurement_index(
measurements: List[Measurement],
) -> Dict[MeasurementType, List[Measurement]]:
"""Generate index of measurements keyed by MeasurementType.
Any missing MeasurementType returns an empty list.
There may be multiple measurements of each MeasurementType.
"""
index = collections.defaultdict(list)
for m in measurements:
index[m.measurement_type].append(m)
return index
def safe_average(l: List[Optional[float]]):
values = l and [f for f in l if f] or None
return values and numpy.nanmean(values) or None
def safe_max(l: List[Optional[float]]):
values = l and [f for f in l if f] or None
return l and numpy.nanmax(values) or None
def safe_min(l: List[Optional[float]]):
values = l and [f for f in l if f] or None
return l and numpy.nanmin(values) or None