diff --git a/shared/src/orisys_app_shared/record/experiment.py b/shared/src/orisys_app_shared/record/experiment.py index fc0769b..8b90b5c 100644 --- a/shared/src/orisys_app_shared/record/experiment.py +++ b/shared/src/orisys_app_shared/record/experiment.py @@ -77,6 +77,7 @@ FORCES_HEADER = ( "FN_output_N", "FX_output_N", "FY_output_N", + "Fmag_raw", ) FRAMES_HEADER = ( "frame_id", @@ -109,6 +110,14 @@ ROW_BACKLOG = 8192 VIDEO_PACING_TOLERANCE = 0.5 +def raw_magnitude(fn: float, fx: float, fy: float) -> float: + """Magnitude of the three raw force components. Missing any one leaves it blank.""" + values = (fn, fx, fy) + if not all(np.isfinite(value) for value in values): + return float("nan") + return float(np.sqrt(sum(value * value for value in values))) + + def format_value(value: float) -> str: """Full-precision CSV cell. ``NaN`` means "not available" and is left empty. @@ -1142,6 +1151,7 @@ class _SessionWriter: format_value(sample.fn_n_processed), format_value(sample.fx_n_processed), format_value(sample.fy_n_processed), + format_value(raw_magnitude(sample.fn_raw, sample.fx_raw, sample.fy_raw)), ) ) diff --git a/shared/tests/test_experiment_recorder.py b/shared/tests/test_experiment_recorder.py index 7bf1b42..5324c91 100644 --- a/shared/tests/test_experiment_recorder.py +++ b/shared/tests/test_experiment_recorder.py @@ -118,11 +118,15 @@ def test_unavailable_values_are_empty_not_zero(root): failed = rows[1] assert failed["valid"] == "0" - for column in ("FN_raw", "FX_raw", "FY_raw", "FN_N", "FX_N", "FY_N"): + for column in ("FN_raw", "FX_raw", "FY_raw", "FN_N", "FX_N", "FY_N", "Fmag_raw"): assert failed[column] == "", "a failed readout was written as a number" + recorded = rows[0] + assert recorded["Fmag_raw"] == repr((9.0 ** 2 + 0.4 ** 2 + 0.4 ** 2) ** 0.5) + no_raw = rows[2] assert no_raw["FN_raw"] == "" and no_raw["FX_raw"] == "", "raw was not left empty" + assert no_raw["Fmag_raw"] == "" assert no_raw["FN_N"] == "2.0", "calibrated values must still be recorded" assert no_raw["valid"] == "1"