186 lines
9.0 KiB
Python
186 lines
9.0 KiB
Python
# =============================
|
|
# app/simulation/ui/engine.py
|
|
# =============================
|
|
|
|
from __future__ import annotations
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
from app.simulation.modules.engine import ENGINE_DEFAULTS
|
|
from app.simulation.ui import UITab
|
|
|
|
class EngineTab(UITab):
|
|
NAME = "engine"
|
|
TITLE = "Motor"
|
|
PRIO = 10
|
|
|
|
def __init__(self, parent, sim):
|
|
self.sim = sim
|
|
self.frame = ttk.Frame(parent, padding=8)
|
|
for c in (0,1,2,3): self.frame.columnconfigure(c, weight=1)
|
|
|
|
# ---------- Linke Spalte ----------
|
|
rowL = 0
|
|
def L(lbl, var, w=12, kind="entry", values=None):
|
|
nonlocal rowL
|
|
ttk.Label(self.frame, text=lbl).grid(row=rowL, column=0, sticky="w")
|
|
if kind == "entry":
|
|
ttk.Entry(self.frame, textvariable=var, width=w).grid(row=rowL, column=1, sticky="w")
|
|
elif kind == "combo":
|
|
ttk.Combobox(self.frame, textvariable=var, state="readonly",
|
|
values=values or [], width=w).grid(row=rowL, column=1, sticky="w")
|
|
rowL += 1
|
|
|
|
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.rise = tk.IntVar(); L("Anstieg [RPM/s]", self.rise)
|
|
self.fall = tk.IntVar(); L("Abfall [RPM/s]", self.fall)
|
|
self.curve = tk.StringVar(); L("Gaspedal-Kennlinie", self.curve, kind="combo",
|
|
values=["linear","progressive","aggressive"])
|
|
|
|
ttk.Separator(self.frame).grid(row=rowL, column=0, columnspan=2, sticky="ew", pady=(8,6)); rowL += 1
|
|
|
|
self.power = tk.DoubleVar(); L("Motorleistung [kW]", self.power)
|
|
self.tqpeak = tk.DoubleVar(); L("Drehmoment-Peak [RPM]", self.tqpeak)
|
|
|
|
ttk.Separator(self.frame).grid(row=rowL, column=0, columnspan=2, sticky="ew", pady=(8,6)); rowL += 1
|
|
|
|
self.st_nom = tk.DoubleVar(); L("Starter Nenn-RPM", self.st_nom)
|
|
self.st_vmin= tk.DoubleVar(); L("Starter min. Spannung [V]", self.st_vmin)
|
|
self.st_thr = tk.DoubleVar(); L("Start-Schwelle [RPM]", self.st_thr)
|
|
self.stall = tk.DoubleVar(); L("Stall-Grenze [RPM]", self.stall)
|
|
|
|
# ---------- Rechte Spalte ----------
|
|
rowR = 0
|
|
def R(lbl, var, w=12, kind="entry"):
|
|
nonlocal rowR
|
|
ttk.Label(self.frame, text=lbl).grid(row=rowR, column=2, sticky="w")
|
|
if kind == "entry":
|
|
ttk.Entry(self.frame, textvariable=var, width=w).grid(row=rowR, column=3, sticky="w")
|
|
elif kind == "label":
|
|
ttk.Label(self.frame, textvariable=var).grid(row=rowR, column=3, sticky="w")
|
|
elif kind == "scale":
|
|
s = ttk.Scale(self.frame, from_=0.0, to=100.0, variable=var,
|
|
command=lambda _=None: self._on_pedal_change())
|
|
s.grid(row=rowR, column=3, sticky="ew")
|
|
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_over = tk.DoubleVar(); R("DK Schub [%]", self.dk_over)
|
|
self.dk_tau = tk.DoubleVar(); R("DK Zeitkonstante [s]", self.dk_tau)
|
|
self.tq_kp = tk.DoubleVar(); R("Torque-Kp", self.tq_kp)
|
|
self.tq_ki = tk.DoubleVar(); R("Torque-Ki", self.tq_ki)
|
|
|
|
ttk.Separator(self.frame).grid(row=rowR, column=2, columnspan=2, sticky="ew", pady=(8,6)); rowR += 1
|
|
|
|
self.jit_idle= tk.DoubleVar(); R("Jitter Leerlauf [±RPM]", self.jit_idle)
|
|
self.jit_high= tk.DoubleVar(); R("Jitter hoch [±RPM]", self.jit_high)
|
|
self.jit_tau = tk.DoubleVar(); R("Jitter-Zeitkonstante [s]", self.jit_tau)
|
|
self.jit_off = tk.DoubleVar(); R("Jitter aus unter [RPM]", self.jit_off)
|
|
|
|
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")
|
|
|
|
# ---------- Buttons ----------
|
|
rowBtns = max(rowL, rowR) + 1
|
|
btn = ttk.Frame(self.frame); btn.grid(row=rowBtns, column=0, columnspan=4, sticky="w", pady=(8,0))
|
|
ttk.Button(btn, text="Aktualisieren", command=self.refresh).pack(side="left")
|
|
ttk.Button(btn, text="Anwenden", command=self.apply).pack(side="left", padx=(8,0))
|
|
|
|
self.refresh()
|
|
|
|
def _on_pedal_change(self):
|
|
try: self.sim.v.set("throttle_pedal_pct", float(self.pedal.get()))
|
|
except: pass
|
|
|
|
def refresh(self):
|
|
e = dict(ENGINE_DEFAULTS); e.update(self.sim.v.config.get("engine", {}))
|
|
|
|
# links
|
|
self.idle.set(e.get("idle_rpm", ENGINE_DEFAULTS["idle_rpm"]))
|
|
self.cold_idle.set(e.get("cold_idle_rpm", e.get("idle_rpm", ENGINE_DEFAULTS["idle_rpm"])))
|
|
self.cold_end.set(e.get("cold_idle_end_c", 50.0))
|
|
self.cold_mode.set(e.get("idle_cold_mode", "two_point"))
|
|
|
|
self.maxrpm.set(e.get("max_rpm", ENGINE_DEFAULTS["max_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.power.set(e.get("engine_power_kw", ENGINE_DEFAULTS["engine_power_kw"]))
|
|
self.tqpeak.set(e.get("torque_peak_rpm", ENGINE_DEFAULTS["torque_peak_rpm"]))
|
|
|
|
self.st_nom.set(e.get("starter_rpm_nominal", ENGINE_DEFAULTS["starter_rpm_nominal"]))
|
|
self.st_vmin.set(e.get("starter_voltage_min", ENGINE_DEFAULTS["starter_voltage_min"]))
|
|
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
|
|
self.amb_c.set(e.get("coolant_ambient_c", ENGINE_DEFAULTS["coolant_ambient_c"]))
|
|
|
|
self.dk_idle.set(e.get("throttle_plate_idle_min_pct", ENGINE_DEFAULTS["throttle_plate_idle_min_pct"]))
|
|
self.dk_over.set(e.get("throttle_plate_overrun_pct", ENGINE_DEFAULTS["throttle_plate_overrun_pct"]))
|
|
self.dk_tau.set(e.get("throttle_plate_tau_s", ENGINE_DEFAULTS["throttle_plate_tau_s"]))
|
|
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.jit_idle.set(e.get("rpm_jitter_idle_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_idle_amp_rpm"]))
|
|
self.jit_high.set(e.get("rpm_jitter_high_amp_rpm", ENGINE_DEFAULTS["rpm_jitter_high_amp_rpm"]))
|
|
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.get("throttle_pedal_pct", ENGINE_DEFAULTS["throttle_pedal_pct"]))
|
|
self._on_pedal_change()
|
|
|
|
def apply(self):
|
|
cfg = {"engine": {
|
|
# Idle & Kaltlauf (Zweipunkt)
|
|
"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()),
|
|
"rpm_rise_per_s": int(self.rise.get()),
|
|
"rpm_fall_per_s": int(self.fall.get()),
|
|
"throttle_curve": self.curve.get(),
|
|
"engine_power_kw": float(self.power.get()),
|
|
"torque_peak_rpm": float(self.tqpeak.get()),
|
|
|
|
# Start/Abwürgen
|
|
"starter_rpm_nominal": float(self.st_nom.get()),
|
|
"starter_voltage_min": float(self.st_vmin.get()),
|
|
"start_rpm_threshold": float(self.st_thr.get()),
|
|
"stall_rpm": float(self.stall.get()),
|
|
|
|
# Umgebung & DBW
|
|
"coolant_ambient_c": float(self.amb_c.get()),
|
|
"throttle_plate_idle_min_pct": float(self.dk_idle.get()),
|
|
"throttle_plate_overrun_pct": float(self.dk_over.get()),
|
|
"throttle_plate_tau_s": float(self.dk_tau.get()),
|
|
"torque_ctrl_kp": float(self.tq_kp.get()),
|
|
"torque_ctrl_ki": float(self.tq_ki.get()),
|
|
|
|
# Jitter
|
|
"rpm_jitter_idle_amp_rpm": float(self.jit_idle.get()),
|
|
"rpm_jitter_high_amp_rpm": float(self.jit_high.get()),
|
|
"rpm_jitter_tau_s": float(self.jit_tau.get()),
|
|
"rpm_jitter_off_threshold_rpm": float(self.jit_off.get()),
|
|
|
|
# UI
|
|
"throttle_pedal_pct": float(self.pedal.get()),
|
|
}}
|
|
self.sim.load_config(cfg)
|