forked from M-Labs/ionpak-thermostat
add configurable Steinhart-Hart equation
This commit is contained in:
parent
2992688184
commit
8611cc1c79
|
@ -50,23 +50,26 @@ The scope of this setting is per TCP session.
|
||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
| Syntax | Function |
|
| Syntax | Function |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `report` | Show current input |
|
| `report` | Show current input |
|
||||||
| `report mode` | Show current report mode |
|
| `report mode` | Show current report mode |
|
||||||
| `report mode <off/on>` | Set report mode |
|
| `report mode <off/on>` | Set report mode |
|
||||||
| `pwm <0/1> max_i_pos <width> <total>` | Set PWM duty cycle for **max_i_pos** to *width / total* |
|
| `pwm <0/1> max_i_pos <width> <total>` | Set PWM duty cycle for **max_i_pos** to *width / total* |
|
||||||
| `pwm <0/1> max_i_neg <width> <total>` | Set PWM duty cycle for **max_i_neg** to *width / total* |
|
| `pwm <0/1> max_i_neg <width> <total>` | Set PWM duty cycle for **max_i_neg** to *width / total* |
|
||||||
| `pwm <0/1> max_v <width> <total>` | Set PWM duty cycle for **max_v** to *width / total* |
|
| `pwm <0/1> max_v <width> <total>` | Set PWM duty cycle for **max_v** to *width / total* |
|
||||||
| `pwm <0/1> <width> <total>` | Set PWM duty cycle for **i_set** to manual *width / total* |
|
| `pwm <0/1> <width> <total>` | Set PWM duty cycle for **i_set** to manual *width / total* |
|
||||||
| `pwm <0/1> pid` | Set PWM to be controlled by PID |
|
| `pwm <0/1> pid` | Set PWM to be controlled by PID |
|
||||||
| `pid` | Show PID configuration |
|
| `pid` | Show PID configuration |
|
||||||
| `pid <0/1> target <value>` | Set the PID controller target |
|
| `pid <0/1> target <value>` | Set the PID controller target |
|
||||||
| `pid <0/1> kp <value>` | Set proportional gain |
|
| `pid <0/1> kp <value>` | Set proportional gain |
|
||||||
| `pid <0/1> ki <value>` | Set integral gain |
|
| `pid <0/1> ki <value>` | Set integral gain |
|
||||||
| `pid <0/1> kd <value>` | Set differential gain |
|
| `pid <0/1> kd <value>` | Set differential gain |
|
||||||
| `pid <0/1> output_min <value>` | Set mininum output |
|
| `pid <0/1> output_min <value>` | Set mininum output |
|
||||||
| `pid <0/1> output_max <value>` | Set maximum output |
|
| `pid <0/1> output_max <value>` | Set maximum output |
|
||||||
| `pid <0/1> integral_min <value>` | Set integral lower bound |
|
| `pid <0/1> integral_min <value>` | Set integral lower bound |
|
||||||
| `pid <0/1> integral_max <value>` | Set integral upper bound |
|
| `pid <0/1> integral_max <value>` | Set integral upper bound |
|
||||||
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
|
| `s-h` | Show Steinhart-Hart equation parameters |
|
||||||
|
| `s-h <0/1> <a/b/c> <value>` | Set Steinhart-Hart parameter for a channel |
|
||||||
|
| `s-h <0/1> <parallel_resistance> <value>` | Set parallel resistance of the ADC |
|
||||||
|
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
|
||||||
|
|
|
@ -66,6 +66,7 @@ pub enum ShowCommand {
|
||||||
Reporting,
|
Reporting,
|
||||||
Pwm,
|
Pwm,
|
||||||
Pid,
|
Pid,
|
||||||
|
SteinhartHart,
|
||||||
PostFilter,
|
PostFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +82,15 @@ pub enum PidParameter {
|
||||||
IntegralMax,
|
IntegralMax,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Steinhart-Hart equation parameter
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum ShParameter {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
ParallelR,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct PwmConfig {
|
pub struct PwmConfig {
|
||||||
pub width: u16,
|
pub width: u16,
|
||||||
|
@ -115,6 +125,11 @@ pub enum Command {
|
||||||
parameter: PidParameter,
|
parameter: PidParameter,
|
||||||
value: f32,
|
value: f32,
|
||||||
},
|
},
|
||||||
|
SteinhartHart {
|
||||||
|
channel: usize,
|
||||||
|
parameter: ShParameter,
|
||||||
|
value: f32,
|
||||||
|
},
|
||||||
PostFilter {
|
PostFilter {
|
||||||
channel: usize,
|
channel: usize,
|
||||||
rate: f32,
|
rate: f32,
|
||||||
|
@ -288,7 +303,7 @@ fn pid_parameter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
Ok((input, result))
|
Ok((input, result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `pid` | pid_parameter
|
/// `pid` | `pid <pid_parameter>`
|
||||||
fn pid(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
fn pid(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
let (input, _) = tag("pid")(input)?;
|
let (input, _) = tag("pid")(input)?;
|
||||||
alt((
|
alt((
|
||||||
|
@ -300,6 +315,35 @@ fn pid(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `s-h <0-1> <parameter> <value>`
|
||||||
|
fn steinhart_hart_parameter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
|
let (input, channel) = channel(input)?;
|
||||||
|
let (input, _) = whitespace(input)?;
|
||||||
|
let (input, parameter) =
|
||||||
|
alt((value(ShParameter::A, tag("a")),
|
||||||
|
value(ShParameter::B, tag("b")),
|
||||||
|
value(ShParameter::C, tag("c")),
|
||||||
|
value(ShParameter::ParallelR, tag("parallel_resistance"))
|
||||||
|
))(input)?;
|
||||||
|
let (input, _) = whitespace(input)?;
|
||||||
|
let (input, value) = float(input)?;
|
||||||
|
let result = value
|
||||||
|
.map(|value| Command::SteinhartHart { channel, parameter, value });
|
||||||
|
Ok((input, result))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `s-h` | `s-h <steinhart_hart_parameter>`
|
||||||
|
fn steinhart_hart(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
|
let (input, _) = tag("s-h")(input)?;
|
||||||
|
alt((
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
steinhart_hart_parameter
|
||||||
|
),
|
||||||
|
value(Ok(Command::Show(ShowCommand::SteinhartHart)), end)
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
fn postfilter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
fn postfilter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
let (input, _) = tag("postfilter")(input)?;
|
let (input, _) = tag("postfilter")(input)?;
|
||||||
alt((
|
alt((
|
||||||
|
@ -327,6 +371,7 @@ fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
map(report, Ok),
|
map(report, Ok),
|
||||||
pwm,
|
pwm,
|
||||||
pid,
|
pid,
|
||||||
|
steinhart_hart,
|
||||||
postfilter,
|
postfilter,
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ mod ad7172;
|
||||||
mod pid;
|
mod pid;
|
||||||
mod tec;
|
mod tec;
|
||||||
use tec::{Tec, TecPin};
|
use tec::{Tec, TecPin};
|
||||||
|
mod steinhart_hart;
|
||||||
|
use steinhart_hart as sh;
|
||||||
|
|
||||||
pub struct UART0;
|
pub struct UART0;
|
||||||
|
|
||||||
|
@ -82,6 +84,8 @@ macro_rules! create_socket {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VCC: f32 = 3.3;
|
||||||
|
|
||||||
const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters {
|
const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters {
|
||||||
kp: 1.0,
|
kp: 1.0,
|
||||||
ki: 1.0,
|
ki: 1.0,
|
||||||
|
@ -92,6 +96,13 @@ const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters {
|
||||||
integral_max: 0xffff as f32,
|
integral_max: 0xffff as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DEFAULT_SH_PARAMETERS: sh::Parameters = sh::Parameters {
|
||||||
|
a: 0.01,
|
||||||
|
b: 0.01,
|
||||||
|
c: 0.01,
|
||||||
|
parallel_r: 100.0, // TODO
|
||||||
|
};
|
||||||
|
|
||||||
const PWM_PID_WIDTH: u16 = 0xffff;
|
const PWM_PID_WIDTH: u16 = 0xffff;
|
||||||
|
|
||||||
// TODO: maybe rename to `TECS`?
|
// TODO: maybe rename to `TECS`?
|
||||||
|
@ -106,6 +117,7 @@ struct ControlState {
|
||||||
report: Option<(u64, u32)>,
|
report: Option<(u64, u32)>,
|
||||||
pid_enabled: bool,
|
pid_enabled: bool,
|
||||||
pid: pid::Controller,
|
pid: pid::Controller,
|
||||||
|
sh: sh::Parameters,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
|
@ -183,6 +195,7 @@ fn main() -> ! {
|
||||||
// Start with disengaged PID to let user setup parameters first
|
// Start with disengaged PID to let user setup parameters first
|
||||||
pid_enabled: false,
|
pid_enabled: false,
|
||||||
pid: pid::Controller::new(DEFAULT_PID_PARAMETERS.clone()),
|
pid: pid::Controller::new(DEFAULT_PID_PARAMETERS.clone()),
|
||||||
|
sh: DEFAULT_SH_PARAMETERS.clone(),
|
||||||
};
|
};
|
||||||
let mut states = [init_state.clone(), init_state.clone()];
|
let mut states = [init_state.clone(), init_state.clone()];
|
||||||
|
|
||||||
|
@ -330,6 +343,18 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Command::Show(ShowCommand::SteinhartHart) => {
|
||||||
|
for (channel, state) in states.iter().enumerate() {
|
||||||
|
let _ = writeln!(
|
||||||
|
socket, "Channel {} parameters for the Steinhart-Hart equation",
|
||||||
|
channel,
|
||||||
|
);
|
||||||
|
let _ = writeln!(socket, "- a={}", state.sh.a);
|
||||||
|
let _ = writeln!(socket, "- b={}", state.sh.b);
|
||||||
|
let _ = writeln!(socket, "- c={}", state.sh.c);
|
||||||
|
let _ = writeln!(socket, "- parallel_r={}", state.sh.parallel_r);
|
||||||
|
}
|
||||||
|
}
|
||||||
Command::Show(ShowCommand::PostFilter) => {
|
Command::Show(ShowCommand::PostFilter) => {
|
||||||
for (channel, _) in states.iter().enumerate() {
|
for (channel, _) in states.iter().enumerate() {
|
||||||
match adc.get_postfilter(channel as u8).unwrap() {
|
match adc.get_postfilter(channel as u8).unwrap() {
|
||||||
|
@ -411,6 +436,16 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
let _ = writeln!(socket, "PID parameter updated");
|
let _ = writeln!(socket, "PID parameter updated");
|
||||||
}
|
}
|
||||||
|
Command::SteinhartHart { channel, parameter, value } => {
|
||||||
|
let sh = &mut states[channel].sh;
|
||||||
|
use command_parser::ShParameter::*;
|
||||||
|
match parameter {
|
||||||
|
A => sh.a = value,
|
||||||
|
B => sh.b = value,
|
||||||
|
C => sh.c = value,
|
||||||
|
ParallelR => sh.parallel_r = value,
|
||||||
|
}
|
||||||
|
}
|
||||||
Command::PostFilter { channel, rate } => {
|
Command::PostFilter { channel, rate } => {
|
||||||
let filter = ad7172::PostFilter::closest(rate);
|
let filter = ad7172::PostFilter::closest(rate);
|
||||||
match filter {
|
match filter {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
use libm::F32Ext;
|
||||||
|
|
||||||
|
/// Steinhart-Hart equation parameters
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Parameters {
|
||||||
|
pub a: f32,
|
||||||
|
pub b: f32,
|
||||||
|
pub c: f32,
|
||||||
|
/// Parallel resistance
|
||||||
|
///
|
||||||
|
/// Not truly part of the equation but required to calculate
|
||||||
|
/// resistance from voltage.
|
||||||
|
pub parallel_r: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parameters {
|
||||||
|
/// input: Voltage
|
||||||
|
///
|
||||||
|
/// Result unit: Kelvin
|
||||||
|
pub fn get_temperature(&self, input: f32) -> f32 {
|
||||||
|
let r = self.parallel_r * input;
|
||||||
|
let ln_r = r.ln();
|
||||||
|
let inv_temp = self.a +
|
||||||
|
self.b * ln_r +
|
||||||
|
self.c * ln_r * ln_r * ln_r;
|
||||||
|
1.0 / inv_temp
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue