first commit
This commit is contained in:
66
app/simulator.py
Normal file
66
app/simulator.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# simulator.py — Driveline & ECU-State
|
||||
from __future__ import annotations
|
||||
import threading
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class DrivelineModel:
|
||||
idle_rpm: int = 1400
|
||||
max_rpm: int = 9500
|
||||
kmh_per_krpm: tuple = (0.0, 12.0, 19.0, 25.0, 32.0, 38.0, 45.0)
|
||||
rpm_rise_per_s: int = 5000
|
||||
rpm_fall_per_s: int = 3500
|
||||
|
||||
def target_rpm_from_throttle(self, throttle_pct: int) -> int:
|
||||
t = max(0, min(100, throttle_pct)) / 100.0
|
||||
return int(self.idle_rpm + t * (self.max_rpm - self.idle_rpm))
|
||||
|
||||
def speed_from_rpm_gear(self, rpm: int, gear: int) -> float:
|
||||
if gear <= 0:
|
||||
return 0.0
|
||||
k = self.kmh_per_krpm[min(gear, len(self.kmh_per_krpm) - 1)]
|
||||
return (rpm / 1000.0) * k
|
||||
|
||||
class EcuState:
|
||||
"""Thread-sichere Zustandsmaschine (Gang, Gas, RPM, Speed)."""
|
||||
def __init__(self, model: DrivelineModel | None = None) -> None:
|
||||
self.model = model or DrivelineModel()
|
||||
self._lock = threading.Lock()
|
||||
self._gear = 0
|
||||
self._throttle = 0
|
||||
self._rpm = self.model.idle_rpm
|
||||
self._speed = 0.0
|
||||
self._last = time.monotonic()
|
||||
|
||||
def set_gear(self, gear: int) -> None:
|
||||
with self._lock:
|
||||
self._gear = max(0, min(6, int(gear)))
|
||||
|
||||
def set_throttle(self, thr: int) -> None:
|
||||
with self._lock:
|
||||
self._throttle = max(0, min(100, int(thr)))
|
||||
|
||||
def snapshot(self) -> tuple[int, int, int, float]:
|
||||
with self._lock:
|
||||
return self._gear, self._throttle, self._rpm, self._speed
|
||||
|
||||
def update(self) -> None:
|
||||
now = time.monotonic()
|
||||
dt = max(0.0, min(0.1, now - self._last))
|
||||
self._last = now
|
||||
with self._lock:
|
||||
target = self.model.target_rpm_from_throttle(self._throttle)
|
||||
if self._rpm < target:
|
||||
self._rpm = min(self._rpm + int(self.model.rpm_rise_per_s * dt), target)
|
||||
else:
|
||||
self._rpm = max(self._rpm - int(self.model.rpm_fall_per_s * dt), target)
|
||||
min_idle = 800 if self._gear == 0 and self._throttle == 0 else self.model.idle_rpm
|
||||
self._rpm = max(min_idle, min(self._rpm, self.model.max_rpm))
|
||||
|
||||
target_speed = self.model.speed_from_rpm_gear(self._rpm, self._gear)
|
||||
alpha = min(1.0, 4.0 * dt)
|
||||
if self._gear == 0:
|
||||
target_speed = 0.0
|
||||
self._speed = (1 - alpha) * self._speed + alpha * target_speed
|
||||
self._speed = max(0.0, min(self._speed, 299.0))
|
Reference in New Issue
Block a user