Use degree celsius as temperature base unit

- Breaking: Erase settings before flashing
- except beta in Steinhart-Hart equation
- to keep the temperature value set consistent with the value returned
- f32 floating point calculation is inaccurate
This commit is contained in:
linuswck 2024-08-07 17:22:30 +08:00
parent af73ac8127
commit 3ba8b99084
5 changed files with 56 additions and 63 deletions

View File

@ -8,8 +8,7 @@ use uom::si::{electric_current::{ampere, ElectricCurrent},
electric_potential::{volt, ElectricPotential}, electric_potential::{volt, ElectricPotential},
electrical_conductance::{siemens, ElectricalConductance}, electrical_conductance::{siemens, ElectricalConductance},
electrical_resistance::{ohm, ElectricalResistance}, electrical_resistance::{ohm, ElectricalResistance},
power::{watt, Power}, power::{watt, Power}};
thermodynamic_temperature::{degree_celsius, ThermodynamicTemperature}};
use crate::{device::{dfu, sys_timer}, use crate::{device::{dfu, sys_timer},
laser_diode::{laser_diode::{LdDrive, LdSettingsSummary, StatusReport as LdStatusReport}, laser_diode::{laser_diode::{LdDrive, LdSettingsSummary, StatusReport as LdStatusReport},
@ -558,7 +557,7 @@ pub fn execute_cmd(
Some(ThermostatCmdEnum::SetTemperatureSetpoint) => match cmd.json.data_f32 { Some(ThermostatCmdEnum::SetTemperatureSetpoint) => match cmd.json.data_f32 {
Some(val) => { Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket); send_response(buffer, ResponseEnum::Acknowledge, None, socket);
thermostat.set_temperature_setpoint(ThermodynamicTemperature::new::<degree_celsius>(val)); thermostat.set_temperature_setpoint(val);
} }
None => { None => {
send_response( send_response(
@ -722,7 +721,7 @@ pub fn execute_cmd(
Some(ThermostatCmdEnum::SetTempMonUpperLimit) => match cmd.json.data_f32 { Some(ThermostatCmdEnum::SetTempMonUpperLimit) => match cmd.json.data_f32 {
Some(val) => { Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket); send_response(buffer, ResponseEnum::Acknowledge, None, socket);
thermostat.set_temp_mon_upper_limit(ThermodynamicTemperature::new::<degree_celsius>(val)); thermostat.set_temp_mon_upper_limit(val);
} }
None => { None => {
send_response( send_response(
@ -736,7 +735,7 @@ pub fn execute_cmd(
Some(ThermostatCmdEnum::SetTempMonLowerLimit) => match cmd.json.data_f32 { Some(ThermostatCmdEnum::SetTempMonLowerLimit) => match cmd.json.data_f32 {
Some(val) => { Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket); send_response(buffer, ResponseEnum::Acknowledge, None, socket);
thermostat.set_temp_mon_lower_limit(ThermodynamicTemperature::new::<degree_celsius>(val)); thermostat.set_temp_mon_lower_limit(val);
} }
None => { None => {
send_response( send_response(
@ -754,7 +753,7 @@ pub fn execute_cmd(
Some(ThermostatCmdEnum::SetShT0) => match cmd.json.data_f32 { Some(ThermostatCmdEnum::SetShT0) => match cmd.json.data_f32 {
Some(val) => { Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket); send_response(buffer, ResponseEnum::Acknowledge, None, socket);
thermostat.set_sh_t0(ThermodynamicTemperature::new::<degree_celsius>(val)); thermostat.set_sh_t0(val);
} }
None => { None => {
send_response( send_response(

View File

@ -2,8 +2,7 @@ use miniconf::Tree;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uom::si::{electric_potential::volt, use uom::si::{electric_potential::volt,
electrical_resistance::ohm, electrical_resistance::ohm,
f32::{ElectricPotential, ElectricalResistance, ThermodynamicTemperature}, f32::{ElectricPotential, ElectricalResistance}};
thermodynamic_temperature::degree_celsius};
use crate::thermostat::{ad7172, steinhart_hart as sh}; use crate::thermostat::{ad7172, steinhart_hart as sh};
const R_INNER: f32 = 2.0 * 5100.0; const R_INNER: f32 = 2.0 * 5100.0;
@ -48,7 +47,7 @@ pub struct PidState {
adc_data: Option<u32>, adc_data: Option<u32>,
adc_calibration: ad7172::ChannelCalibration, adc_calibration: ad7172::ChannelCalibration,
pid_engaged: bool, pid_engaged: bool,
set_point: ThermodynamicTemperature, set_point: f32,
sh: sh::Parameters, sh: sh::Parameters,
controller: Controller, controller: Controller,
} }
@ -59,7 +58,7 @@ impl Default for PidState {
adc_data: None, adc_data: None,
adc_calibration: ad7172::ChannelCalibration::default(), adc_calibration: ad7172::ChannelCalibration::default(),
pid_engaged: false, pid_engaged: false,
set_point: ThermodynamicTemperature::new::<degree_celsius>(0.0), set_point: 0.0,
sh: sh::Parameters::default(), sh: sh::Parameters::default(),
controller: Controller { controller: Controller {
parameters: Parameters::default(), parameters: Parameters::default(),
@ -98,8 +97,8 @@ impl PidState {
// + x2 * kd // + x2 * kd
// y0 = clip(y0', ymin, ymax) // y0 = clip(y0', ymin, ymax)
pub fn update_pid(&mut self) -> Option<f64> { pub fn update_pid(&mut self) -> Option<f64> {
let input = self.get_temperature()?.get::<degree_celsius>(); let input = self.get_temperature()?;
let setpoint = self.set_point.get::<degree_celsius>(); let setpoint = self.set_point;
let mut output: f64 = self.controller.y1 - setpoint as f64 * f64::from(self.controller.parameters.ki) let mut output: f64 = self.controller.y1 - setpoint as f64 * f64::from(self.controller.parameters.ki)
+ input as f64 + input as f64
* f64::from( * f64::from(
@ -133,7 +132,7 @@ impl PidState {
Some(r) Some(r)
} }
pub fn get_temperature(&self) -> Option<ThermodynamicTemperature> { pub fn get_temperature(&self) -> Option<f32> {
let r = self.get_sens()?; let r = self.get_sens()?;
let temperature = self.sh.get_temperature(r); let temperature = self.sh.get_temperature(r);
Some(temperature) Some(temperature)
@ -170,15 +169,15 @@ impl PidState {
self.controller.y1 = 0.0; self.controller.y1 = 0.0;
} }
pub fn set_pid_setpoint(&mut self, temperature: ThermodynamicTemperature) { pub fn set_pid_setpoint(&mut self, temperature: f32) {
self.set_point = temperature; self.set_point = temperature;
} }
pub fn get_pid_setpoint(&mut self) -> ThermodynamicTemperature { pub fn get_pid_setpoint(&mut self) -> f32 {
self.set_point self.set_point
} }
pub fn set_sh_t0(&mut self, t0: ThermodynamicTemperature) { pub fn set_sh_t0(&mut self, t0: f32) {
self.sh.t0 = t0 self.sh.t0 = t0
} }

View File

@ -2,33 +2,32 @@ use miniconf::Tree;
use num_traits::float::Float; use num_traits::float::Float;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uom::si::{electrical_resistance::ohm, use uom::si::{electrical_resistance::ohm,
f32::{ElectricalResistance, ThermodynamicTemperature}, f32::ElectricalResistance,
ratio::ratio, ratio::ratio};
thermodynamic_temperature::{degree_celsius, kelvin}};
/// Steinhart-Hart equation parameters /// Steinhart-Hart equation parameters
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
pub struct Parameters { pub struct Parameters {
/// Base temperature /// Base temperature (Degree Celsius)
pub t0: ThermodynamicTemperature, pub t0: f32,
/// Base resistance /// Base resistance
pub r0: ElectricalResistance, pub r0: ElectricalResistance,
/// Beta /// Beta (Kelvin)
pub b: f32, pub b: f32,
} }
impl Parameters { impl Parameters {
/// Perform the voltage to temperature conversion. /// Perform the voltage to temperature conversion.
pub fn get_temperature(&self, r: ElectricalResistance) -> ThermodynamicTemperature { pub fn get_temperature(&self, r: ElectricalResistance) -> f32 {
let inv_temp = 1.0 / self.t0.get::<kelvin>() + (r / self.r0).get::<ratio>().ln() / self.b; let inv_temp = 1.0 / (self.t0 + 273.15) + (r / self.r0).get::<ratio>().ln() / self.b;
ThermodynamicTemperature::new::<kelvin>(1.0 / inv_temp) 1.0 / inv_temp - 273.15
} }
} }
impl Default for Parameters { impl Default for Parameters {
fn default() -> Self { fn default() -> Self {
Parameters { Parameters {
t0: ThermodynamicTemperature::new::<degree_celsius>(25.0), t0: 25.0,
r0: ElectricalResistance::new::<ohm>(10_000.0), r0: ElectricalResistance::new::<ohm>(10_000.0),
b: 3800.0, b: 3800.0,
} }

View File

@ -1,7 +1,6 @@
use miniconf::Tree; use miniconf::Tree;
use num_traits::Float; use num_traits::Float;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uom::si::{f32::ThermodynamicTemperature, thermodynamic_temperature::degree_celsius};
#[derive(PartialEq, Deserialize, Serialize, Copy, Clone, Default, Debug)] #[derive(PartialEq, Deserialize, Serialize, Copy, Clone, Default, Debug)]
pub enum TempStatusEnum { pub enum TempStatusEnum {
#[default] #[default]
@ -25,9 +24,9 @@ pub struct TempMonSettings {
} }
pub struct TempMon { pub struct TempMon {
pub upper_limit: ThermodynamicTemperature, pub upper_limit: f32,
pub lower_limit: ThermodynamicTemperature, pub lower_limit: f32,
pub set_point: ThermodynamicTemperature, pub set_point: f32,
pub status: TempStatus, pub status: TempStatus,
state: State, state: State,
count: u32, count: u32,
@ -38,9 +37,9 @@ pub struct TempMon {
impl Default for TempMon { impl Default for TempMon {
fn default() -> Self { fn default() -> Self {
Self { Self {
upper_limit: ThermodynamicTemperature::new::<degree_celsius>(45.0), upper_limit: 45.0,
lower_limit: ThermodynamicTemperature::new::<degree_celsius>(0.0), lower_limit: 0.0,
set_point: ThermodynamicTemperature::new::<degree_celsius>(0.0), set_point: 0.0,
status: TempStatus { status: TempStatus {
status: TempStatusEnum::Off, status: TempStatusEnum::Off,
over_temp_alarm: false, over_temp_alarm: false,
@ -68,25 +67,25 @@ impl TempMon {
const OVER_TEMP_COUNT_LIMIT: u32 = 25; const OVER_TEMP_COUNT_LIMIT: u32 = 25;
const TEMP_STABLE_COUNT_LIMIT: u32 = 100; const TEMP_STABLE_COUNT_LIMIT: u32 = 100;
pub fn set_upper_limit(&mut self, upper_limit: ThermodynamicTemperature) { pub fn set_upper_limit(&mut self, upper_limit: f32) {
self.upper_limit = upper_limit; self.upper_limit = upper_limit;
self.is_limit_changed = true; self.is_limit_changed = true;
} }
pub fn get_upper_limit(&mut self) -> ThermodynamicTemperature { pub fn get_upper_limit(&mut self) -> f32 {
self.upper_limit self.upper_limit
} }
pub fn set_lower_limit(&mut self, lower_limit: ThermodynamicTemperature) { pub fn set_lower_limit(&mut self, lower_limit: f32) {
self.lower_limit = lower_limit; self.lower_limit = lower_limit;
self.is_limit_changed = true; self.is_limit_changed = true;
} }
pub fn get_lower_limit(&mut self) -> ThermodynamicTemperature { pub fn get_lower_limit(&mut self) -> f32 {
self.lower_limit self.lower_limit
} }
pub fn set_setpoint(&mut self, set_point: ThermodynamicTemperature) { pub fn set_setpoint(&mut self, set_point: f32) {
if self.set_point != set_point { if self.set_point != set_point {
self.is_set_point_changed = true; self.is_set_point_changed = true;
self.count = 0; self.count = 0;
@ -99,7 +98,7 @@ impl TempMon {
self.state = State::default(); self.state = State::default();
} }
pub fn update_status(&mut self, pid_engaged: bool, pwr_on: bool, temp: ThermodynamicTemperature) { pub fn update_status(&mut self, pid_engaged: bool, pwr_on: bool, temp: f32) {
match self.state { match self.state {
State::PwrOff => { State::PwrOff => {
self.is_set_point_changed = false; self.is_set_point_changed = false;
@ -135,10 +134,10 @@ impl TempMon {
State::PidStartUp | State::PidStable => { State::PidStartUp | State::PidStable => {
let mut is_over_temp = temp > self.upper_limit || temp < self.lower_limit; let mut is_over_temp = temp > self.upper_limit || temp < self.lower_limit;
if self.state != State::PidStartUp { if self.state != State::PidStartUp {
is_over_temp = is_over_temp || (temp.value - self.set_point.value).abs() > 0.5; is_over_temp = is_over_temp || (temp - self.set_point).abs() > 0.5;
} }
let is_within_spec: bool = (temp.value - self.set_point.value).abs() < 0.001; let is_within_spec: bool = (temp - self.set_point).abs() < 0.001;
if is_over_temp { if is_over_temp {
if self.count > TempMon::OVER_TEMP_COUNT_LIMIT { if self.count > TempMon::OVER_TEMP_COUNT_LIMIT {
self.status.status = TempStatusEnum::OverTemp; self.status.status = TempStatusEnum::OverTemp;
@ -191,8 +190,8 @@ impl TempMon {
pub fn get_settings(&mut self) -> TempMonSettings { pub fn get_settings(&mut self) -> TempMonSettings {
TempMonSettings { TempMonSettings {
upper_limit: self.upper_limit.get::<degree_celsius>(), upper_limit: self.upper_limit,
lower_limit: self.lower_limit.get::<degree_celsius>(), lower_limit: self.lower_limit,
} }
} }
} }

View File

@ -6,9 +6,8 @@ use serde::{Deserialize, Serialize};
use uom::si::{electric_current::ampere, use uom::si::{electric_current::ampere,
electric_potential::volt, electric_potential::volt,
electrical_resistance::ohm, electrical_resistance::ohm,
f32::{ElectricCurrent, ElectricPotential, ElectricalResistance, ThermodynamicTemperature}, f32::{ElectricCurrent, ElectricPotential, ElectricalResistance},
ratio::ratio, ratio::ratio};
thermodynamic_temperature::degree_celsius};
use crate::{sys_timer, use crate::{sys_timer,
thermostat::{ad5680, thermostat::{ad5680,
@ -185,7 +184,7 @@ impl Thermostat {
self.temp_mon self.temp_mon
.update_status(pid_engaged, self.max1968.is_powered_on(), temp); .update_status(pid_engaged, self.max1968.is_powered_on(), temp);
debug!("state.get_pid_engaged(): {:?}", pid_engaged); debug!("state.get_pid_engaged(): {:?}", pid_engaged);
debug!("Temperature: {:?} degree", temp.get::<degree_celsius>()); debug!("Temperature: {:?} degree", temp);
data_rdy = true; data_rdy = true;
}); });
data_rdy data_rdy
@ -200,7 +199,7 @@ impl Thermostat {
self.set_i(ElectricCurrent::new::<ampere>(pid_output as f32)); self.set_i(ElectricCurrent::new::<ampere>(pid_output as f32));
debug!( debug!(
"Temperature Set Point: {:?} degree", "Temperature Set Point: {:?} degree",
self.pid_ctrl_ch0.get_pid_setpoint().get::<degree_celsius>() self.pid_ctrl_ch0.get_pid_setpoint()
); );
} }
None => {} None => {}
@ -357,7 +356,7 @@ impl Thermostat {
let temperature: Option<f32>; let temperature: Option<f32>;
match self.pid_ctrl_ch0.get_temperature() { match self.pid_ctrl_ch0.get_temperature() {
Some(val) => temperature = Some(val.get::<degree_celsius>()), Some(val) => temperature = Some(val),
None => { None => {
temperature = None; temperature = None;
} }
@ -374,10 +373,10 @@ impl Thermostat {
} }
} }
pub fn get_temperature(&mut self) -> ThermodynamicTemperature { pub fn get_temperature(&mut self) -> f32 {
match self.pid_ctrl_ch0.get_temperature() { match self.pid_ctrl_ch0.get_temperature() {
Some(val) => val, Some(val) => val,
None => ThermodynamicTemperature::new::<degree_celsius>(NAN), None => NAN,
} }
} }
@ -388,7 +387,7 @@ impl Thermostat {
fn get_steinhart_hart(&mut self) -> ThermistorParams { fn get_steinhart_hart(&mut self) -> ThermistorParams {
let sh = self.pid_ctrl_ch0.get_sh(); let sh = self.pid_ctrl_ch0.get_sh();
ThermistorParams { ThermistorParams {
t0: sh.t0.get::<degree_celsius>(), t0: sh.t0,
r0: sh.r0, r0: sh.r0,
b: sh.b, b: sh.b,
} }
@ -396,7 +395,7 @@ impl Thermostat {
fn apply_steinhart_hart(&mut self, sh: ThermistorParams) { fn apply_steinhart_hart(&mut self, sh: ThermistorParams) {
self.pid_ctrl_ch0.apply_sh(Sh_Params { self.pid_ctrl_ch0.apply_sh(Sh_Params {
t0: ThermodynamicTemperature::new::<degree_celsius>(sh.t0), t0: sh.t0,
r0: sh.r0, r0: sh.r0,
b: sh.b, b: sh.b,
}) })
@ -439,11 +438,11 @@ impl Thermostat {
self.pid_ctrl_ch0.set_sh_r0(r0); self.pid_ctrl_ch0.set_sh_r0(r0);
} }
pub fn set_sh_t0(&mut self, t0: ThermodynamicTemperature) { pub fn set_sh_t0(&mut self, t0: f32) {
self.pid_ctrl_ch0.set_sh_t0(t0); self.pid_ctrl_ch0.set_sh_t0(t0);
} }
pub fn set_temperature_setpoint(&mut self, t: ThermodynamicTemperature) { pub fn set_temperature_setpoint(&mut self, t: f32) {
let t = t let t = t
.min(self.temp_mon.get_upper_limit()) .min(self.temp_mon.get_upper_limit())
.max(self.temp_mon.get_lower_limit()); .max(self.temp_mon.get_lower_limit());
@ -453,16 +452,16 @@ impl Thermostat {
pub fn apply_temp_mon_settings(&mut self, settings: TempMonSettings) { pub fn apply_temp_mon_settings(&mut self, settings: TempMonSettings) {
self.temp_mon self.temp_mon
.set_upper_limit(ThermodynamicTemperature::new::<degree_celsius>(settings.upper_limit)); .set_upper_limit(settings.upper_limit);
self.temp_mon self.temp_mon
.set_lower_limit(ThermodynamicTemperature::new::<degree_celsius>(settings.lower_limit)); .set_lower_limit(settings.lower_limit);
} }
pub fn set_temp_mon_upper_limit(&mut self, t: ThermodynamicTemperature) { pub fn set_temp_mon_upper_limit(&mut self, t: f32) {
self.temp_mon.set_upper_limit(t); self.temp_mon.set_upper_limit(t);
} }
pub fn set_temp_mon_lower_limit(&mut self, t: ThermodynamicTemperature) { pub fn set_temp_mon_lower_limit(&mut self, t: f32) {
self.temp_mon.set_lower_limit(t); self.temp_mon.set_lower_limit(t);
} }
@ -508,7 +507,7 @@ impl Thermostat {
ThermostatSettingsSummary { ThermostatSettingsSummary {
default_pwr_on: self.tec_settings.default_pwr_on, default_pwr_on: self.tec_settings.default_pwr_on,
pid_engaged: self.get_pid_engaged(), pid_engaged: self.get_pid_engaged(),
temperature_setpoint: self.pid_ctrl_ch0.get_pid_setpoint().get::<degree_celsius>(), temperature_setpoint: self.pid_ctrl_ch0.get_pid_setpoint(),
tec_settings: self.get_tec_settings(), tec_settings: self.get_tec_settings(),
pid_params: self.get_pid_settings(), pid_params: self.get_pid_settings(),
temp_adc_settings: TempAdcFilter { temp_adc_settings: TempAdcFilter {
@ -549,9 +548,7 @@ impl Thermostat {
self.set_pid_engaged(settings.pid_engaged); self.set_pid_engaged(settings.pid_engaged);
self.pid_ctrl_ch0.apply_pid_params(settings.pid_params); self.pid_ctrl_ch0.apply_pid_params(settings.pid_params);
self.set_temperature_setpoint(ThermodynamicTemperature::new::<degree_celsius>( self.set_temperature_setpoint(settings.temperature_setpoint);
settings.temperature_setpoint,
));
if !settings.pid_engaged { if !settings.pid_engaged {
self.set_i(settings.tec_settings.i_set.value); self.set_i(settings.tec_settings.i_set.value);
} }