engine tweaks
This commit is contained in:
@@ -1,162 +1,118 @@
|
|||||||
# =============================
|
# =============================
|
||||||
# app/simulation/modules/engine.py
|
# app/simulation/modules/engine.py
|
||||||
# =============================
|
# =============================
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from app.simulation.simulator import Module, Vehicle
|
from app.simulation.simulator import Module, Vehicle
|
||||||
import math, random
|
import math, random
|
||||||
|
|
||||||
ENGINE_DEFAULTS = {
|
ENGINE_DEFAULTS = {
|
||||||
# Basis
|
|
||||||
"idle_rpm": 1200,
|
"idle_rpm": 1200,
|
||||||
|
"idle_rpm": 800, # normaler Idle
|
||||||
|
"cold_idle_rpm": 1050, # Kaltlauf-Idle
|
||||||
|
"cold_idle_end_c": 40.0, # bis zu dieser Kühlmitteltemp gilt cold_idle
|
||||||
|
"idle_cold_mode": "two_point", # "two_point" | "slope"
|
||||||
"max_rpm": 9000,
|
"max_rpm": 9000,
|
||||||
"rpm_rise_per_s": 4000,
|
"rpm_rise_per_s": 4000,
|
||||||
"rpm_fall_per_s": 3000,
|
"rpm_fall_per_s": 3000,
|
||||||
"throttle_curve": "linear",
|
"throttle_curve": "linear",
|
||||||
|
|
||||||
# Starter / Startlogik
|
|
||||||
"starter_rpm_nominal": 250.0,
|
"starter_rpm_nominal": 250.0,
|
||||||
"starter_voltage_min": 10.5,
|
"starter_voltage_min": 10.5,
|
||||||
"start_rpm_threshold": 210.0,
|
"start_rpm_threshold": 210.0,
|
||||||
"stall_rpm": 500.0,
|
"stall_rpm": 500.0,
|
||||||
|
|
||||||
# Thermische Einflüsse (nur fürs Derating/Viskosität benutzt)
|
|
||||||
"coolant_ambient_c": 20.0,
|
"coolant_ambient_c": 20.0,
|
||||||
"idle_cold_gain_per_deg": 3.0,
|
"idle_cold_gain_per_deg": 3.0,
|
||||||
"idle_cold_gain_max": 500.0,
|
"idle_cold_gain_max": 500.0,
|
||||||
|
|
||||||
# Öl / Öldruck
|
|
||||||
"oil_pressure_idle_bar": 1.2,
|
"oil_pressure_idle_bar": 1.2,
|
||||||
"oil_pressure_slope_bar_per_krpm": 0.8,
|
"oil_pressure_slope_bar_per_krpm": 0.8,
|
||||||
"oil_pressure_off_floor_bar": 0.2,
|
"oil_pressure_off_floor_bar": 0.2,
|
||||||
|
|
||||||
# Leistungsdaten
|
|
||||||
"engine_power_kw": 60.0,
|
"engine_power_kw": 60.0,
|
||||||
"torque_peak_rpm": 7000.0,
|
"torque_peak_rpm": 7000.0,
|
||||||
|
|
||||||
# Drive-by-wire / Regler
|
|
||||||
"throttle_plate_idle_min_pct": 6.0,
|
"throttle_plate_idle_min_pct": 6.0,
|
||||||
"throttle_plate_overrun_pct": 2.0,
|
"throttle_plate_overrun_pct": 2.0,
|
||||||
"throttle_plate_tau_s": 0.08,
|
"throttle_plate_tau_s": 0.08,
|
||||||
"torque_ctrl_kp": 1.2,
|
"torque_ctrl_kp": 1.2,
|
||||||
"torque_ctrl_ki": 0.6,
|
"torque_ctrl_ki": 0.6,
|
||||||
|
|
||||||
# RPM-Jitter
|
|
||||||
"rpm_jitter_idle_amp_rpm": 12.0,
|
"rpm_jitter_idle_amp_rpm": 12.0,
|
||||||
"rpm_jitter_high_amp_rpm": 4.0,
|
"rpm_jitter_high_amp_rpm": 4.0,
|
||||||
"rpm_jitter_tau_s": 0.20,
|
"rpm_jitter_tau_s": 0.20,
|
||||||
"rpm_jitter_off_threshold_rpm": 250.0,
|
"rpm_jitter_off_threshold_rpm": 250.0,
|
||||||
|
|
||||||
# UI
|
|
||||||
"throttle_pedal_pct": 0.0,
|
"throttle_pedal_pct": 0.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
class EngineModule(Module):
|
class EngineModule(Module):
|
||||||
PRIO = 20
|
PRIO = 20
|
||||||
NAME = "engine"
|
NAME = "engine"
|
||||||
"""
|
|
||||||
Erweiterte Motormodellierung mit realistischem Jitter & Drive-by-Wire:
|
|
||||||
- OFF/ACC/ON/START Logik, Starten/Abwürgen
|
|
||||||
- Thermik (Kühlmittel/Öl), Öldruck ~ f(RPM)
|
|
||||||
- Startverhalten abhängig von Spannung & Öltemp
|
|
||||||
- Leistungsmodell via engine_power_kw + torque_peak_rpm
|
|
||||||
- Fahrerwunsch: throttle_pedal_pct (0..100) → Ziel-Leistungsanteil
|
|
||||||
* Drosselklappe (throttle_plate_pct) wird per PI-Regler geführt
|
|
||||||
* Mindestöffnung im Leerlauf, fast zu im Schubbetrieb
|
|
||||||
- Realistischer RPM-Jitter:
|
|
||||||
* bandbegrenztes Rauschen (1. Ordnung) mit Amplitude ~ f(RPM)
|
|
||||||
* kein Jitter unter einer Schwell-RPM oder wenn Motor aus
|
|
||||||
Outputs:
|
|
||||||
rpm, coolant_temp, oil_temp, oil_pressure
|
|
||||||
engine_available_torque_nm, engine_net_torque_nm
|
|
||||||
throttle_plate_pct (neu), throttle_pedal_pct (durchgereicht)
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._running = False
|
self._running = False
|
||||||
self._oil_p_tau = 0.25 # Zeitkonstante Öldruck
|
self._oil_p_tau = 0.25
|
||||||
# DBW intern
|
|
||||||
self._plate_pct = 5.0
|
self._plate_pct = 5.0
|
||||||
self._tc_i = 0.0
|
self._tc_i = 0.0
|
||||||
# AR(1)-Noise
|
|
||||||
self._rpm_noise = 0.0
|
self._rpm_noise = 0.0
|
||||||
|
# NEU: Gnadenfrist nach dem Anspringen
|
||||||
|
self._post_start_s = 0.0
|
||||||
|
|
||||||
# ---- helpers ----------------------------------------------------------
|
# -- helpers (unverändert) --
|
||||||
def _curve(self, t: float, mode: str) -> float:
|
def _curve(self, t: float, mode: str) -> float:
|
||||||
if mode == "progressive": return t**1.5
|
if mode == "progressive": return t**1.5
|
||||||
if mode == "aggressive": return t**0.7
|
if mode == "aggressive": return t**0.7
|
||||||
return t
|
return t
|
||||||
|
def _tmax_at_rpm(self, power_kw: float, rpm: float, peak_rpm: float) -> float:
|
||||||
def _torque_at_rpm(self, power_kw: float, rpm: float, peak_rpm: float) -> float:
|
|
||||||
rpm = max(0.0, rpm)
|
rpm = max(0.0, rpm)
|
||||||
t_max = (9550.0 * max(0.0, power_kw)) / max(500.0, peak_rpm)
|
t_peak = (9550.0 * max(0.0, power_kw)) / max(500.0, peak_rpm)
|
||||||
x = min(math.pi, max(0.0, (rpm / max(1.0, peak_rpm)) * (math.pi/2)))
|
x = min(math.pi, max(0.0, (rpm / max(1.0, peak_rpm)) * (math.pi/2)))
|
||||||
return max(0.0, t_max * math.sin(x))
|
return max(0.0, t_peak * math.sin(x))
|
||||||
|
|
||||||
def _plate_airflow_factor(self, plate_pct: float) -> float:
|
def _plate_airflow_factor(self, plate_pct: float) -> float:
|
||||||
theta = max(0.0, min(90.0, (plate_pct/100.0)*90.0)) * math.pi/180.0
|
theta = max(0.0, min(90.0, (plate_pct/100.0)*90.0)) * math.pi/180.0
|
||||||
return math.sin(theta)**2
|
return math.sin(theta)**2
|
||||||
|
|
||||||
def _visco(self, temp_c: float) -> float:
|
def _visco(self, temp_c: float) -> float:
|
||||||
# -10°C -> 0.6 … 20°C -> 0.8 … 90°C -> 1.0
|
|
||||||
if temp_c <= -10: return 0.6
|
if temp_c <= -10: return 0.6
|
||||||
if temp_c >= 90: return 1.0
|
if temp_c >= 90: return 1.0
|
||||||
if temp_c <= 20: return 0.6 + (temp_c + 10.0) * (0.2/30.0)
|
if temp_c <= 20: return 0.6 + (temp_c + 10.0) * (0.2/30.0)
|
||||||
return 0.8 + (temp_c - 20.0) * (0.2/70.0)
|
return 0.8 + (temp_c - 20.0) * (0.2/70.0)
|
||||||
|
|
||||||
# ---- main -------------------------------------------------------------
|
|
||||||
def apply(self, v: Vehicle, dt: float) -> None:
|
def apply(self, v: Vehicle, dt: float) -> None:
|
||||||
e = v.config.setdefault("engine", {})
|
e = v.config.setdefault("engine", {})
|
||||||
|
# --- Config (wie gehabt) ---
|
||||||
# --- Config ---
|
idle=float(e.get("idle_rpm", ENGINE_DEFAULTS["idle_rpm"])); maxr=float(e.get("max_rpm", ENGINE_DEFAULTS["max_rpm"]))
|
||||||
idle = float(e.get("idle_rpm", ENGINE_DEFAULTS["idle_rpm"]))
|
rise=float(e.get("rpm_rise_per_s", ENGINE_DEFAULTS["rpm_rise_per_s"])); fall=float(e.get("rpm_fall_per_s", ENGINE_DEFAULTS["rpm_fall_per_s"]))
|
||||||
maxr = float(e.get("max_rpm", ENGINE_DEFAULTS["max_rpm"]))
|
thr_curve=e.get("throttle_curve", ENGINE_DEFAULTS["throttle_curve"])
|
||||||
rise = float(e.get("rpm_rise_per_s", ENGINE_DEFAULTS["rpm_rise_per_s"]))
|
ambient=float(e.get("coolant_ambient_c", ENGINE_DEFAULTS["coolant_ambient_c"]))
|
||||||
fall = float(e.get("rpm_fall_per_s", ENGINE_DEFAULTS["rpm_fall_per_s"]))
|
cold_gain_per_deg=float(e.get("idle_cold_gain_per_deg", ENGINE_DEFAULTS["idle_cold_gain_per_deg"]))
|
||||||
thr_curve = e.get("throttle_curve", ENGINE_DEFAULTS["throttle_curve"])
|
cold_gain_max=float(e.get("idle_cold_gain_max", ENGINE_DEFAULTS["idle_cold_gain_max"]))
|
||||||
|
starter_nom=float(e.get("starter_rpm_nominal", ENGINE_DEFAULTS["starter_rpm_nominal"]))
|
||||||
ambient = float(e.get("coolant_ambient_c", ENGINE_DEFAULTS["coolant_ambient_c"]))
|
starter_vmin=float(e.get("starter_voltage_min", ENGINE_DEFAULTS["starter_voltage_min"]))
|
||||||
cold_gain_per_deg = float(e.get("idle_cold_gain_per_deg", ENGINE_DEFAULTS["idle_cold_gain_per_deg"]))
|
start_rpm_th=float(e.get("start_rpm_threshold", ENGINE_DEFAULTS["start_rpm_threshold"]))
|
||||||
cold_gain_max = float(e.get("idle_cold_gain_max", ENGINE_DEFAULTS["idle_cold_gain_max"]))
|
stall_rpm=float(e.get("stall_rpm", ENGINE_DEFAULTS["stall_rpm"]))
|
||||||
|
power_kw=float(e.get("engine_power_kw", ENGINE_DEFAULTS["engine_power_kw"]))
|
||||||
starter_nom = float(e.get("starter_rpm_nominal", ENGINE_DEFAULTS["starter_rpm_nominal"]))
|
peak_torque_rpm=float(e.get("torque_peak_rpm", ENGINE_DEFAULTS["torque_peak_rpm"]))
|
||||||
starter_vmin= float(e.get("starter_voltage_min", ENGINE_DEFAULTS["starter_voltage_min"]))
|
oil_idle_bar=float(e.get("oil_pressure_idle_bar", ENGINE_DEFAULTS["oil_pressure_idle_bar"]))
|
||||||
start_rpm_th= float(e.get("start_rpm_threshold", ENGINE_DEFAULTS["start_rpm_threshold"]))
|
oil_slope_bar_per_krpm=float(e.get("oil_pressure_slope_bar_per_krpm", ENGINE_DEFAULTS["oil_pressure_slope_bar_per_krpm"]))
|
||||||
stall_rpm = float(e.get("stall_rpm", ENGINE_DEFAULTS["stall_rpm"]))
|
oil_floor_off=float(e.get("oil_pressure_off_floor_bar", ENGINE_DEFAULTS["oil_pressure_off_floor_bar"]))
|
||||||
|
plate_idle_min=float(e.get("throttle_plate_idle_min_pct", ENGINE_DEFAULTS["throttle_plate_idle_min_pct"]))
|
||||||
power_kw = float(e.get("engine_power_kw", ENGINE_DEFAULTS["engine_power_kw"]))
|
plate_overrun=float(e.get("throttle_plate_overrun_pct", ENGINE_DEFAULTS["throttle_plate_overrun_pct"]))
|
||||||
peak_torque_rpm = float(e.get("torque_peak_rpm", ENGINE_DEFAULTS["torque_peak_rpm"]))
|
plate_tau=float(e.get("throttle_plate_tau_s", ENGINE_DEFAULTS["throttle_plate_tau_s"]))
|
||||||
|
torque_kp=float(e.get("torque_ctrl_kp", ENGINE_DEFAULTS["torque_ctrl_kp"]))
|
||||||
oil_idle_bar = float(e.get("oil_pressure_idle_bar", ENGINE_DEFAULTS["oil_pressure_idle_bar"]))
|
torque_ki=float(e.get("torque_ctrl_ki", ENGINE_DEFAULTS["torque_ctrl_ki"]))
|
||||||
oil_slope_bar_per_krpm = float(e.get("oil_pressure_slope_bar_per_krpm", ENGINE_DEFAULTS["oil_pressure_slope_bar_per_krpm"]))
|
jitter_idle_amp=float(e.get("rpm_jitter_idle_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_idle_amp_rpm"]))
|
||||||
oil_floor_off = float(e.get("oil_pressure_off_floor_bar", ENGINE_DEFAULTS["oil_pressure_off_floor_bar"]))
|
jitter_hi_amp=float(e.get("rpm_jitter_high_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_high_amp_rpm"]))
|
||||||
|
jitter_tau=float(e.get("rpm_jitter_tau_s", ENGINE_DEFAULTS["rpm_jitter_tau_s"]))
|
||||||
plate_idle_min = float(e.get("throttle_plate_idle_min_pct", ENGINE_DEFAULTS["throttle_plate_idle_min_pct"]))
|
jitter_off_rpm=float(e.get("rpm_jitter_off_threshold_rpm", ENGINE_DEFAULTS["rpm_jitter_off_threshold_rpm"]))
|
||||||
plate_overrun = float(e.get("throttle_plate_overrun_pct", ENGINE_DEFAULTS["throttle_plate_overrun_pct"]))
|
|
||||||
plate_tau = float(e.get("throttle_plate_tau_s", ENGINE_DEFAULTS["throttle_plate_tau_s"]))
|
|
||||||
torque_kp = float(e.get("torque_ctrl_kp", ENGINE_DEFAULTS["torque_ctrl_kp"]))
|
|
||||||
torque_ki = float(e.get("torque_ctrl_ki", ENGINE_DEFAULTS["torque_ctrl_ki"]))
|
|
||||||
|
|
||||||
jitter_idle_amp= float(e.get("rpm_jitter_idle_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_idle_amp_rpm"]))
|
|
||||||
jitter_hi_amp = float(e.get("rpm_jitter_high_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_high_amp_rpm"]))
|
|
||||||
jitter_tau = float(e.get("rpm_jitter_tau_s", ENGINE_DEFAULTS["rpm_jitter_tau_s"]))
|
|
||||||
jitter_off_rpm = float(e.get("rpm_jitter_off_threshold_rpm", ENGINE_DEFAULTS["rpm_jitter_off_threshold_rpm"]))
|
|
||||||
|
|
||||||
# --- State ---
|
# --- State ---
|
||||||
rpm = float(v.ensure("rpm", 0.0))
|
rpm=float(v.ensure("rpm", 0.0))
|
||||||
pedal = float(v.ensure("throttle_pedal_pct", float(e.get("throttle_pedal_pct", 0.0))))
|
pedal=float(v.ensure("throttle_pedal_pct", float(e.get("throttle_pedal_pct", 0.0))))
|
||||||
pedal = max(0.0, min(100.0, pedal))
|
pedal=max(0.0, min(100.0, pedal))
|
||||||
ign = str(v.ensure("ignition", "OFF"))
|
ign=str(v.ensure("ignition", "OFF"))
|
||||||
elx_v = float(v.ensure("elx_voltage", 0.0))
|
elx_v=float(v.ensure("elx_voltage", 0.0))
|
||||||
cool = float(v.ensure("coolant_temp", ambient)) # nur lesen
|
cool=float(v.ensure("coolant_temp", ambient))
|
||||||
oil = float(v.ensure("oil_temp", ambient)) # nur lesen
|
oil=float(v.ensure("oil_temp", ambient))
|
||||||
oil_p = float(v.ensure("oil_pressure", 0.0))
|
oil_p=float(v.ensure("oil_pressure", 0.0))
|
||||||
|
|
||||||
# externe Momente (Alternator/Getriebe/…)
|
torque_load=max(0.0, v.acc_total("engine.torque_load_nm"))
|
||||||
torque_load = max(0.0, v.acc_total("engine.torque_load_nm"))
|
torque_load=max(torque_load, float(v.get("engine_ext_torque_nm", 0.0)))
|
||||||
torque_load = max(torque_load, float(v.get("engine_ext_torque_nm", 0.0))) # legacy fallback
|
|
||||||
|
|
||||||
# Dashboard-Metriken
|
# Dashboard (wie gehabt)
|
||||||
v.register_metric("rpm", unit="RPM", fmt=".1f", label="Drehzahl", source="engine", priority=20)
|
v.register_metric("rpm", unit="RPM", fmt=".1f", label="Drehzahl", source="engine", priority=20)
|
||||||
v.register_metric("oil_pressure", unit="bar", fmt=".2f", label="Öldruck", source="engine", priority=42)
|
v.register_metric("oil_pressure", unit="bar", fmt=".2f", label="Öldruck", source="engine", priority=42)
|
||||||
v.register_metric("engine_available_torque_nm", unit="Nm", fmt=".0f", label="Verfügbares Motormoment", source="engine", priority=43)
|
v.register_metric("engine_available_torque_nm", unit="Nm", fmt=".0f", label="Verfügbares Motormoment", source="engine", priority=43)
|
||||||
@@ -165,104 +121,118 @@ class EngineModule(Module):
|
|||||||
v.register_metric("throttle_pedal_pct", unit="%", fmt=".0f", label="Gaspedal", source="engine", priority=46)
|
v.register_metric("throttle_pedal_pct", unit="%", fmt=".0f", label="Gaspedal", source="engine", priority=46)
|
||||||
v.register_metric("throttle_plate_pct", unit="%", fmt=".0f", label="Drosselklappe", source="engine", priority=47)
|
v.register_metric("throttle_plate_pct", unit="%", fmt=".0f", label="Drosselklappe", source="engine", priority=47)
|
||||||
|
|
||||||
# --- Start-/Ziel-RPM Logik ---
|
# --- Startlogik + Post-Start-Grace ---
|
||||||
# Starter-Viskositätseinfluss
|
|
||||||
vfac = 0.0 if elx_v <= starter_vmin else min(1.2, (elx_v - starter_vmin) / max(0.3, (12.6 - starter_vmin)))
|
vfac = 0.0 if elx_v <= starter_vmin else min(1.2, (elx_v - starter_vmin) / max(0.3, (12.6 - starter_vmin)))
|
||||||
crank_rpm = starter_nom * vfac * self._visco(oil)
|
crank_rpm = starter_nom * vfac * self._visco(oil)
|
||||||
|
start_rpm_min=0.15*idle; start_rpm_max=0.45*idle
|
||||||
# effektive Startschwelle (15..45% Idle)
|
|
||||||
start_rpm_min = 0.15 * idle
|
|
||||||
start_rpm_max = 0.45 * idle
|
|
||||||
start_rpm_th_eff = max(start_rpm_min, min(start_rpm_th, start_rpm_max))
|
start_rpm_th_eff = max(start_rpm_min, min(start_rpm_th, start_rpm_max))
|
||||||
|
|
||||||
if ign in ("OFF", "ACC"):
|
if ign in ("OFF","ACC"):
|
||||||
self._running = False
|
self._running = False
|
||||||
target_rpm = 0.0
|
self._post_start_s = 0.0
|
||||||
elif ign == "START":
|
elif ign == "START":
|
||||||
target_rpm = crank_rpm
|
# wenn Schwelle erreicht: Motor gilt als angesprungen + Gnadenfrist
|
||||||
if not self._running and target_rpm >= start_rpm_th_eff and elx_v > starter_vmin:
|
if not self._running and crank_rpm >= start_rpm_th_eff and elx_v > starter_vmin:
|
||||||
self._running = True
|
self._running = True
|
||||||
|
self._post_start_s = 1.2
|
||||||
|
rpm = max(rpm, crank_rpm) # Starter dreht mit
|
||||||
else: # ON
|
else: # ON
|
||||||
if not self._running and rpm >= max(0.15*idle, start_rpm_th_eff*0.9):
|
if not self._running and rpm >= max(0.15*idle, start_rpm_th_eff*0.9):
|
||||||
self._running = True
|
self._running = True
|
||||||
if self._running:
|
self._post_start_s = 1.0
|
||||||
cold_add = max(0.0, min(ENGINE_DEFAULTS["idle_cold_gain_max"],
|
|
||||||
(90.0 - cool) * cold_gain_per_deg))
|
if self._running and self._post_start_s > 0.0:
|
||||||
idle_eff = idle + cold_add
|
self._post_start_s = max(0.0, self._post_start_s - dt)
|
||||||
target_rpm = max(idle_eff, min(maxr, rpm))
|
|
||||||
|
# --- Drehmomentmodell ---
|
||||||
|
tmax_rpm = self._tmax_at_rpm(power_kw, max(1.0, rpm), peak_torque_rpm)
|
||||||
|
|
||||||
|
cold_add = max(0.0, min(ENGINE_DEFAULTS["idle_cold_gain_max"], (90.0 - cool) * cold_gain_per_deg))
|
||||||
|
mode = str(e.get("idle_cold_mode", ENGINE_DEFAULTS["idle_cold_mode"])).lower()
|
||||||
|
cold_idle = float(e.get("cold_idle_rpm", ENGINE_DEFAULTS["cold_idle_rpm"]))
|
||||||
|
cold_end = float(e.get("cold_idle_end_c", ENGINE_DEFAULTS["cold_idle_end_c"]))
|
||||||
|
|
||||||
|
if mode == "two_point":
|
||||||
|
idle_eff = cold_idle if cool < cold_end else idle
|
||||||
else:
|
else:
|
||||||
target_rpm = 0.0
|
# Fallback: alte dynamische Rampe
|
||||||
|
cold_add = max(0.0, min(ENGINE_DEFAULTS["idle_cold_gain_max"],
|
||||||
|
(90.0 - cool) * float(e.get("idle_cold_gain_per_deg",
|
||||||
|
ENGINE_DEFAULTS["idle_cold_gain_per_deg"]))))
|
||||||
|
idle_eff = idle + cold_add
|
||||||
|
|
||||||
# --- Basis-Moment & Derating ---
|
rpm_err = max(0.0, idle_eff - rpm)
|
||||||
base_torque = self._torque_at_rpm(power_kw, max(1.0, rpm), peak_torque_rpm)
|
t_idle_cap = 0.35 * max(5.0, self._tmax_at_rpm(power_kw, max(500.0, idle_eff), peak_torque_rpm))
|
||||||
temp_derate = max(0.7, 1.0 - max(0.0, (oil - 110.0)) * 0.005)
|
t_idle_req = t_idle_cap * min(1.0, rpm_err / max(50.0, 0.2*idle_eff))
|
||||||
|
|
||||||
# --- DBW (PI auf Torque-Anteil) ---
|
|
||||||
demand = self._curve(pedal/100.0, thr_curve)
|
demand = self._curve(pedal/100.0, thr_curve)
|
||||||
plate_target_min = plate_overrun if demand < 0.02 else plate_idle_min
|
t_driver_req = demand * tmax_rpm
|
||||||
|
|
||||||
airflow = self._plate_airflow_factor(self._plate_pct)
|
# WICHTIG: Momentfreigabe auch in START, wenn _running bereits True
|
||||||
torque_avail = base_torque * airflow * temp_derate
|
running_mode = self._running and (ign in ("ON","START"))
|
||||||
torque_frac = 0.0 if base_torque <= 1e-6 else (torque_avail / (base_torque * temp_derate))
|
t_target = (max(t_idle_req, t_driver_req) if running_mode else 0.0)
|
||||||
err = max(0.0, demand) - max(0.0, min(1.0, torque_frac))
|
|
||||||
|
|
||||||
if ign == "ON" and self._running:
|
temp_derate = max(0.6, 1.0 - max(0.0, (oil - 120.0)) * 0.006)
|
||||||
|
|
||||||
|
norm_target = 0.0 if tmax_rpm <= 1e-6 else max(0.0, min(1.0, t_target / (tmax_rpm * temp_derate)))
|
||||||
|
norm_avail = self._plate_airflow_factor(self._plate_pct)
|
||||||
|
err = norm_target - norm_avail
|
||||||
|
|
||||||
|
if running_mode:
|
||||||
self._tc_i += err * torque_ki * dt
|
self._tc_i += err * torque_ki * dt
|
||||||
else:
|
else:
|
||||||
self._tc_i *= 0.95
|
self._tc_i *= 0.9
|
||||||
|
|
||||||
plate_cmd = self._plate_pct + (torque_kp * err + self._tc_i) * 100.0
|
plate_cmd = self._plate_pct + (torque_kp * err + self._tc_i) * 100.0
|
||||||
plate_cmd = max(plate_target_min, min(100.0, plate_cmd))
|
plate_min = plate_overrun if (demand < 0.02 and rpm > idle_eff + 200.0) else plate_idle_min
|
||||||
|
plate_cmd = max(plate_min, min(100.0, plate_cmd))
|
||||||
a_tau = min(1.0, dt / max(1e-3, plate_tau))
|
a_tau = min(1.0, dt / max(1e-3, plate_tau))
|
||||||
self._plate_pct = (1.0 - a_tau) * self._plate_pct + a_tau * plate_cmd
|
self._plate_pct = (1.0 - a_tau) * self._plate_pct + a_tau * plate_cmd
|
||||||
|
|
||||||
# aktualisiertes Moment
|
|
||||||
airflow = self._plate_airflow_factor(self._plate_pct)
|
airflow = self._plate_airflow_factor(self._plate_pct)
|
||||||
avail_torque = base_torque * airflow * temp_derate
|
avail_torque = tmax_rpm * airflow * temp_derate
|
||||||
net_torque = max(0.0, avail_torque - max(0.0, torque_load))
|
net_torque = max(0.0, avail_torque - max(0.0, torque_load))
|
||||||
|
|
||||||
# --- Wärmeleistung pushen (W) ---
|
# Wärme (wie gehabt)
|
||||||
# mechanische Leistung:
|
|
||||||
mech_power_w = net_torque * (2.0 * math.pi * rpm / 60.0)
|
mech_power_w = net_torque * (2.0 * math.pi * rpm / 60.0)
|
||||||
# grober Wirkungsgrad (0.24..0.34 je nach Pedal/Kennlinie)
|
eta = 0.24 + 0.10 * demand
|
||||||
eta = 0.24 + 0.10 * self._curve(pedal/100.0, thr_curve)
|
|
||||||
eta = max(0.05, min(0.45, eta))
|
eta = max(0.05, min(0.45, eta))
|
||||||
fuel_power_w = mech_power_w / max(1e-3, eta)
|
fuel_power_w = mech_power_w / max(1e-3, eta)
|
||||||
heat_w = max(0.0, fuel_power_w - mech_power_w)
|
heat_w = max(0.0, fuel_power_w - mech_power_w)
|
||||||
# Idle-Basiswärme, damit im Leerlauf nicht auskühlt:
|
|
||||||
idle_heat_w = 1500.0 * (rpm / max(1.0, idle))
|
idle_heat_w = 1500.0 * (rpm / max(1.0, idle))
|
||||||
heat_w = max(heat_w, idle_heat_w)
|
heat_w = max(heat_w, idle_heat_w)
|
||||||
v.push("thermal.heat_w", +heat_w, source="engine")
|
v.push("thermal.heat_w", +heat_w, source="engine")
|
||||||
|
|
||||||
# --- Ziel-RPM aus Netto-Moment ---
|
# RPM-Dynamik
|
||||||
if ign == "ON" and self._running:
|
if running_mode:
|
||||||
cold_add = max(0.0, min(ENGINE_DEFAULTS["idle_cold_gain_max"],
|
torque_norm = 0.0 if tmax_rpm <= 1e-6 else max(0.0, min(1.0, net_torque / tmax_rpm))
|
||||||
(90.0 - cool) * cold_gain_per_deg))
|
free_target = idle_eff + torque_norm * (maxr - idle_eff)
|
||||||
idle_eff = idle + cold_add
|
if rpm < free_target:
|
||||||
denom = (base_torque * temp_derate + 1e-6)
|
rpm = min(free_target, rpm + rise * max(0.2, torque_norm) * dt)
|
||||||
torque_norm = 0.0 if denom <= 1e-8 else max(0.0, min(1.0, net_torque / denom))
|
else:
|
||||||
target_rpm = idle_eff + torque_norm * (maxr - idle_eff)
|
rpm = max(free_target, rpm - fall * dt)
|
||||||
|
elif ign == "START":
|
||||||
|
rpm = max(rpm, crank_rpm)
|
||||||
|
else:
|
||||||
|
rpm *= 0.98
|
||||||
|
|
||||||
# Inertia
|
# Stall NUR wenn keine Gnadenfrist aktiv ist
|
||||||
if rpm < target_rpm: rpm = min(target_rpm, rpm + rise * dt)
|
if ign == "ON" and self._running and self._post_start_s <= 0.0 and rpm < stall_rpm:
|
||||||
else: rpm = max(target_rpm, rpm - fall * dt)
|
|
||||||
|
|
||||||
# Stall
|
|
||||||
if ign == "ON" and self._running and rpm < stall_rpm:
|
|
||||||
self._running = False
|
self._running = False
|
||||||
|
rpm = 0.0
|
||||||
|
|
||||||
# --- Öldruck ---
|
# Öldruck
|
||||||
if self._running and rpm > 0.0:
|
if self._running and rpm > 0.0:
|
||||||
over_krpm = max(0.0, (rpm - idle)/1000.0)
|
over_krpm = max(0.0, (rpm - idle)/1000.0)
|
||||||
oil_target = oil_idle_bar + oil_slope_bar_per_krpm * over_krpm
|
oil_target = oil_idle_bar + oil_slope_bar_per_krpm * over_krpm
|
||||||
elif ign == "START" and target_rpm > 0.0:
|
elif ign == "START" and rpm > 0.0:
|
||||||
oil_target = max(oil_floor_off, 0.4)
|
oil_target = max(oil_floor_off, 0.4)
|
||||||
else:
|
else:
|
||||||
oil_target = oil_floor_off
|
oil_target = oil_floor_off
|
||||||
a = min(1.0, dt / max(0.05, self._oil_p_tau))
|
a = min(1.0, dt / max(0.05, self._oil_p_tau))
|
||||||
oil_p = (1-a) * oil_p + a * oil_target
|
oil_p = (1-a) * oil_p + a * oil_target
|
||||||
|
|
||||||
# --- RPM-Jitter ---
|
# Jitter (wie gehabt)
|
||||||
if self._running and rpm >= jitter_off_rpm and ign == "ON":
|
if self._running and rpm >= jitter_off_rpm and ign == "ON":
|
||||||
b = min(1.0, dt / max(1e-3, jitter_tau))
|
b = min(1.0, dt / max(1e-3, jitter_tau))
|
||||||
eta_n = random.uniform(-1.0, 1.0)
|
eta_n = random.uniform(-1.0, 1.0)
|
||||||
@@ -273,12 +243,10 @@ class EngineModule(Module):
|
|||||||
else:
|
else:
|
||||||
self._rpm_noise *= 0.9
|
self._rpm_noise *= 0.9
|
||||||
|
|
||||||
# --- Clamp & Set ---
|
# Clamp & Set
|
||||||
rpm = max(0.0, min(rpm, maxr))
|
rpm = max(0.0, min(rpm, maxr))
|
||||||
oil_p = max(oil_floor_off, min(8.0, oil_p))
|
oil_p = max(oil_floor_off, min(8.0, oil_p))
|
||||||
|
|
||||||
v.set("rpm", float(rpm))
|
v.set("rpm", float(rpm))
|
||||||
# Temperaturen NICHT setzen – CoolingModule ist owner!
|
|
||||||
v.set("oil_pressure", float(oil_p))
|
v.set("oil_pressure", float(oil_p))
|
||||||
v.set("engine_available_torque_nm", float(avail_torque))
|
v.set("engine_available_torque_nm", float(avail_torque))
|
||||||
v.set("engine_torque_load_nm", float(torque_load))
|
v.set("engine_torque_load_nm", float(torque_load))
|
||||||
|
@@ -31,6 +31,13 @@ class EngineTab(UITab):
|
|||||||
rowL += 1
|
rowL += 1
|
||||||
|
|
||||||
self.idle = tk.IntVar(); L("Leerlauf [RPM]", self.idle)
|
self.idle = tk.IntVar(); L("Leerlauf [RPM]", self.idle)
|
||||||
|
self.cold_idle = tk.IntVar(); L("Kaltlauf-Idle [RPM]", self.cold_idle)
|
||||||
|
self.cold_end = tk.DoubleVar(); L("Kaltlauf Ende bei [°C]", self.cold_end)
|
||||||
|
self.cold_mode = tk.StringVar(); L("Kaltlauf-Modus", self.cold_mode, kind="combo",
|
||||||
|
values=["two_point","slope"])
|
||||||
|
|
||||||
|
ttk.Separator(self.frame).grid(row=rowL, column=0, columnspan=2, sticky="ew", pady=(8,6)); rowL += 1
|
||||||
|
|
||||||
self.maxrpm = tk.IntVar(); L("Max RPM", self.maxrpm)
|
self.maxrpm = tk.IntVar(); L("Max RPM", self.maxrpm)
|
||||||
self.rise = tk.IntVar(); L("Anstieg [RPM/s]", self.rise)
|
self.rise = tk.IntVar(); L("Anstieg [RPM/s]", self.rise)
|
||||||
self.fall = tk.IntVar(); L("Abfall [RPM/s]", self.fall)
|
self.fall = tk.IntVar(); L("Abfall [RPM/s]", self.fall)
|
||||||
@@ -49,12 +56,6 @@ class EngineTab(UITab):
|
|||||||
self.st_thr = tk.DoubleVar(); L("Start-Schwelle [RPM]", self.st_thr)
|
self.st_thr = tk.DoubleVar(); L("Start-Schwelle [RPM]", self.st_thr)
|
||||||
self.stall = tk.DoubleVar(); L("Stall-Grenze [RPM]", self.stall)
|
self.stall = tk.DoubleVar(); L("Stall-Grenze [RPM]", self.stall)
|
||||||
|
|
||||||
ttk.Separator(self.frame).grid(row=rowL, column=0, columnspan=2, sticky="ew", pady=(8,6)); rowL += 1
|
|
||||||
|
|
||||||
self.o_idle = tk.DoubleVar(); L("Öldruck Leerlauf [bar]", self.o_idle)
|
|
||||||
self.o_slope= tk.DoubleVar(); L("Öldruck Steigung [bar/krpm]", self.o_slope)
|
|
||||||
self.o_floor= tk.DoubleVar(); L("Öldruck Boden [bar]", self.o_floor)
|
|
||||||
|
|
||||||
# ---------- Rechte Spalte ----------
|
# ---------- Rechte Spalte ----------
|
||||||
rowR = 0
|
rowR = 0
|
||||||
def R(lbl, var, w=12, kind="entry"):
|
def R(lbl, var, w=12, kind="entry"):
|
||||||
@@ -70,6 +71,10 @@ class EngineTab(UITab):
|
|||||||
s.grid(row=rowR, column=3, sticky="ew")
|
s.grid(row=rowR, column=3, sticky="ew")
|
||||||
rowR += 1
|
rowR += 1
|
||||||
|
|
||||||
|
self.amb_c = tk.DoubleVar(); R("Umgebung [°C]", self.amb_c)
|
||||||
|
|
||||||
|
ttk.Separator(self.frame).grid(row=rowR, column=2, columnspan=2, sticky="ew", pady=(8,6)); rowR += 1
|
||||||
|
|
||||||
self.dk_idle = tk.DoubleVar(); R("DK min Leerlauf [%]", self.dk_idle)
|
self.dk_idle = tk.DoubleVar(); R("DK min Leerlauf [%]", self.dk_idle)
|
||||||
self.dk_over = tk.DoubleVar(); R("DK Schub [%]", self.dk_over)
|
self.dk_over = tk.DoubleVar(); R("DK Schub [%]", self.dk_over)
|
||||||
self.dk_tau = tk.DoubleVar(); R("DK Zeitkonstante [s]", self.dk_tau)
|
self.dk_tau = tk.DoubleVar(); R("DK Zeitkonstante [s]", self.dk_tau)
|
||||||
@@ -85,12 +90,6 @@ class EngineTab(UITab):
|
|||||||
|
|
||||||
ttk.Separator(self.frame).grid(row=rowR, column=2, columnspan=2, sticky="ew", pady=(8,6)); rowR += 1
|
ttk.Separator(self.frame).grid(row=rowR, column=2, columnspan=2, sticky="ew", pady=(8,6)); rowR += 1
|
||||||
|
|
||||||
self.amb_c = tk.DoubleVar(); R("Umgebung [°C]", self.amb_c)
|
|
||||||
self.cold_k = tk.DoubleVar(); R("Kalt-Leerlauf +/°C [RPM/°C]", self.cold_k)
|
|
||||||
self.cold_max=tk.DoubleVar(); R("Kalt-Leerlauf max [RPM]", self.cold_max)
|
|
||||||
|
|
||||||
ttk.Separator(self.frame).grid(row=rowR, column=2, columnspan=2, sticky="ew", pady=(8,6)); rowR += 1
|
|
||||||
|
|
||||||
self.pedal = tk.DoubleVar(); R("Gaspedal [%]", self.pedal, kind="scale")
|
self.pedal = tk.DoubleVar(); R("Gaspedal [%]", self.pedal, kind="scale")
|
||||||
|
|
||||||
# ---------- Buttons ----------
|
# ---------- Buttons ----------
|
||||||
@@ -109,78 +108,78 @@ class EngineTab(UITab):
|
|||||||
e = dict(ENGINE_DEFAULTS); e.update(self.sim.v.config.get("engine", {}))
|
e = dict(ENGINE_DEFAULTS); e.update(self.sim.v.config.get("engine", {}))
|
||||||
|
|
||||||
# links
|
# links
|
||||||
self.idle.set(e["idle_rpm"])
|
self.idle.set(e.get("idle_rpm", ENGINE_DEFAULTS["idle_rpm"]))
|
||||||
self.maxrpm.set(e["max_rpm"])
|
self.cold_idle.set(e.get("cold_idle_rpm", e.get("idle_rpm", ENGINE_DEFAULTS["idle_rpm"])))
|
||||||
self.rise.set(e["rpm_rise_per_s"])
|
self.cold_end.set(e.get("cold_idle_end_c", 50.0))
|
||||||
self.fall.set(e["rpm_fall_per_s"])
|
self.cold_mode.set(e.get("idle_cold_mode", "two_point"))
|
||||||
self.curve.set(e["throttle_curve"])
|
|
||||||
|
|
||||||
self.power.set(e["engine_power_kw"])
|
self.maxrpm.set(e.get("max_rpm", ENGINE_DEFAULTS["max_rpm"]))
|
||||||
self.tqpeak.set(e["torque_peak_rpm"])
|
self.rise.set(e.get("rpm_rise_per_s", ENGINE_DEFAULTS["rpm_rise_per_s"]))
|
||||||
|
self.fall.set(e.get("rpm_fall_per_s", ENGINE_DEFAULTS["rpm_fall_per_s"]))
|
||||||
|
self.curve.set(e.get("throttle_curve", ENGINE_DEFAULTS["throttle_curve"]))
|
||||||
|
|
||||||
self.st_nom.set(e["starter_rpm_nominal"])
|
self.power.set(e.get("engine_power_kw", ENGINE_DEFAULTS["engine_power_kw"]))
|
||||||
self.st_vmin.set(e["starter_voltage_min"])
|
self.tqpeak.set(e.get("torque_peak_rpm", ENGINE_DEFAULTS["torque_peak_rpm"]))
|
||||||
self.st_thr.set(e["start_rpm_threshold"])
|
|
||||||
self.stall.set(e["stall_rpm"])
|
|
||||||
|
|
||||||
self.o_idle.set(e["oil_pressure_idle_bar"])
|
self.st_nom.set(e.get("starter_rpm_nominal", ENGINE_DEFAULTS["starter_rpm_nominal"]))
|
||||||
self.o_slope.set(e["oil_pressure_slope_bar_per_krpm"])
|
self.st_vmin.set(e.get("starter_voltage_min", ENGINE_DEFAULTS["starter_voltage_min"]))
|
||||||
self.o_floor.set(e["oil_pressure_off_floor_bar"])
|
self.st_thr.set(e.get("start_rpm_threshold", ENGINE_DEFAULTS["start_rpm_threshold"]))
|
||||||
|
self.stall.set(e.get("stall_rpm", ENGINE_DEFAULTS["stall_rpm"]))
|
||||||
|
|
||||||
# rechts
|
# rechts
|
||||||
self.dk_idle.set(e["throttle_plate_idle_min_pct"])
|
self.amb_c.set(e.get("coolant_ambient_c", ENGINE_DEFAULTS["coolant_ambient_c"]))
|
||||||
self.dk_over.set(e["throttle_plate_overrun_pct"])
|
|
||||||
self.dk_tau.set(e["throttle_plate_tau_s"])
|
|
||||||
self.tq_kp.set(e["torque_ctrl_kp"])
|
|
||||||
self.tq_ki.set(e["torque_ctrl_ki"])
|
|
||||||
|
|
||||||
self.jit_idle.set(e["rpm_jitter_idle_amp_rpm"])
|
self.dk_idle.set(e.get("throttle_plate_idle_min_pct", ENGINE_DEFAULTS["throttle_plate_idle_min_pct"]))
|
||||||
self.jit_high.set(e["rpm_jitter_high_amp_rpm"])
|
self.dk_over.set(e.get("throttle_plate_overrun_pct", ENGINE_DEFAULTS["throttle_plate_overrun_pct"]))
|
||||||
self.jit_tau.set(e["rpm_jitter_tau_s"])
|
self.dk_tau.set(e.get("throttle_plate_tau_s", ENGINE_DEFAULTS["throttle_plate_tau_s"]))
|
||||||
self.jit_off.set(e["rpm_jitter_off_threshold_rpm"])
|
self.tq_kp.set(e.get("torque_ctrl_kp", ENGINE_DEFAULTS["torque_ctrl_kp"]))
|
||||||
|
self.tq_ki.set(e.get("torque_ctrl_ki", ENGINE_DEFAULTS["torque_ctrl_ki"]))
|
||||||
|
|
||||||
self.amb_c.set(e["coolant_ambient_c"])
|
self.jit_idle.set(e.get("rpm_jitter_idle_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_idle_amp_rpm"]))
|
||||||
self.cold_k.set(e["idle_cold_gain_per_deg"])
|
self.jit_high.set(e.get("rpm_jitter_high_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_high_amp_rpm"]))
|
||||||
self.cold_max.set(e["idle_cold_gain_max"])
|
self.jit_tau.set(e.get("rpm_jitter_tau_s", ENGINE_DEFAULTS["rpm_jitter_tau_s"]))
|
||||||
|
self.jit_off.set(e.get("rpm_jitter_off_threshold_rpm", ENGINE_DEFAULTS["rpm_jitter_off_threshold_rpm"]))
|
||||||
|
|
||||||
self.pedal.set(e["throttle_pedal_pct"])
|
self.pedal.set(e.get("throttle_pedal_pct", ENGINE_DEFAULTS["throttle_pedal_pct"]))
|
||||||
self._on_pedal_change()
|
self._on_pedal_change()
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
cfg = {"engine": {
|
cfg = {"engine": {
|
||||||
|
# Idle & Kaltlauf (Zweipunkt)
|
||||||
"idle_rpm": int(self.idle.get()),
|
"idle_rpm": int(self.idle.get()),
|
||||||
|
"cold_idle_rpm": int(self.cold_idle.get()),
|
||||||
|
"cold_idle_end_c": float(self.cold_end.get()),
|
||||||
|
"idle_cold_mode": self.cold_mode.get(),
|
||||||
|
|
||||||
|
# Basis/Leistung
|
||||||
"max_rpm": int(self.maxrpm.get()),
|
"max_rpm": int(self.maxrpm.get()),
|
||||||
"rpm_rise_per_s": int(self.rise.get()),
|
"rpm_rise_per_s": int(self.rise.get()),
|
||||||
"rpm_fall_per_s": int(self.fall.get()),
|
"rpm_fall_per_s": int(self.fall.get()),
|
||||||
"throttle_curve": self.curve.get(),
|
"throttle_curve": self.curve.get(),
|
||||||
|
|
||||||
"engine_power_kw": float(self.power.get()),
|
"engine_power_kw": float(self.power.get()),
|
||||||
"torque_peak_rpm": float(self.tqpeak.get()),
|
"torque_peak_rpm": float(self.tqpeak.get()),
|
||||||
|
|
||||||
|
# Start/Abwürgen
|
||||||
"starter_rpm_nominal": float(self.st_nom.get()),
|
"starter_rpm_nominal": float(self.st_nom.get()),
|
||||||
"starter_voltage_min": float(self.st_vmin.get()),
|
"starter_voltage_min": float(self.st_vmin.get()),
|
||||||
"start_rpm_threshold": float(self.st_thr.get()),
|
"start_rpm_threshold": float(self.st_thr.get()),
|
||||||
"stall_rpm": float(self.stall.get()),
|
"stall_rpm": float(self.stall.get()),
|
||||||
|
|
||||||
"oil_pressure_idle_bar": float(self.o_idle.get()),
|
# Umgebung & DBW
|
||||||
"oil_pressure_slope_bar_per_krpm": float(self.o_slope.get()),
|
"coolant_ambient_c": float(self.amb_c.get()),
|
||||||
"oil_pressure_off_floor_bar": float(self.o_floor.get()),
|
|
||||||
|
|
||||||
"throttle_plate_idle_min_pct": float(self.dk_idle.get()),
|
"throttle_plate_idle_min_pct": float(self.dk_idle.get()),
|
||||||
"throttle_plate_overrun_pct": float(self.dk_over.get()),
|
"throttle_plate_overrun_pct": float(self.dk_over.get()),
|
||||||
"throttle_plate_tau_s": float(self.dk_tau.get()),
|
"throttle_plate_tau_s": float(self.dk_tau.get()),
|
||||||
"torque_ctrl_kp": float(self.tq_kp.get()),
|
"torque_ctrl_kp": float(self.tq_kp.get()),
|
||||||
"torque_ctrl_ki": float(self.tq_ki.get()),
|
"torque_ctrl_ki": float(self.tq_ki.get()),
|
||||||
|
|
||||||
|
# Jitter
|
||||||
"rpm_jitter_idle_amp_rpm": float(self.jit_idle.get()),
|
"rpm_jitter_idle_amp_rpm": float(self.jit_idle.get()),
|
||||||
"rpm_jitter_high_amp_rpm": float(self.jit_high.get()),
|
"rpm_jitter_high_amp_rpm": float(self.jit_high.get()),
|
||||||
"rpm_jitter_tau_s": float(self.jit_tau.get()),
|
"rpm_jitter_tau_s": float(self.jit_tau.get()),
|
||||||
"rpm_jitter_off_threshold_rpm": float(self.jit_off.get()),
|
"rpm_jitter_off_threshold_rpm": float(self.jit_off.get()),
|
||||||
|
|
||||||
"coolant_ambient_c": float(self.amb_c.get()),
|
# UI
|
||||||
"idle_cold_gain_per_deg": float(self.cold_k.get()),
|
|
||||||
"idle_cold_gain_max": float(self.cold_max.get()),
|
|
||||||
|
|
||||||
"throttle_pedal_pct": float(self.pedal.get()),
|
"throttle_pedal_pct": float(self.pedal.get()),
|
||||||
}}
|
}}
|
||||||
self.sim.load_config(cfg)
|
self.sim.load_config(cfg)
|
||||||
|
Reference in New Issue
Block a user