From 58d14db5120580343089a86f4b46ff505877dd1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 25 Oct 2024 15:37:32 +0000 Subject: [PATCH] cleanup, code style --- Cargo.toml | 3 +-- src/hardware/adc.rs | 18 ++++++++------- src/main.rs | 33 +++++++++++++-------------- src/output_channel.rs | 52 ++++++++++++++++++++++++++++--------------- 4 files changed, 61 insertions(+), 45 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 51e8c25..fa63eb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,6 @@ idsp = "0.15.0" embedded-hal = "0.2.7" bitbybit = "1.3.2" arbitrary-int = "1.2.7" -# stabilizer = "0.9.0" lm75 = "0.2" bytemuck = { version = "1.19.0", features = [ "derive", @@ -86,7 +85,7 @@ incremental = false opt-level = 3 [profile.release] -opt-level = 3 +opt-level = "s" debug = true lto = true codegen-units = 1 diff --git a/src/hardware/adc.rs b/src/hardware/adc.rs index f5988dd..42c8396 100644 --- a/src/hardware/adc.rs +++ b/src/hardware/adc.rs @@ -110,7 +110,9 @@ pub trait Convert { fn convert(&self, code: AdcCode) -> f64; } -/// relative_voltage * gain + offset +/// Relative_voltage * gain + offset +/// +/// Use also for RTD #[derive(Clone, Copy, Debug, Tree)] pub struct Linear { /// Units: output @@ -180,7 +182,7 @@ pub struct Dt670 { impl Default for Dt670 { fn default() -> Self { - Self { v_ref: 5.0.into() } + Self { v_ref: 2.5.into() } } } @@ -188,12 +190,12 @@ impl Convert for Dt670 { fn convert(&self, code: AdcCode) -> f64 { let voltage = f32::from(code) * *self.v_ref; const CURVE: &[(f32, f32, f32)] = &super::dt670::CURVE; - let idx = CURVE.partition_point(|&(_t, v, _dvdt)| v < voltage); - CURVE - .get(idx) - .or(CURVE.last()) - .map(|&(t, v, dvdt)| (t + (voltage - v) * 1.0e3 / dvdt) as f64) - .unwrap() + // This is clearly simplistic. + // It is discontinuous at LUT jumps due to dvdt precision. + // Should use proper interpolation, there are some crates. + let idx = CURVE.partition_point(|&(_, v, _)| v < voltage); + let (t, v, dvdt) = CURVE.get(idx).or(CURVE.last()).unwrap(); + (t + (voltage - v) * 1.0e3 / dvdt) as f64 } } diff --git a/src/main.rs b/src/main.rs index e5ecec6..0890e2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ use strum::IntoEnumIterator; use hardware::{ adc::AdcPhy, - adc::{sm::StateMachine, Adc, AdcCode, Sensor}, + adc::{sm::StateMachine, Adc, AdcCode, Ntc, Sensor}, adc_internal::AdcInternal, dac::{Dac, DacCode}, gpio::{Gpio, PoePower}, @@ -172,8 +172,6 @@ struct Data { #[rtic::app(device = hal::stm32, peripherals = true, dispatchers=[DCMI, JPEG, SDMMC])] mod app { - use hardware::adc::Ntc; - use super::*; #[shared] @@ -211,13 +209,14 @@ mod app { .settings .thermostat_eem .input + .as_flattened_mut() .iter_mut() - .flatten() - .zip(thermostat.adc_input_config.iter_mut().flatten()) + .zip(thermostat.adc_input_config.as_flattened().iter()) { if let Some(mux) = mux { let r_ref = if mux.is_single_ended() { 5.0e3 } else { 10.0e3 }; *channel = Some(InputChannel { + // This isn't ideal as it confilcts with the default/clear notion of serial-settings. sensor: Sensor::Ntc(Ntc::new(25.0, 10.0e3, r_ref, 3988.0)).into(), ..Default::default() }); @@ -354,16 +353,16 @@ mod app { if *alarm.armed { let temperatures = c.shared.temperature.lock(|temp| *temp); let mut alarms = [[None; 4]; 4]; - let mut alarm_state = false; - for phy_i in 0..4 { - for cfg_i in 0..4 { - if let Some(l) = &alarm.temperature_limits[phy_i][cfg_i] { - let a = !(*l[0]..*l[1]).contains(&(temperatures[phy_i][cfg_i] as _)); - alarms[phy_i][cfg_i] = Some(a); - alarm_state |= a; - } - } - } + let alarm_state = alarm + .temperature_limits + .as_flattened() + .iter() + .zip(temperatures.as_flattened().iter()) + .zip(alarms.as_flattened_mut().iter_mut()) + .any(|((l, t), a)| { + *a = l.map(|l| !(*l[0]..*l[1]).contains(&(*t as _))); + a.unwrap_or_default() + }); c.shared .telemetry .lock(|telemetry| telemetry.alarm = alarms); @@ -416,9 +415,9 @@ mod app { }; for (t, u) in s .temperature + .as_flattened_mut() .iter_mut() - .flatten() - .zip(temperature.iter().flatten()) + .zip(temperature.as_flattened().iter()) { *t = *u as _; } diff --git a/src/output_channel.rs b/src/output_channel.rs index 50c84c6..3437939 100644 --- a/src/output_channel.rs +++ b/src/output_channel.rs @@ -8,13 +8,39 @@ use num_traits::Float; #[derive(Copy, Clone, Debug, Tree)] pub struct Pid { + /// Integral gain + /// + /// Units: output/input per second pub ki: Leaf, - pub kp: Leaf, // sign reference for all gains and limits + /// Proportional gain + /// + /// Note that this is the sign reference for all gains and limits + /// + /// Units: output/input + pub kp: Leaf, + /// Derivative gain + /// + /// Units: output/input*second pub kd: Leaf, + /// Integral gain limit + /// + /// Units: output/input pub li: Leaf, + /// Derivative gain limit + /// + /// Units: output/input pub ld: Leaf, + /// Setpoint + /// + /// Units: input pub setpoint: Leaf, + /// Output lower limit + /// + /// Units: output pub min: Leaf, + /// Output upper limit + /// + /// Units: output pub max: Leaf, } @@ -100,28 +126,18 @@ pub struct OutputChannel { /// 0.0 to 4.3 pub voltage_limit: Leaf, + /// PID/Biquad/IIR filter parameters + /// + /// The y limits will be clamped to the maximum output current of +-3 A. pub pid: Pid, - /// IIR filter parameters. - /// The y limits will be clamped to the maximum output current of +-3 A. - /// - /// # Value - /// See [iir::Biquad] #[tree(skip)] pub iir: iir::Biquad, - /// Thermostat input channel weights. Each input temperature of an enabled channel + /// Thermostat input channel weights. Each input of an enabled input channel /// is multiplied by its weight and the accumulated output is fed into the IIR. /// The weights will be internally normalized to one (sum of the absolute values) /// if they are not all zero. - /// - /// # Path - /// `weights//` - /// * ` := [0, 1, 2, 3]` specifies which adc to configure. - /// * `` specifies which channel of an ADC to configure. Only the enabled channels for the specific ADC are available. - /// - /// # Value - /// f32 pub weights: Leaf<[[f32; 4]; 4]>, } @@ -141,9 +157,9 @@ impl OutputChannel { /// compute weighted iir input, iir state and return the new output pub fn update(&mut self, temperatures: &[[f64; 4]; 4], iir_state: &mut [f64; 4]) -> f64 { let temperature = temperatures + .as_flattened() .iter() - .flatten() - .zip(self.weights.iter().flatten()) + .zip(self.weights.as_flattened().iter()) .map(|(t, w)| t * *w as f64) .sum(); let iir = if *self.state == State::On { @@ -175,7 +191,7 @@ impl OutputChannel { // Note: The weights which are not 'None' should always affect an enabled channel and therefore count for normalization. if divisor != 0.0 { let n = divisor.recip(); - for w in self.weights.iter_mut().flatten() { + for w in self.weights.as_flattened_mut().iter_mut() { *w *= n; } }