|
STAR
Cal STAR — firmware, DAQ server, and engine design
|
Output smoothing for calibrated PT pressure, per sensor uid (ESP32 and LabJack T7 alike). More...
Namespaces | |
| namespace | rtd |
| namespace | tc |
| namespace | valve_position |
| namespace | anonymous_namespace{CaptureWindow.cpp} |
| namespace | anonymous_namespace{CubicCalibrationStore.cpp} |
| namespace | anonymous_namespace{LcTareStore.cpp} |
| namespace | anonymous_namespace{RobustCalibrationFramework.cpp} |
| namespace | anonymous_namespace{RobustCalibrationManager.cpp} |
Classes | |
| struct | NoiseCoefficients |
| Noise coefficients from Allan variance fit (scripts/calibration/allan_variance.py). More... | |
| struct | AdcSample |
| struct | CaptureResult |
| class | CaptureWindow |
| Per-sensor ring of recent samples, and the capture decision over it. More... | |
| class | CommandDedupe |
| Drops a CalibrationCommand the service has already handled. More... | |
| struct | CubicPoint |
| One operator-captured calibration point: raw ADC code paired with a known reference PSI. More... | |
| struct | CubicFit |
| Result of a least-squares polynomial fit over a channel's captured points. More... | |
| struct | CaptureQuality |
| How trustworthy the most recent capture on this channel was. More... | |
| struct | CubicChannel |
| Per-sensor calibration record: identity, captured points, and the current fit. More... | |
| class | CubicCalibrationStore |
| Owns the per-channel captured points and the fitted cubic for the calibration service. More... | |
| class | IMUCalibration |
| IMU Sensor Calibration System. More... | |
| class | IMUCalibrationSystem |
| Complete IMU Calibration System. More... | |
| struct | LcTare |
| One load cell's tare: the scale reads zero at the load it was holding when the operator pressed Tare. More... | |
| class | LcTareStore |
| Owns the per-channel tares for the calibration service. More... | |
| struct | PTCalibrationCoeffs |
| PT Calibration Coefficients. More... | |
| class | PTCalibrationManager |
| PT Calibration Manager. More... | |
| class | PtSmoother |
| struct | EnvironmentalState |
| Environmental state [T, H, V, A, M] — scripts/calibration/robust_calibration.py. More... | |
| struct | CalibrationPoint |
| class | RobustCalibrationFramework |
| Port of scripts/calibration/robust_calibration.py RobustCalibrationFramework: 9-parameter environmental basis, TLS, Bayesian update, RLS, GLR drift, Gauss–Markov bias, optional Allan σ_meas (AllanVariance.hpp). More... | |
| struct | SensorState |
| class | RobustCalibrationManager |
| Runtime PT calibration via RobustCalibrationFramework (9-D basis, TLS / Bayesian / RLS / GLR / bias), seeded from factory cubic. More... | |
| struct | PolynomialCalibration |
| class | SensorCalibrationManager |
Enumerations | |
| enum class | SensorKind { PT , LC } |
| Which family of sensor a channel belongs to. More... | |
| enum class | CalTarget { None , PT , LC } |
| Which live calibration manager a store entry's fit belongs in — the one rule every caller that applies a resumed curve to the running stream must go through. More... | |
Functions | |
| double | measurement_uncertainty (double tau, const NoiseCoefficients &coeffs, double voltage=0.0, double sigma_base=1e-3) |
| Measurement σ from paper Section 7 (Python measurement_uncertainty). | |
| void | compute_allan_variance (const std::vector< double > ×eries, double tau0, std::vector< double > &tau_out, std::vector< double > &sigma2_out) |
| NoiseCoefficients | fit_noise_coefficients (const std::vector< double > &tau_arr, const std::vector< double > &sigma2_arr) |
| CalTarget | cal_target (const CubicChannel &ch) |
| uint32_t | hp_pt_shunt_code (uint32_t wire) |
| A 4-20 mA PT's wire code -> the shunt code the conversions and calibrations work in. | |
| std::string | lc_tare_entity (uint8_t board_id, uint8_t connector) |
| The publish-path entity name for an LC channel: "LC<slot>_Cal.CH<connector>", where slot is board_id % 10 with 0 -> 10 — the same rule DatabaseConfig uses to name the calibrated LC VTables, and the same board_number the LC publish path already holds. | |
| uint8_t | pt_logical_calibration_channel (uint8_t board_slot_number, uint8_t local_connector) |
| PT board slot (1–10, from board_id % 10 with 0→10) + local connector (1–10) → factory/JSON logical channel index (slot 1 → 1..10, slot 2 → 11..20, …). | |
| double | type_k_c_from_mv (double mv) |
| Temperature (C) for a type K EMF in mV, referenced to 0 C. | |
| double | type_k_mv_from_c (double c) |
| EMF (mV, referenced to 0 C) a type K produces at c. | |
| static bool | skip_json_for_pt_polynomial_load (const std::string &filename) |
| Match calibration_orchestrator._load_prior_from_polynomial_calibration: skip non-factory JSON. | |
Variables | |
| constexpr uint64_t | kCaptureWindowMs = 1000 |
| How far back a capture averages. | |
| constexpr uint64_t | kMaxSampleAgeMs = 1500 |
| Newest sample older than this (in OUR clock) means the sensor is not live. | |
| constexpr size_t | kMinCaptureSamples = 3 |
| Below this a "mean" is not one, and the settle check has nothing to say. | |
| constexpr uint64_t | kStaleSamplePeriods = 2 |
| Liveness allowance for a slow sensor, in its own sample periods: one late sample is jitter, two missing in a row is a sensor that stopped. | |
| constexpr uint64_t | kMaxCaptureWindowMs = 5000 |
| Upper bound on the adaptive window and staleness allowance. | |
| constexpr uint64_t | kRingSpanMs = 8000 |
| Ring eviction: by span so it self-sizes across 1-250 Hz, by count so memory is bounded if a board ever runs fast. | |
| constexpr size_t | kRingMax = 1024 |
| constexpr double | kSettleZ = 6.0 |
| Half-mean difference, in standard errors, above which the window is not settled. | |
| constexpr const char * | kReasonOk = "" |
| Why a capture was refused. | |
| constexpr const char * | kReasonNoSamples = "no_samples" |
| constexpr const char * | kReasonStale = "stale" |
| constexpr const char * | kReasonTooFew = "too_few" |
| constexpr const char * | kRawUnitAdc = "adc" |
| CubicChannel::raw_unit values. | |
| constexpr const char * | kRawUnitMicrovolts = "uV" |
| constexpr double | kTypeKMinMv = -6.404 |
| Lowest and highest EMF the inverse covers (mV): -250 C to 1372 C. | |
| constexpr double | kTypeKMaxMv = 69.553 |
Output smoothing for calibrated PT pressure, per sensor uid (ESP32 and LabJack T7 alike).
An exponential moving average seeded with the sensor's FIRST reading. It used to live in a plain std::unordered_map<uint16_t, double> read through operator[], which default-inserts 0.0: the "not yet set" test (isfinite) then passed on the very first sample, and every PT ramped up from 0 psi over its first handful of readings (a 300 psi tank archived a 68 psi minimum).
|
strong |
Which live calibration manager a store entry's fit belongs in — the one rule every caller that applies a resumed curve to the running stream must go through.
None for an orphan (see CubicChannel::live): it has no sensor streaming, and its logical channel is shared with whatever live board happens to own that slot. On 2026-11-09 LC board 41 was disabled in config; its three saved entries (connectors 1, 6, 7) resumed as orphans, and because the service's LC/PT discriminant was built from ENABLED boards they were taken for PTs. Each held one point, so each fit was invalid, so the service CLEARED PT logical channels 1, 6 and 7 — FT-PT-R, FF-PT and DR-PT-G — right after the PT entries had set them. All three streamed 0 psi, with raw ADC healthy and a good cubic sitting on disk.
| Enumerator | |
|---|---|
| None | |
| PT | |
| LC | |
Definition at line 143 of file CubicCalibrationStore.hpp.
|
strong |
Which family of sensor a channel belongs to.
logical_ch is (slot - 1) * 10 + connector with slot = board_id % 10, and check_board_slots only prevents two boards of the SAME kind sharing a slot. So PT board 22 and LC board 42 are both slot 2, and PT uid 2201 and LC uid 4201 both land on logical channel 11. The logical-channel maps below are written from a uid-ordered map, so the higher uid silently won: on 2026-09-13 a load cell's curve overwrote a 5000 psi transducer's on disk. The kind namespaces those maps so the two cannot collide.
| Enumerator | |
|---|---|
| PT | |
| LC | |
Definition at line 49 of file CubicCalibrationStore.hpp.
|
inline |
Definition at line 145 of file CubicCalibrationStore.hpp.
References ch(), LC, None, and PT.
Referenced by disabled_board_orphan_is_not_applied(), and main().
| void fsw::calibration::compute_allan_variance | ( | const std::vector< double > & | timeseries, |
| double | tau0, | ||
| std::vector< double > & | tau_out, | ||
| std::vector< double > & | sigma2_out ) |
Definition at line 11 of file AllanVariance.cpp.
| NoiseCoefficients fsw::calibration::fit_noise_coefficients | ( | const std::vector< double > & | tau_arr, |
| const std::vector< double > & | sigma2_arr ) |
Definition at line 67 of file AllanVariance.cpp.
References fsw::calibration::NoiseCoefficients::B, fsw::calibration::NoiseCoefficients::K, fsw::calibration::NoiseCoefficients::Q, fsw::calibration::NoiseCoefficients::R, fsw::calibration::NoiseCoefficients::sigma_min, and fsw::calibration::NoiseCoefficients::tau_min.
|
inline |
A 4-20 mA PT's wire code -> the shunt code the conversions and calibrations work in.
The code is full scale at 2^31 against the 2.5 V internal reference, and the loop at 20 mA across 120 Ohm is 2.4 V, so every reading a live loop can produce sits in [0, 2^31). A code at or above 2^31 is the ADC's two's-complement NEGATIVE: the shunt below 0 V, which is what an open or unpowered loop's noise does around zero.
It used to be clamped to 2^31-1 instead – full scale, 20 mA, 5000 psi. On 2026-11-07 COPV-PT-R and HPD-PT (PT board 2, connectors 1 and 3, both reading ~0 mA) produced codes like 0xFFFF0FB5 (-61515) a few times a minute; each became a 5000 psi sample, the output EMA turned it into a 1250 psi pulse decaying over ~1 s, and the controller and the plots both received it.
A negative code reads as no current: 0, which the conversion reports as 0 psi.
Definition at line 23 of file HpPtCode.hpp.
Referenced by main().
| std::string fsw::calibration::lc_tare_entity | ( | uint8_t | board_id, |
| uint8_t | connector ) |
The publish-path entity name for an LC channel: "LC<slot>_Cal.CH<connector>", where slot is board_id % 10 with 0 -> 10 — the same rule DatabaseConfig uses to name the calibrated LC VTables, and the same board_number the LC publish path already holds.
It exists as one shared function because the failure mode of a second copy is specific and has already happened: slot is NOT board_id, so PT board 22 and LC board 42 are both slot 2, and deriving a uid back out of an entity string collides them. Node must key on this string rather than re-derive it.
Definition at line 29 of file LcTareStore.cpp.
References board_id.
Referenced by main().
|
inline |
Measurement σ from paper Section 7 (Python measurement_uncertainty).
Definition at line 24 of file AllanVariance.hpp.
Referenced by fsw::calibration::RobustCalibrationFramework::compute_measurement_variance().
|
inline |
PT board slot (1–10, from board_id % 10 with 0→10) + local connector (1–10) → factory/JSON logical channel index (slot 1 → 1..10, slot 2 → 11..20, …).
Same rule as calibration_service.
Definition at line 51 of file PTCalibration.hpp.
Referenced by fsw::calibration::CubicCalibrationStore::load(), main(), and fsw::routing::SensorRouter::route_pt_samples_calibrated().
|
static |
Match calibration_orchestrator._load_prior_from_polynomial_calibration: skip non-factory JSON.
Definition at line 365 of file PTCalibration.cpp.
Referenced by fsw::calibration::PTCalibrationManager::find_latest_json_file().
| double fsw::calibration::type_k_c_from_mv | ( | double | mv | ) |
Temperature (C) for a type K EMF in mV, referenced to 0 C.
NaN outside the curve.
Definition at line 9 of file TypeK.cpp.
References r.
Referenced by convert_tc_adc_to_temp_c(), main(), fsw::t7::tc_c(), and type_k_mv_from_c().
| double fsw::calibration::type_k_mv_from_c | ( | double | c | ) |
EMF (mV, referenced to 0 C) a type K produces at c.
NaN outside the curve.
Definition at line 38 of file TypeK.cpp.
References kTypeKMaxMv, kTypeKMinMv, and type_k_c_from_mv().
Referenced by anonymous_namespace{t7_bridge_main.cpp}::fake_signal(), main(), and fsw::t7::tc_c().
|
constexpr |
How far back a capture averages.
~14 samples on a 13.7 Hz load cell (standard error ~214 counts against a 53,000-count weight step) and ~61 on a PT — while staying short enough that a load change two seconds before the button cannot leak in.
This is the FLOOR. A sensor slower than kMinCaptureSamples per second gets a window of kMinCaptureSamples of its own sample periods instead (see capture()): the LC boards at SINC4 / 20 SPS deliver ~1 Hz per channel, and a fixed 1 s window never held three of their samples, so every LC capture and Zero-All was refused as too_few or stale.
Definition at line 71 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture(), anonymous_namespace{test_capture_window.cpp}::fast_sensor_bounds_unchanged(), anonymous_namespace{test_capture_window.cpp}::low_rate_step_after_settle(), and anonymous_namespace{test_capture_window.cpp}::window_bound_high_rate().
|
constexpr |
Upper bound on the adaptive window and staleness allowance.
A sensor slower than this allows is not one a capture can honestly describe "right now"; it fails closed.
Definition at line 82 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture(), and anonymous_namespace{test_capture_window.cpp}::ring_bounds().
|
constexpr |
Newest sample older than this (in OUR clock) means the sensor is not live.
A floor, like the window: a slow sensor is allowed kStaleSamplePeriods of its own sample periods.
Definition at line 74 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture(), and anonymous_namespace{test_capture_window.cpp}::fast_sensor_bounds_unchanged().
|
constexpr |
Below this a "mean" is not one, and the settle check has nothing to say.
Definition at line 76 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture(), and anonymous_namespace{test_capture_window.cpp}::slow_load_cell_captures().
|
inlineconstexpr |
CubicChannel::raw_unit values.
Definition at line 52 of file CubicCalibrationStore.hpp.
Referenced by fsw::calibration::CubicCalibrationStore::load().
|
inlineconstexpr |
Definition at line 53 of file CubicCalibrationStore.hpp.
Referenced by fsw::calibration::CubicCalibrationStore::load(), and main().
|
inlineconstexpr |
Definition at line 100 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture().
|
inlineconstexpr |
Why a capture was refused.
Stable strings — they go in the log and in the store.
Definition at line 99 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture().
|
inlineconstexpr |
Definition at line 101 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture().
|
inlineconstexpr |
Definition at line 102 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture().
|
constexpr |
Definition at line 88 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::push(), and anonymous_namespace{test_capture_window.cpp}::ring_bounds().
|
constexpr |
Ring eviction: by span so it self-sizes across 1-250 Hz, by count so memory is bounded if a board ever runs fast.
Both are enforced on push. Must exceed kMaxCaptureWindowMs by at least one slow sample period, or a slow sensor's window could never fill.
Definition at line 87 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::push(), and anonymous_namespace{test_capture_window.cpp}::ring_bounds().
|
constexpr |
Half-mean difference, in standard errors, above which the window is not settled.
Definition at line 90 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture(), and anonymous_namespace{test_capture_window.cpp}::settle_detection().
|
constexpr |
Liveness allowance for a slow sensor, in its own sample periods: one late sample is jitter, two missing in a row is a sensor that stopped.
Definition at line 79 of file CaptureWindow.hpp.
Referenced by fsw::calibration::CaptureWindow::capture().
|
constexpr |
Definition at line 15 of file TypeK.hpp.
Referenced by type_k_mv_from_c().
|
constexpr |
Lowest and highest EMF the inverse covers (mV): -250 C to 1372 C.
Definition at line 14 of file TypeK.hpp.
Referenced by type_k_mv_from_c().