add LSV peak state, auto/manual toggle, and peak readout to app

This commit is contained in:
jess 2026-04-02 18:14:41 -07:00
parent 30cd80d03b
commit df6268d2ac
1 changed files with 41 additions and 5 deletions

View File

@ -124,6 +124,8 @@ pub enum Message {
BrowseLoadAsReference(i64), BrowseLoadAsReference(i64),
BrowseDeleteMeasurement(i64), BrowseDeleteMeasurement(i64),
BrowseBack, BrowseBack,
/* LSV analysis */
LsvToggleManual,
/* Misc */ /* Misc */
Reconnect, Reconnect,
UdpAddrChanged(String), UdpAddrChanged(String),
@ -170,6 +172,8 @@ pub struct App {
lsv_stop_v: String, lsv_stop_v: String,
lsv_scan_rate: String, lsv_scan_rate: String,
lsv_rtia: LpRtia, lsv_rtia: LpRtia,
lsv_peaks: Vec<crate::lsv_analysis::LsvPeak>,
lsv_manual_peaks: bool,
lsv_data: text_editor::Content, lsv_data: text_editor::Content,
/* Amp */ /* Amp */
@ -407,6 +411,8 @@ impl App {
lsv_stop_v: "500".into(), lsv_stop_v: "500".into(),
lsv_scan_rate: "50".into(), lsv_scan_rate: "50".into(),
lsv_rtia: LpRtia::R10K, lsv_rtia: LpRtia::R10K,
lsv_peaks: Vec::new(),
lsv_manual_peaks: false,
lsv_data: text_editor::Content::with_text(&fmt_lsv(&[])), lsv_data: text_editor::Content::with_text(&fmt_lsv(&[])),
amp_points: Vec::new(), amp_points: Vec::new(),
@ -630,6 +636,9 @@ impl App {
if let Some(sid) = self.current_session { if let Some(sid) = self.current_session {
self.save_lsv(sid); self.save_lsv(sid);
} }
if !self.lsv_manual_peaks {
self.lsv_peaks = crate::lsv_analysis::detect_peaks(&self.lsv_points);
}
self.status = format!("LSV complete: {} points", self.lsv_points.len()); self.status = format!("LSV complete: {} points", self.lsv_points.len());
} }
EisMessage::AmpStart { v_hold } => { EisMessage::AmpStart { v_hold } => {
@ -807,6 +816,14 @@ impl App {
self.send_cmd(&protocol::build_sysex_get_temp()); self.send_cmd(&protocol::build_sysex_get_temp());
self.send_cmd(&protocol::build_sysex_start_lsv(vs, ve, sr, self.lsv_rtia)); self.send_cmd(&protocol::build_sysex_start_lsv(vs, ve, sr, self.lsv_rtia));
} }
Message::LsvToggleManual => {
self.lsv_manual_peaks = !self.lsv_manual_peaks;
if self.lsv_manual_peaks {
self.lsv_peaks.clear();
} else {
self.lsv_peaks = crate::lsv_analysis::detect_peaks(&self.lsv_points);
}
}
/* Amp */ /* Amp */
Message::AmpVholdChanged(s) => self.amp_v_hold = s, Message::AmpVholdChanged(s) => self.amp_v_hold = s,
Message::AmpIntervalChanged(s) => self.amp_interval = s, Message::AmpIntervalChanged(s) => self.amp_interval = s,
@ -1404,6 +1421,9 @@ impl App {
.style(style_action()) .style(style_action())
.padding([6, 16]) .padding([6, 16])
.on_press(Message::StartLsv), .on_press(Message::StartLsv),
button(text(if self.lsv_manual_peaks { "Manual" } else { "Auto" }).size(13))
.padding([6, 12])
.on_press(Message::LsvToggleManual),
] ]
.spacing(10) .spacing(10)
.align_y(iced::Alignment::End) .align_y(iced::Alignment::End)
@ -1515,11 +1535,27 @@ impl App {
.height(Length::Fill); .height(Length::Fill);
row![bode, nyquist].spacing(10).height(Length::Fill).into() row![bode, nyquist].spacing(10).height(Length::Fill).into()
} }
Tab::Lsv => canvas(crate::plot::VoltammogramPlot { Tab::Lsv => {
points: &self.lsv_points, let plot = canvas(crate::plot::VoltammogramPlot {
reference: self.lsv_ref.as_deref(), points: &self.lsv_points,
}) reference: self.lsv_ref.as_deref(),
.width(Length::Fill).height(Length::Fill).into(), peaks: &self.lsv_peaks,
})
.width(Length::Fill).height(Length::Fill);
if self.lsv_peaks.is_empty() {
plot.into()
} else {
let info: Vec<String> = self.lsv_peaks.iter().map(|p| {
use crate::lsv_analysis::PeakKind;
match p.kind {
PeakKind::FreeCl => format!("Free: {:.0}mV {:.2}uA", p.v_mv, p.i_ua),
PeakKind::TotalCl => format!("Total: {:.0}mV {:.2}uA", p.v_mv, p.i_ua),
PeakKind::Crossover => format!("X-over: {:.0}mV", p.v_mv),
}
}).collect();
column![text(info.join(" | ")).size(14), plot].spacing(4).height(Length::Fill).into()
}
}
Tab::Amp => canvas(crate::plot::AmperogramPlot { Tab::Amp => canvas(crate::plot::AmperogramPlot {
points: &self.amp_points, points: &self.amp_points,
reference: self.amp_ref.as_deref(), reference: self.amp_ref.as_deref(),