Skip to content

Commit bad1cf2

Browse files
Depth error handling (#27)
* Working towards a better depth interpretation / handling * Improving calibration when sensor throws a 0 at start.
1 parent 6614d88 commit bad1cf2

2 files changed

Lines changed: 62 additions & 23 deletions

File tree

study_lyte/adjustments.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,15 @@ def remove_ambient(active, ambient, min_ambient_range=100, direction='forward'):
175175
return clean
176176

177177

178-
def apply_calibration(series, coefficients, minimum=None, maximum=None):
178+
def apply_calibration(series, coefficients, minimum=None, maximum=None, tare=False):
179179
"""
180180
Apply any calibration using poly1d
181181
"""
182182
poly = np.poly1d(coefficients)
183183
result = poly(series)
184+
if tare:
185+
result = result - np.nanmedian(result[0:50])
186+
184187
if maximum is not None:
185188
result[result > maximum] = maximum
186189
if minimum is not None:

study_lyte/profile.py

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@ def __init__(self, filename, surface_detection_offset=4.5, calibration=None,
8181
self._error = None
8282
self._ground = None
8383

84-
def assign_event_depths(self):
84+
def assign_event_depths(self, depth:pd.Series):
8585
"""" Enable depth assignment post depth realization """
8686
self.events
87-
for event in [self._start, self._stop, self._surface.nir, self._surface.force]:
88-
event.depth = self.depth.iloc[event.index]
87+
for event in [self._start, self._stop]:
88+
event.depth = depth.iloc[event.index]
89+
self._surface = self.assign_surface_depths(depth)
8990

9091
@property
9192
def serial_number(self):
@@ -182,8 +183,7 @@ def force(self):
182183
force = self.raw['Sensor1'].values
183184
if self.calibration is not None:
184185
if 'Sensor1' in self.calibration.keys():
185-
force = apply_calibration(self.raw['Sensor1'].values, self.calibration['Sensor1'], minimum=0, maximum=15000)
186-
force = force - np.nanmean(force[0:20])
186+
force = apply_calibration(self.raw['Sensor1'].values, self.calibration['Sensor1'], minimum=None, maximum=15000, tare=True)
187187

188188
self._force = pd.DataFrame({'force': force, 'depth': self.depth.values})
189189
self._force = self._force.iloc[self.surface.force.index:self.end].reset_index()
@@ -424,14 +424,26 @@ def depth(self):
424424
self.barometer.depth.values.copy(),
425425
error=self.error.index)
426426

427-
if depth.min() < -230 and self.accelerometer.depth.min() > -230:
428-
LOG.warning('Fused depth result produced a profile > 230 cm. Defaulting to accelerometer')
429-
self._depth = self.accelerometer.depth
430-
431-
elif depth.min() < -230 and self.barometer.depth.min() > -230:
432-
LOG.warning('Fused and accelerometer depth resulted in a profile > 230 cm. Defaulting to barometer')
433-
self._depth = self.barometer.depth
434-
427+
# Failed fusion
428+
unrealistic_depth = 230
429+
travel = abs(depth.max() - depth.min())
430+
431+
# Unrealistic depth
432+
if travel > unrealistic_depth:
433+
warn_msg = f'Fused depth result produced a profile > {unrealistic_depth} cm.'
434+
435+
# Check if acceleration alone is reasonable
436+
if self.accelerometer.distance_traveled < unrealistic_depth:
437+
LOG.warning(warn_msg + ' Defaulting to accelerometer')
438+
self._depth = self.accelerometer.depth
439+
440+
# Check if barometer alone is reasonable
441+
elif self.barometer.distance_traveled < unrealistic_depth:
442+
LOG.warning(warn_msg + ' Defaulting to barometer')
443+
self._depth = self.barometer.depth
444+
else:
445+
LOG.error(warn_msg + ' Alternate sensors also unrealistic, using data as is.')
446+
self._depth = pd.Series(data=depth, index=self.raw['time'])
435447
else:
436448
self._depth = pd.Series(data=depth, index=self.raw['time'])
437449

@@ -444,7 +456,7 @@ def depth(self):
444456
self._depth = self.barometer.depth
445457

446458
# Assign positions of each event detected
447-
self.assign_event_depths()
459+
self.assign_event_depths(self._depth)
448460

449461
return self._depth
450462

@@ -481,6 +493,38 @@ def stop(self):
481493

482494
return self._stop
483495

496+
def assign_surface_depths(self, depth:pd.Series):
497+
# Event according the NIR sensors
498+
idx = self.surface.nir.index
499+
self._surface.nir.depth = depth.iloc[idx]
500+
501+
# Event according to the force sensor
502+
force_surface_depth = self._surface.nir.depth + self.surface_detection_offset
503+
f_idx = abs(depth - force_surface_depth).argmin()
504+
# Retrieve force estimated start
505+
f_start = get_sensor_start(self.raw['Sensor1'], max_threshold=0.02, threshold=-0.02)
506+
f_start = f_start or f_idx
507+
508+
# If the force start is before the NIR start then adjust
509+
if f_start < self.start.index:
510+
LOG.info(f'Choosing motion start ({self.start.index}) over force start ({f_start})...')
511+
f_idx = self.start.index
512+
force_surface_depth = depth.iloc[f_idx]
513+
514+
elif f_start < f_idx:
515+
LOG.info(f'Choosing force start ({f_start}) over nir derived ({f_idx})...')
516+
f_idx = f_start
517+
force_surface_depth = depth.iloc[f_idx]
518+
519+
self._surface.force.index = f_idx
520+
self._surface.force.depth = depth.iloc[f_idx]
521+
self._surface.force.time = self.raw['time'].iloc[f_idx]
522+
523+
# Adjust surface detection to modify the start if there is conflict.
524+
if self._surface.nir.time < self.start.time:
525+
self._start = self._surface.nir
526+
self._start.name = 'start'
527+
484528
@property
485529
def surface(self):
486530
"""
@@ -517,11 +561,6 @@ def surface(self):
517561
force = Event(name='surface', index=f_idx, depth=force_surface_depth, time=self.raw['time'].iloc[f_idx])
518562
self._surface = SimpleNamespace(name='surface', nir=nir, force=force)
519563

520-
# Allow surface detection to modify the start if there is conflict.
521-
if nir.time < self.start.time:
522-
self._start = nir
523-
self._start.name = 'start'
524-
525564
return self._surface
526565

527566
@property
@@ -651,10 +690,7 @@ def fuse_depths(cls, acc_depth, baro_depth, error=None):
651690
# Scale total
652691
sensor_diff = abs(acc_bottom) - abs(baro_bottom)
653692
delta = 0.572 * abs(acc_bottom) + 0.308 * abs(baro_bottom) + 0.264 * sensor_diff + 8.916
654-
# delta = (acc_bottom * (5 - scale) + baro_bottom * scale) / 5
655693
avg = (avg / avg_bottom) * -1 * delta
656-
# from study_lyte.plotting import plot_ts
657-
# ax = plot_ts(avg, show=True)
658694

659695
return avg
660696

0 commit comments

Comments
 (0)