Compare commits

...

4 Commits

3 changed files with 58 additions and 31 deletions

View File

@ -28,6 +28,7 @@ series = {
'sens': Series(0.0001), 'sens': Series(0.0001),
'temperature': Series(), 'temperature': Series(),
'i_set': Series(), 'i_set': Series(),
'pid_output': Series(),
'vref': Series(), 'vref': Series(),
'dac_feedback': Series(), 'dac_feedback': Series(),
'i_tec': Series(), 'i_tec': Series(),
@ -39,7 +40,6 @@ series_lock = Lock()
quit = False quit = False
def recv_data(tec): def recv_data(tec):
print("reporting")
for data in tec.report_mode(): for data in tec.report_mode():
if data['channel'] == 0: if data['channel'] == 0:
series_lock.acquire() series_lock.acquire()
@ -56,7 +56,6 @@ def recv_data(tec):
break break
tec = Client() tec = Client()
print("connected")
thread = Thread(target=recv_data, args=(tec,)) thread = Thread(target=recv_data, args=(tec,))
thread.start() thread.start()
@ -64,15 +63,17 @@ fig, ax = plt.subplots()
for k, s in series.iteritems(): for k, s in series.iteritems():
s.plot, = ax.plot([], [], label=k) s.plot, = ax.plot([], [], label=k)
ax.legend() legend = ax.legend()
def animate(i): def animate(i):
min_x, max_x, min_y, max_y = None, None, None, None min_x, max_x, min_y, max_y = None, None, None, None
series_lock.acquire() series_lock.acquire()
try: try:
for s in series.itervalues(): for k, s in series.iteritems():
s.plot.set_data(s.x_data, s.y_data) s.plot.set_data(s.x_data, s.y_data)
if len(s.y_data) > 0:
s.plot.set_label("{}: {:.3f}".format(k, s.y_data[-1]))
if len(s.x_data) > 0: if len(s.x_data) > 0:
min_x_ = min(s.x_data) min_x_ = min(s.x_data)
@ -107,21 +108,13 @@ def animate(i):
ax.set_xlim(min_x, max_x) ax.set_xlim(min_x, max_x)
ax.set_ylim(min_y - margin_y, max_y + margin_y) ax.set_ylim(min_y - margin_y, max_y + margin_y)
global legend
legend.remove()
legend = ax.legend()
ani = animation.FuncAnimation( ani = animation.FuncAnimation(
fig, animate, interval=1, blit=False, save_count=50) fig, animate, interval=1, blit=False, save_count=50)
# To save the animation, use e.g.
#
# ani.save("movie.mp4")
#
# or
#
# writer = animation.FFMpegWriter(
# fps=15, metadata=dict(artist='Me'), bitrate=1800)
# ani.save("movie.mp4", writer=writer)
print("show")
plt.show() plt.show()
quit = True quit = True
thread.join() thread.join()

View File

@ -91,6 +91,19 @@ impl Channels {
}) })
} }
/// calculate the TEC i_set centerpoint
pub fn get_center(&mut self, channel: usize) -> ElectricPotential {
match self.channel_state(channel).center {
CenterPoint::Vref => {
let vref = self.read_vref(channel);
self.channel_state(channel).vref = vref;
vref
},
CenterPoint::Override(center_point) =>
ElectricPotential::new::<volt>(center_point.into()),
}
}
/// i_set DAC /// i_set DAC
fn get_dac(&mut self, channel: usize) -> (ElectricPotential, ElectricPotential) { fn get_dac(&mut self, channel: usize) -> (ElectricPotential, ElectricPotential) {
let dac_factor = match channel.into() { let dac_factor = match channel.into() {
@ -104,13 +117,7 @@ impl Channels {
} }
pub fn get_i(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) { pub fn get_i(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) {
let state = self.channel_state(channel); let center_point = self.get_center(channel);
let center_point = match state.center {
CenterPoint::Vref =>
state.vref,
CenterPoint::Override(center_point) =>
ElectricPotential::new::<volt>(center_point.into()),
};
let r_sense = ElectricalResistance::new::<ohm>(R_SENSE); let r_sense = ElectricalResistance::new::<ohm>(R_SENSE);
let (voltage, max) = self.get_dac(channel); let (voltage, max) = self.get_dac(channel);
let i_tec = (voltage - center_point) / (10.0 * r_sense); let i_tec = (voltage - center_point) / (10.0 * r_sense);
@ -138,13 +145,7 @@ impl Channels {
} }
pub fn set_i(&mut self, channel: usize, i_tec: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) { pub fn set_i(&mut self, channel: usize, i_tec: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) {
let state = self.channel_state(channel); let center_point = self.get_center(channel);
let center_point = match state.center {
CenterPoint::Vref =>
state.vref,
CenterPoint::Override(center_point) =>
ElectricPotential::new::<volt>(center_point.into()),
};
let r_sense = ElectricalResistance::new::<ohm>(R_SENSE); let r_sense = ElectricalResistance::new::<ohm>(R_SENSE);
let voltage = i_tec * 10.0 * r_sense + center_point; let voltage = i_tec * 10.0 * r_sense + center_point;
let (voltage, max) = self.set_dac(channel, voltage); let (voltage, max) = self.set_dac(channel, voltage);
@ -417,6 +418,9 @@ impl Channels {
let i_tec = self.read_itec(channel); let i_tec = self.read_itec(channel);
let tec_i = (i_tec - vref) / ElectricalResistance::new::<ohm>(0.4); let tec_i = (i_tec - vref) / ElectricalResistance::new::<ohm>(0.4);
let state = self.channel_state(channel); let state = self.channel_state(channel);
let pid_output = state.pid.last_output.map(|last_output|
ElectricCurrent::new::<ampere>(last_output)
);
Report { Report {
channel, channel,
time: state.adc_time.total_millis(), time: state.adc_time.total_millis(),
@ -431,6 +435,7 @@ impl Channels {
i_tec, i_tec,
tec_i, tec_i,
tec_u_meas: self.read_tec_u_meas(channel), tec_u_meas: self.read_tec_u_meas(channel),
pid_output,
} }
} }
} }
@ -449,12 +454,41 @@ pub struct Report {
i_tec: ElectricPotential, i_tec: ElectricPotential,
tec_i: ElectricCurrent, tec_i: ElectricCurrent,
tec_u_meas: ElectricPotential, tec_u_meas: ElectricPotential,
pid_output: Option<ElectricCurrent>,
} }
type JsonBuffer = heapless::Vec<u8, heapless::consts::U320>; type JsonBuffer = heapless::Vec<u8, heapless::consts::U360>;
impl Report { impl Report {
pub fn to_json(&self) -> Result<JsonBuffer, serde_json_core::ser::Error> { pub fn to_json(&self) -> Result<JsonBuffer, serde_json_core::ser::Error> {
serde_json_core::to_vec(self) serde_json_core::to_vec(self)
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn report_to_json() {
// `/ 1.1` results in values with a really long serialization
let report = Report {
channel: 0,
time: 3200,
adc: Some(ElectricPotential::new::<volt>(0.65 / 1.1)),
sens: Some(ElectricalResistance::new::<ohm>(10000.0 / 1.1)),
temperature: Some(30.0 / 1.1),
pid_engaged: false,
i_set: ElectricCurrent::new::<ampere>(0.5 / 1.1),
vref: ElectricPotential::new::<volt>(1.5 / 1.1),
dac_feedback: ElectricPotential::new::<volt>(2.0 / 1.1),
i_tec: ElectricPotential::new::<volt>(2.0 / 1.1),
tec_i: ElectricCurrent::new::<ampere>(0.2 / 1.1),
tec_u_meas: ElectricPotential::new::<volt>(2.0 / 1.1),
pid_output: Some(ElectricCurrent::new::<ampere>(0.5 / 1.1)),
};
let buf = report.to_json().unwrap();
assert_eq!(buf[0], b'{');
assert_eq!(buf[buf.len() - 1], b'}');
}
}

View File

@ -4,7 +4,7 @@ use crate::usb;
pub fn init_log() { pub fn init_log() {
static USB_LOGGER: usb::Logger = usb::Logger; static USB_LOGGER: usb::Logger = usb::Logger;
let _ = log::set_logger(&USB_LOGGER); let _ = log::set_logger(&USB_LOGGER);
log::set_max_level(log::LevelFilter::Info); log::set_max_level(log::LevelFilter::Trace);
} }
#[cfg(feature = "semihosting")] #[cfg(feature = "semihosting")]