2 iOS: add LSV point density config, remove auto/manual toggle

This commit is contained in:
jess 2026-04-02 23:10:44 -07:00
parent 090fcfa2f5
commit 8de67ca66e
3 changed files with 38 additions and 16 deletions

View File

@ -1,6 +1,12 @@
import Foundation import Foundation
import Observation import Observation
enum LsvDensityMode: String, CaseIterable, Identifiable {
case ptsPerMv = "pts/mV"
case ptsPerSec = "pts/s"
var id: String { rawValue }
}
enum Tab: String, CaseIterable, Identifiable { enum Tab: String, CaseIterable, Identifiable {
case eis = "EIS" case eis = "EIS"
case lsv = "LSV" case lsv = "LSV"
@ -38,12 +44,13 @@ final class AppState {
// LSV // LSV
var lsvPoints: [LsvPoint] = [] var lsvPoints: [LsvPoint] = []
var lsvPeaks: [LsvPeak] = [] 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"
var lsvScanRate: String = "50" var lsvScanRate: String = "50"
var lsvRtia: LpRtia = .r10K var lsvRtia: LpRtia = .r10K
var lsvDensityMode: LsvDensityMode = .ptsPerMv
var lsvDensity: String = "1"
// Amperometry // Amperometry
var ampPoints: [AmpPoint] = [] var ampPoints: [AmpPoint] = []
@ -171,9 +178,7 @@ final class AppState {
case .lsvEnd: case .lsvEnd:
saveLsv() saveLsv()
if !lsvManualPeaks {
lsvPeaks = detectLsvPeaks(lsvPoints) lsvPeaks = detectLsvPeaks(lsvPoints)
}
var st = "LSV complete: \(lsvPoints.count) points" var st = "LSV complete: \(lsvPoints.count) points"
if let s = phSlope, let o = phOffset, abs(s) > 1e-6 { if let s = phSlope, let o = phOffset, abs(s) > 1e-6 {
if let peak = detectQhqPeak(lsvPoints) { if let peak = detectQhqPeak(lsvPoints) {
@ -300,13 +305,30 @@ final class AppState {
send(buildSysexStartSweep()) send(buildSysexStartSweep())
} }
func lsvCalcPoints() -> UInt16 {
let vs = Float(lsvStartV) ?? 0
let ve = Float(lsvStopV) ?? 500
let sr = Float(lsvScanRate) ?? 50
let d = Float(lsvDensity) ?? 1
let range = abs(ve - vs)
let raw: Float
switch lsvDensityMode {
case .ptsPerMv:
raw = range * d
case .ptsPerSec:
raw = abs(sr) < 0.001 ? 2 : (range / abs(sr)) * d
}
return max(2, min(500, UInt16(raw)))
}
func startLSV() { func startLSV() {
lsvPoints.removeAll() lsvPoints.removeAll()
let vs = Float(lsvStartV) ?? 0 let vs = Float(lsvStartV) ?? 0
let ve = Float(lsvStopV) ?? 500 let ve = Float(lsvStopV) ?? 500
let sr = Float(lsvScanRate) ?? 50 let sr = Float(lsvScanRate) ?? 50
let n = lsvCalcPoints()
send(buildSysexGetTemp()) send(buildSysexGetTemp())
send(buildSysexStartLsv(vStart: vs, vStop: ve, scanRate: sr, lpRtia: lsvRtia)) send(buildSysexStartLsv(vStart: vs, vStop: ve, scanRate: sr, lpRtia: lsvRtia, numPoints: n))
} }
func startAmp() { func startAmp() {

View File

@ -307,12 +307,13 @@ func buildSysexGetConfig() -> [UInt8] {
[0xF0, sysexMfr, CMD_GET_CONFIG, 0xF7] [0xF0, sysexMfr, CMD_GET_CONFIG, 0xF7]
} }
func buildSysexStartLsv(vStart: Float, vStop: Float, scanRate: Float, lpRtia: LpRtia) -> [UInt8] { func buildSysexStartLsv(vStart: Float, vStop: Float, scanRate: Float, lpRtia: LpRtia, numPoints: UInt16) -> [UInt8] {
var sx: [UInt8] = [0xF0, sysexMfr, CMD_START_LSV] var sx: [UInt8] = [0xF0, sysexMfr, CMD_START_LSV]
sx.append(contentsOf: encodeFloat(vStart)) sx.append(contentsOf: encodeFloat(vStart))
sx.append(contentsOf: encodeFloat(vStop)) sx.append(contentsOf: encodeFloat(vStop))
sx.append(contentsOf: encodeFloat(scanRate)) sx.append(contentsOf: encodeFloat(scanRate))
sx.append(lpRtia.rawValue) sx.append(lpRtia.rawValue)
sx.append(contentsOf: encodeU16(numPoints))
sx.append(0xF7) sx.append(0xF7)
return sx return sx
} }

View File

@ -41,18 +41,17 @@ struct LSVView: View {
LabeledPicker("RTIA", selection: $state.lsvRtia, items: LpRtia.allCases) { $0.label } LabeledPicker("RTIA", selection: $state.lsvRtia, items: LpRtia.allCases) { $0.label }
.frame(width: 120) .frame(width: 120)
LabeledPicker("Density", selection: $state.lsvDensityMode, items: LsvDensityMode.allCases) { $0.rawValue }
.frame(width: 100)
LabeledField("Value", text: $state.lsvDensity, width: 60)
Text("\(state.lsvCalcPoints()) pts")
.font(.caption)
.foregroundStyle(.secondary)
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)