| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- /// Rolling 5 km fuel economy calculated from MAF, speed and throttle.
- ///
- /// Petrol constants: stoichiometric AFR 14.7 and 745 g/L. This is deliberately
- /// an estimate; the dashboard presents it as a trend, not a measurement.
- class ObdEconomy {
- static const windowKm = 5.0;
- static const minimumKm = 0.5;
- static const _maxGap = Duration(seconds: 30);
- static const _afr = 14.7;
- static const _fuelDensityGramsPerLitre = 745.0;
- final List<_Segment> _segments = [];
- DateTime? _lastAt;
- double? _lastSpeedKmh;
- double? _lastMafGps;
- double? get litresPer100Km {
- if (_segments.isEmpty) return null;
- var km = 0.0;
- var litres = 0.0;
- for (final segment in _segments) {
- km += segment.km;
- litres += segment.litres;
- }
- if (km < minimumKm || km <= 0) return null;
- return (100 * litres / km).clamp(0.0, 99.9);
- }
- double get accumulatedKm {
- return _segments.fold(0, (total, segment) => total + segment.km);
- }
- void reset() {
- _segments.clear();
- _lastAt = null;
- _lastSpeedKmh = null;
- _lastMafGps = null;
- }
- void add({
- required DateTime at,
- required double? speedKmh,
- required double? mafGps,
- required double? throttlePercent,
- }) {
- final previousAt = _lastAt;
- _lastAt = at;
- if (speedKmh == null || mafGps == null) {
- _lastSpeedKmh = null;
- _lastMafGps = null;
- return;
- }
- if (previousAt == null ||
- _lastSpeedKmh == null ||
- _lastMafGps == null ||
- at.difference(previousAt) > _maxGap ||
- at.isBefore(previousAt)) {
- if (previousAt != null && at.difference(previousAt) > _maxGap) {
- reset();
- }
- _lastAt = at;
- _lastSpeedKmh = speedKmh;
- _lastMafGps = mafGps;
- return;
- }
- final deltaSeconds = at.difference(previousAt).inMilliseconds / 1000.0;
- if (deltaSeconds <= 0) return;
- final fuelCut =
- throttlePercent != null && throttlePercent < 1 && speedKmh > 10;
- final litresPerHour = fuelCut
- ? 0.0
- : (mafGps / _afr) * 3600 / _fuelDensityGramsPerLitre;
- final km = speedKmh * deltaSeconds / 3600;
- if (km > 0) {
- _segments.add(
- _Segment(km: km, litres: litresPerHour * deltaSeconds / 3600),
- );
- _trim();
- }
- _lastAt = at;
- _lastSpeedKmh = speedKmh;
- _lastMafGps = mafGps;
- }
- void _trim() {
- var km = accumulatedKm;
- while (km > windowKm && _segments.isNotEmpty) {
- km -= _segments.removeAt(0).km;
- }
- }
- }
- class _Segment {
- const _Segment({required this.km, required this.litres});
- final double km;
- final double litres;
- }
|