STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
fsw::calibration Namespace Reference

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 > &timeseries, 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

Detailed Description

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).

Enumeration Type Documentation

◆ CalTarget

enum class fsw::calibration::CalTarget
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.

◆ SensorKind

enum class fsw::calibration::SensorKind
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.

Function Documentation

◆ cal_target()

CalTarget fsw::calibration::cal_target ( const CubicChannel & ch)
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().

◆ compute_allan_variance()

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.

◆ fit_noise_coefficients()

◆ hp_pt_shunt_code()

uint32_t fsw::calibration::hp_pt_shunt_code ( uint32_t wire)
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().

◆ lc_tare_entity()

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().

◆ measurement_uncertainty()

double fsw::calibration::measurement_uncertainty ( double tau,
const NoiseCoefficients & coeffs,
double voltage = 0.0,
double sigma_base = 1e-3 )
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().

◆ pt_logical_calibration_channel()

uint8_t fsw::calibration::pt_logical_calibration_channel ( uint8_t board_slot_number,
uint8_t local_connector )
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().

◆ skip_json_for_pt_polynomial_load()

bool fsw::calibration::skip_json_for_pt_polynomial_load ( const std::string & filename)
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().

◆ type_k_c_from_mv()

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().

◆ 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().

Variable Documentation

◆ kCaptureWindowMs

uint64_t fsw::calibration::kCaptureWindowMs = 1000
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().

◆ kMaxCaptureWindowMs

uint64_t fsw::calibration::kMaxCaptureWindowMs = 5000
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().

◆ kMaxSampleAgeMs

uint64_t fsw::calibration::kMaxSampleAgeMs = 1500
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().

◆ kMinCaptureSamples

size_t fsw::calibration::kMinCaptureSamples = 3
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().

◆ kRawUnitAdc

const char* fsw::calibration::kRawUnitAdc = "adc"
inlineconstexpr

◆ kRawUnitMicrovolts

const char* fsw::calibration::kRawUnitMicrovolts = "uV"
inlineconstexpr

◆ kReasonNoSamples

const char* fsw::calibration::kReasonNoSamples = "no_samples"
inlineconstexpr

Definition at line 100 of file CaptureWindow.hpp.

Referenced by fsw::calibration::CaptureWindow::capture().

◆ kReasonOk

const char* fsw::calibration::kReasonOk = ""
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().

◆ kReasonStale

const char* fsw::calibration::kReasonStale = "stale"
inlineconstexpr

Definition at line 101 of file CaptureWindow.hpp.

Referenced by fsw::calibration::CaptureWindow::capture().

◆ kReasonTooFew

const char* fsw::calibration::kReasonTooFew = "too_few"
inlineconstexpr

Definition at line 102 of file CaptureWindow.hpp.

Referenced by fsw::calibration::CaptureWindow::capture().

◆ kRingMax

size_t fsw::calibration::kRingMax = 1024
constexpr

◆ kRingSpanMs

uint64_t fsw::calibration::kRingSpanMs = 8000
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().

◆ kSettleZ

double fsw::calibration::kSettleZ = 6.0
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().

◆ kStaleSamplePeriods

uint64_t fsw::calibration::kStaleSamplePeriods = 2
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().

◆ kTypeKMaxMv

double fsw::calibration::kTypeKMaxMv = 69.553
constexpr

Definition at line 15 of file TypeK.hpp.

Referenced by type_k_mv_from_c().

◆ kTypeKMinMv

double fsw::calibration::kTypeKMinMv = -6.404
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().