using System; using System.Collections.Generic; using System.Globalization; namespace HC_APTBS.Models { /// /// Maps a motor RPM setpoint to the corresponding analogue control voltage /// required to drive the bench motor to that speed. /// /// /// The lookup table is ordered by ascending RPM. /// performs a linear scan and returns the voltage of the last entry whose /// RPM is ≤ the requested value (step interpolation). /// /// public class RpmVoltageRelation { /// Analogue voltage to apply to the motor controller (V). public double Voltage { get; set; } /// Target motor speed (RPM). public int Rpm { get; set; } /// Motor control voltage (V). /// Corresponding motor speed (RPM). public RpmVoltageRelation(double voltage, int rpm) { Voltage = voltage; Rpm = rpm; } // ── Lookup ──────────────────────────────────────────────────────────────── /// /// Returns the control voltage for the given /// by scanning the ordered for the closest lower entry. /// Returns 0 if the table is empty or no lower entry is found. /// /// Requested motor speed in RPM. /// Ordered (ascending RPM) lookup table. public static double VoltageForRpm(int targetRpm, IReadOnlyList table) { double previousVoltage = -1; foreach (var entry in table) { if (entry.Rpm == targetRpm) return entry.Voltage; if (targetRpm < entry.Rpm) return previousVoltage < 0 ? 0 : previousVoltage; previousVoltage = entry.Voltage; } return 0; } // ── Serialisation ───────────────────────────────────────────────────────── /// /// Serialises a list of relations to the compact pipe-separated storage format /// used in config.xml: RPM|Voltage;RPM|Voltage;… /// public static string Serialise(IReadOnlyList relations) { if (relations == null || relations.Count == 0) return string.Empty; var parts = new List(relations.Count); foreach (var r in relations) parts.Add($"{r.Rpm}|{r.Voltage.ToString(CultureInfo.InvariantCulture)}"); return string.Join(";", parts); } /// /// Deserialises a list of relations from the compact storage format. /// public static List Deserialise(string serialised) { var result = new List(); if (string.IsNullOrWhiteSpace(serialised)) return result; foreach (var part in serialised.Split(';')) { var tokens = part.Split('|'); if (tokens.Length != 2) continue; if (!int.TryParse(tokens[0], out int rpm)) continue; if (!double.TryParse(tokens[1], NumberStyles.Float, CultureInfo.InvariantCulture, out double voltage)) continue; result.Add(new RpmVoltageRelation(voltage, rpm)); } return result; } } }