1#ifndef SENSOR_CALIBRATION_HPP
2#define SENSOR_CALIBRATION_HPP
48 for (
size_t i = 1; i <
coeffs.size(); ++i) {
56 return evaluate(
static_cast<double>(adc_code));
75 const std::string& default_unit =
"",
int default_order = 3)
89 bool load_calibration(
const std::string& json_dir,
const std::string& csv_path);
103 double calculate(uint8_t channel_id, int32_t raw_counts)
const;
143 double A = 3.9083e-3;
144 double B = -5.775e-7;
145 double C = -4.183e-12;
150 double r = 1.0 + cvd.A * t_c + cvd.B * t_c * t_c;
152 r += cvd.C * (t_c - 100.0) * t_c * t_c * t_c;
163 if (!(resistance_ohms > 0.0) || !(cvd.R0 > 0.0))
164 return std::numeric_limits<double>::quiet_NaN();
165 const double ratio = resistance_ohms / cvd.R0;
166 const double disc = cvd.A * cvd.A - 4.0 * cvd.B * (1.0 - ratio);
168 return std::numeric_limits<double>::quiet_NaN();
169 constexpr double kMinC = -205.0, kMaxC = 855.0;
170 double t = (-cvd.A + std::sqrt(disc)) / (2.0 * cvd.B);
171 if (resistance_ohms >= cvd.R0)
172 return t <= kMaxC ? t : std::numeric_limits<double>::quiet_NaN();
173 for (
int i = 0; i < 20; ++i) {
176 cvd.R0 * (cvd.A + 2.0 * cvd.B * t + cvd.C * (4.0 * t * t * t - 300.0 * t * t));
177 const double step = f / df;
179 if (std::fabs(step) < 1e-9)
182 return t >= kMinC ? t : std::numeric_limits<double>::quiet_NaN();
194 constexpr double kAdcMax = 2147483648.0;
195 if (!(excitation_ua > 0.0) || std::fabs(
static_cast<double>(adc_raw)) >= 0.999 * kAdcMax)
196 return std::numeric_limits<double>::quiet_NaN();
197 const double voltage_v = (
static_cast<double>(adc_raw) / kAdcMax) * adc_ref_voltage;
198 const double resistance_ohms = (std::abs(voltage_v) * 1e6) / excitation_ua;
207 double ratio = resistance_ohms / cvd.R0;
208 double disc = cvd.A * cvd.A - 4.0 * cvd.B * (1.0 - ratio);
211 return (-cvd.A + std::sqrt(disc)) / (2.0 * cvd.B);
216 return static_cast<double>(counts) * gain + offset;
242 return {-1.318058e+2, 4.830222e+1, -1.646031e+0, 5.464731e-2, -9.650715e-4,
243 8.802193e-6, -3.110810e-8, 0.0, 0.0};
double calculate(uint8_t channel_id, int32_t raw_counts) const
const PolynomialCalibration * get(uint8_t channel_id) const
bool load_calibration(const std::string &json_dir, const std::string &csv_path)
Auto-discover & load from default directories.
void set_calibration(uint8_t channel_id, const PolynomialCalibration &cal)
Manually set coefficients for a channel.
~SensorCalibrationManager()=default
const std::string & sensor_type() const
bool load_from_csv(const std::string &csv_path)
Load calibration from a CSV file (DiabloAvionics format).
size_t calibrated_count() const
std::string find_latest_json(const std::string &dir) const
bool is_calibrated(uint8_t channel_id) const
SensorCalibrationManager(const std::string &sensor_type, const std::string &default_unit="", int default_order=3)
bool load_from_json(const std::string &json_path)
Load calibration from a JSON calibration file.
std::string default_unit_
void clear_calibration(uint8_t channel_id)
Remove a channel's calibration so is_calibrated() returns false again.
std::map< uint8_t, PolynomialCalibration > calibrations_
double counts_to_resistance(int32_t counts, double gain, double offset)
Convert ADC counts to resistance (assuming linear relationship).
double resistance_to_temp_cvd(double resistance_ohms, const CVDCoeffs &cvd=CVDCoeffs{})
Convert resistance (Ω) to temperature (°C) using iterative CVD inverse.
double temp_to_resistance_cvd(double t_c, const CVDCoeffs &cvd=CVDCoeffs{})
Resistance (Ω) at temperature (°C), IEC 60751 Callendar-Van Dusen, the C term below 0 °C.
double rtd_board_adc_to_temp_c(int32_t adc_raw, double adc_ref_voltage, double excitation_ua, double r0_ohms)
An ESP32 RTD board's reading -> °C: the ADC code (2^31 = adc_ref_voltage) is the voltage across the e...
double resistance_to_temp_cvd_full(double resistance_ohms, const CVDCoeffs &cvd=CVDCoeffs{})
The full CVD inverse: exact above 0 °C (the quadratic), Newton on the C term below it.
std::vector< double > nist_type_k_mv_to_c()
NIST ITS-90 Type K coefficients (0–1372 °C range, voltage in mV → temp in °C) Simplified 9th-order fr...
Output smoothing for calibrated PT pressure, per sensor uid (ESP32 and LabJack T7 alike).
Motorized ball valve position: raw ADC counts -> % open.
double evaluate(double x) const
Evaluate the polynomial at x (Horner's method — numerically stable).
double evaluate(int32_t adc_code) const
Convenience for int32 ADC codes.
PolynomialCalibration(double A, double B, double C, double D, const std::string &u="PSI")
std::vector< double > coeffs
PolynomialCalibration()=default
PolynomialCalibration(std::vector< double > c, const std::string &u="")
Cold junction compensation.