wire LSV peak detection into iOS AppState and LSVView with markers, labels, and toggle
This commit is contained in:
parent
324c8a7f5a
commit
491befa8c6
|
|
@ -37,6 +37,8 @@ final class AppState {
|
||||||
|
|
||||||
// LSV
|
// LSV
|
||||||
var lsvPoints: [LsvPoint] = []
|
var lsvPoints: [LsvPoint] = []
|
||||||
|
var lsvPeaks: [LsvPeak] = []
|
||||||
|
var lsvManualPeaks: Bool = false
|
||||||
var lsvTotal: UInt16 = 0
|
var lsvTotal: UInt16 = 0
|
||||||
var lsvStartV: String = "0"
|
var lsvStartV: String = "0"
|
||||||
var lsvStopV: String = "500"
|
var lsvStopV: String = "500"
|
||||||
|
|
@ -163,6 +165,9 @@ final class AppState {
|
||||||
|
|
||||||
case .lsvEnd:
|
case .lsvEnd:
|
||||||
saveLsv()
|
saveLsv()
|
||||||
|
if !lsvManualPeaks {
|
||||||
|
lsvPeaks = detectLsvPeaks(lsvPoints)
|
||||||
|
}
|
||||||
status = "LSV complete: \(lsvPoints.count) points"
|
status = "LSV complete: \(lsvPoints.count) points"
|
||||||
|
|
||||||
case .ampStart(let vHold):
|
case .ampStart(let vHold):
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ struct LSVView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
controlsRow
|
controlsRow
|
||||||
|
peakLabels
|
||||||
Divider()
|
Divider()
|
||||||
GeometryReader { geo in
|
GeometryReader { geo in
|
||||||
if geo.size.width > 700 {
|
if geo.size.width > 700 {
|
||||||
|
|
@ -42,6 +43,16 @@ struct LSVView: View {
|
||||||
|
|
||||||
Button("Start LSV") { state.startLSV() }
|
Button("Start LSV") { state.startLSV() }
|
||||||
.buttonStyle(ActionButtonStyle(color: .green))
|
.buttonStyle(ActionButtonStyle(color: .green))
|
||||||
|
|
||||||
|
Button(state.lsvManualPeaks ? "Manual" : "Auto") {
|
||||||
|
state.lsvManualPeaks.toggle()
|
||||||
|
if state.lsvManualPeaks {
|
||||||
|
state.lsvPeaks.removeAll()
|
||||||
|
} else {
|
||||||
|
state.lsvPeaks = detectLsvPeaks(state.lsvPoints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.font(.caption)
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
|
|
@ -86,6 +97,18 @@ struct LSVView: View {
|
||||||
.foregroundStyle(Color.yellow)
|
.foregroundStyle(Color.yellow)
|
||||||
.symbolSize(16)
|
.symbolSize(16)
|
||||||
}
|
}
|
||||||
|
ForEach(Array(state.lsvPeaks.enumerated()), id: \.offset) { _, peak in
|
||||||
|
PointMark(
|
||||||
|
x: .value("V", Double(peak.vMv)),
|
||||||
|
y: .value("I", Double(peak.iUa))
|
||||||
|
)
|
||||||
|
.foregroundStyle(peakColor(peak.kind))
|
||||||
|
.symbolSize(100)
|
||||||
|
.symbol(.diamond)
|
||||||
|
RuleMark(x: .value("V", Double(peak.vMv)))
|
||||||
|
.foregroundStyle(peakColor(peak.kind).opacity(0.3))
|
||||||
|
.lineStyle(StrokeStyle(lineWidth: 1, dash: [4, 4]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.chartXAxisLabel("V (mV)")
|
.chartXAxisLabel("V (mV)")
|
||||||
.chartYAxisLabel("I (uA)", position: .leading)
|
.chartYAxisLabel("I (uA)", position: .leading)
|
||||||
|
|
@ -115,6 +138,36 @@ struct LSVView: View {
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var peakLabels: some View {
|
||||||
|
if !state.lsvPeaks.isEmpty {
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
ForEach(Array(state.lsvPeaks.enumerated()), id: \.offset) { _, peak in
|
||||||
|
let label: String = {
|
||||||
|
switch peak.kind {
|
||||||
|
case .freeCl: return String(format: "Free: %.0fmV %.2fuA", peak.vMv, peak.iUa)
|
||||||
|
case .totalCl: return String(format: "Total: %.0fmV %.2fuA", peak.vMv, peak.iUa)
|
||||||
|
case .crossover: return String(format: "X-over: %.0fmV", peak.vMv)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
Text(label)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(peakColor(peak.kind))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 8)
|
||||||
|
.padding(.vertical, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func peakColor(_ kind: PeakKind) -> Color {
|
||||||
|
switch kind {
|
||||||
|
case .freeCl: .green
|
||||||
|
case .totalCl: .orange
|
||||||
|
case .crossover: .purple
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Table
|
// MARK: - Table
|
||||||
|
|
||||||
private var lsvTable: some View {
|
private var lsvTable: some View {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue