iOS: add pH calibration UI in Calibrate tab
This commit is contained in:
parent
818c4ff7a2
commit
1441c5ec42
|
|
@ -15,6 +15,7 @@ struct CalibrateView: View {
|
|||
resultsSection
|
||||
cellConstantSection
|
||||
chlorineCalSection
|
||||
phCalibrationSection
|
||||
}
|
||||
.navigationTitle("Calibrate")
|
||||
}
|
||||
|
|
@ -158,6 +159,80 @@ struct CalibrateView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - pH calibration
|
||||
|
||||
private var phCalibrationSection: some View {
|
||||
Section("pH Calibration (Q/HQ peak-shift)") {
|
||||
if let s = state.phSlope, let o = state.phOffset {
|
||||
Text(String(format: "slope: %.4f mV/pH offset: %.4f mV", s, o))
|
||||
if let peak = detectQhqPeak(state.lsvPoints) {
|
||||
if abs(s) > 1e-6 {
|
||||
let ph = (Double(peak) - o) / s
|
||||
Text(String(format: "Computed pH: %.2f (peak at %.1f mV)", ph, peak))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Known pH")
|
||||
Spacer()
|
||||
TextField("7.00", text: $state.phCalKnown)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.frame(width: 80)
|
||||
#if os(iOS)
|
||||
.keyboardType(.decimalPad)
|
||||
#endif
|
||||
}
|
||||
|
||||
Button("Add Calibration Point") {
|
||||
guard let peak = detectQhqPeak(state.lsvPoints) else {
|
||||
state.status = "No Q/HQ peak found in LSV data"
|
||||
return
|
||||
}
|
||||
guard let ph = Double(state.phCalKnown) else { return }
|
||||
state.phCalPoints.append((ph: ph, mV: Double(peak)))
|
||||
state.status = String(format: "pH cal point: pH=%.2f peak=%.1f mV (%d pts)",
|
||||
ph, peak, state.phCalPoints.count)
|
||||
}
|
||||
.disabled(state.lsvPoints.isEmpty)
|
||||
|
||||
ForEach(Array(state.phCalPoints.enumerated()), id: \.offset) { i, pt in
|
||||
Text(String(format: "%d. pH=%.2f peak=%.1f mV", i + 1, pt.ph, pt.mV))
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
Button("Clear Points") {
|
||||
state.phCalPoints.removeAll()
|
||||
state.status = "pH cal points cleared"
|
||||
}
|
||||
.disabled(state.phCalPoints.isEmpty)
|
||||
|
||||
Button("Compute & Set pH Cal") {
|
||||
let pts = state.phCalPoints
|
||||
guard pts.count >= 2 else {
|
||||
state.status = "Need at least 2 calibration points"
|
||||
return
|
||||
}
|
||||
let n = Double(pts.count)
|
||||
let meanPh = pts.map(\.ph).reduce(0, +) / n
|
||||
let meanV = pts.map(\.mV).reduce(0, +) / n
|
||||
let num = pts.map { ($0.ph - meanPh) * ($0.mV - meanV) }.reduce(0, +)
|
||||
let den = pts.map { ($0.ph - meanPh) * ($0.ph - meanPh) }.reduce(0, +)
|
||||
guard abs(den) > 1e-12 else {
|
||||
state.status = "Degenerate calibration data"
|
||||
return
|
||||
}
|
||||
let slope = num / den
|
||||
let offset = meanV - slope * meanPh
|
||||
state.phSlope = slope
|
||||
state.phOffset = offset
|
||||
state.send(buildSysexSetPhCal(Float(slope), Float(offset)))
|
||||
state.status = String(format: "pH cal set: slope=%.4f offset=%.4f", slope, offset)
|
||||
}
|
||||
.disabled(state.phCalPoints.count < 2)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Calculations
|
||||
|
||||
private func saltGrams(volumeGal: Double, ppm: Double) -> Double {
|
||||
|
|
|
|||
Loading…
Reference in New Issue