namespace ChromeboxFanControl; /// /// Fan curve: 14 control points at 0 °C and 40–100 °C every 5 °C, linear interpolation. /// public static class FanCurve { private const int PointCount = 14; /// Temperature breakpoints (°C): 0, 40, 45, 50, …, 100. public static readonly int[] TempBreakpoints = [0, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]; /// CPU temperature in °C. /// Exactly 14 values 0–100 (fan duty). public static byte CalculateFanPercent(double tempC, ReadOnlySpan curve) { if (curve.Length != PointCount) throw new ArgumentException($"Curve must contain exactly {PointCount} points.", nameof(curve)); var t = Math.Clamp(tempC, 0, 100); if (t <= TempBreakpoints[0]) return (byte)Math.Clamp(curve[0], 0, 100); if (t >= TempBreakpoints[PointCount - 1]) return (byte)Math.Clamp(curve[PointCount - 1], 0, 100); for (var i = 0; i < PointCount - 1; i++) { var t0 = TempBreakpoints[i]; var t1 = TempBreakpoints[i + 1]; if (t >= t0 && t <= t1) { var d0 = Math.Clamp(curve[i], 0, 100); var d1 = Math.Clamp(curve[i + 1], 0, 100); var frac = (t - t0) / (t1 - t0); return (byte)Math.Round(d0 + (d1 - d0) * frac); } } return (byte)Math.Clamp(curve[PointCount - 1], 0, 100); } }