Put sidebar controls in fragment to prevent page blanking
Both controls and display are now fragments, so slider changes don't trigger full page reruns.
This commit is contained in:
@@ -16,9 +16,6 @@ from py_dvt_ate.simulation.physics.engine import PhysicsEngine
|
|||||||
# History buffer size for charts
|
# History buffer size for charts
|
||||||
HISTORY_SIZE = 500
|
HISTORY_SIZE = 500
|
||||||
|
|
||||||
# Simulation speed settings
|
|
||||||
DEFAULT_TIME_MULTIPLIER = 10.0 # 10x faster than real-time
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SimulationHistory:
|
class SimulationHistory:
|
||||||
@@ -48,17 +45,17 @@ def init_session_state() -> None:
|
|||||||
st.session_state.history = SimulationHistory()
|
st.session_state.history = SimulationHistory()
|
||||||
if "running" not in st.session_state:
|
if "running" not in st.session_state:
|
||||||
st.session_state.running = False
|
st.session_state.running = False
|
||||||
if "time_multiplier" not in st.session_state:
|
|
||||||
st.session_state.time_multiplier = DEFAULT_TIME_MULTIPLIER
|
|
||||||
if "last_update" not in st.session_state:
|
if "last_update" not in st.session_state:
|
||||||
st.session_state.last_update = time.time()
|
st.session_state.last_update = time.time()
|
||||||
|
# Note: time_multiplier, temp_setpoint, input_voltage, output_enabled,
|
||||||
|
# load_current are managed by their respective widgets via keys
|
||||||
|
|
||||||
|
|
||||||
def step_simulation() -> None:
|
def step_simulation() -> None:
|
||||||
"""Advance the simulation based on elapsed real time and multiplier."""
|
"""Advance the simulation based on elapsed real time and multiplier."""
|
||||||
engine: PhysicsEngine = st.session_state.engine
|
engine: PhysicsEngine = st.session_state.engine
|
||||||
history: SimulationHistory = st.session_state.history
|
history: SimulationHistory = st.session_state.history
|
||||||
multiplier: float = st.session_state.time_multiplier
|
multiplier: float = st.session_state.get("time_multiplier", 10)
|
||||||
|
|
||||||
# Calculate how much simulation time to advance
|
# Calculate how much simulation time to advance
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
@@ -87,10 +84,18 @@ def step_simulation() -> None:
|
|||||||
history.power_dissipation.append(electrical.power_dissipation)
|
history.power_dissipation.append(electrical.power_dissipation)
|
||||||
|
|
||||||
|
|
||||||
def display_controls() -> None:
|
def sync_engine_from_session_state() -> None:
|
||||||
"""Display simulation control panel in sidebar."""
|
"""Sync engine parameters from session state (called by fragment)."""
|
||||||
engine: PhysicsEngine = st.session_state.engine
|
engine: PhysicsEngine = st.session_state.engine
|
||||||
|
engine.set_chamber_setpoint(st.session_state.get("temp_setpoint", 25.0))
|
||||||
|
engine.set_input_voltage(st.session_state.get("input_voltage", 5.0))
|
||||||
|
engine.set_output_enabled(st.session_state.get("output_enabled", False))
|
||||||
|
engine.set_load_current(st.session_state.get("load_current", 100.0) / 1000.0)
|
||||||
|
|
||||||
|
|
||||||
|
@st.fragment
|
||||||
|
def display_controls() -> None:
|
||||||
|
"""Display simulation control panel in sidebar (as fragment to avoid full reruns)."""
|
||||||
st.sidebar.header("Simulation Controls")
|
st.sidebar.header("Simulation Controls")
|
||||||
|
|
||||||
# Start/Stop button
|
# Start/Stop button
|
||||||
@@ -99,14 +104,12 @@ def display_controls() -> None:
|
|||||||
"Stop Simulation", type="primary", use_container_width=True
|
"Stop Simulation", type="primary", use_container_width=True
|
||||||
):
|
):
|
||||||
st.session_state.running = False
|
st.session_state.running = False
|
||||||
st.rerun()
|
|
||||||
else:
|
else:
|
||||||
if st.sidebar.button(
|
if st.sidebar.button(
|
||||||
"Start Simulation", type="primary", use_container_width=True
|
"Start Simulation", type="primary", use_container_width=True
|
||||||
):
|
):
|
||||||
st.session_state.running = True
|
st.session_state.running = True
|
||||||
st.session_state.last_update = time.time()
|
st.session_state.last_update = time.time()
|
||||||
st.rerun()
|
|
||||||
|
|
||||||
# Reset button
|
# Reset button
|
||||||
if st.sidebar.button("Reset", use_container_width=True):
|
if st.sidebar.button("Reset", use_container_width=True):
|
||||||
@@ -114,27 +117,27 @@ def display_controls() -> None:
|
|||||||
st.session_state.history = SimulationHistory()
|
st.session_state.history = SimulationHistory()
|
||||||
st.session_state.running = False
|
st.session_state.running = False
|
||||||
st.session_state.last_update = time.time()
|
st.session_state.last_update = time.time()
|
||||||
st.rerun()
|
|
||||||
|
|
||||||
st.sidebar.divider()
|
st.sidebar.divider()
|
||||||
|
|
||||||
# Time multiplier
|
# Time multiplier
|
||||||
st.sidebar.subheader("Simulation Speed")
|
st.sidebar.subheader("Simulation Speed")
|
||||||
time_mult = st.sidebar.select_slider(
|
st.sidebar.select_slider(
|
||||||
"Time Multiplier",
|
"Time Multiplier",
|
||||||
options=[1, 2, 5, 10, 20, 50, 100],
|
options=[1, 2, 5, 10, 20, 50, 100],
|
||||||
value=int(st.session_state.time_multiplier),
|
value=10,
|
||||||
format_func=lambda x: f"{x}x",
|
format_func=lambda x: f"{x}x",
|
||||||
key="time_mult_slider",
|
key="time_multiplier",
|
||||||
|
)
|
||||||
|
st.sidebar.caption(
|
||||||
|
f"1 real second = {st.session_state.get('time_multiplier', 10)} simulation seconds"
|
||||||
)
|
)
|
||||||
st.session_state.time_multiplier = float(time_mult)
|
|
||||||
st.sidebar.caption(f"1 real second = {time_mult} simulation seconds")
|
|
||||||
|
|
||||||
st.sidebar.divider()
|
st.sidebar.divider()
|
||||||
|
|
||||||
# Temperature setpoint
|
# Temperature setpoint
|
||||||
st.sidebar.subheader("Thermal Chamber")
|
st.sidebar.subheader("Thermal Chamber")
|
||||||
temp_setpoint = st.sidebar.slider(
|
st.sidebar.slider(
|
||||||
"Temperature Setpoint (C)",
|
"Temperature Setpoint (C)",
|
||||||
min_value=-40.0,
|
min_value=-40.0,
|
||||||
max_value=125.0,
|
max_value=125.0,
|
||||||
@@ -142,13 +145,12 @@ def display_controls() -> None:
|
|||||||
step=5.0,
|
step=5.0,
|
||||||
key="temp_setpoint",
|
key="temp_setpoint",
|
||||||
)
|
)
|
||||||
engine.set_chamber_setpoint(temp_setpoint)
|
|
||||||
|
|
||||||
st.sidebar.divider()
|
st.sidebar.divider()
|
||||||
|
|
||||||
# Power supply controls
|
# Power supply controls
|
||||||
st.sidebar.subheader("Power Supply")
|
st.sidebar.subheader("Power Supply")
|
||||||
input_voltage = st.sidebar.slider(
|
st.sidebar.slider(
|
||||||
"Input Voltage (V)",
|
"Input Voltage (V)",
|
||||||
min_value=0.0,
|
min_value=0.0,
|
||||||
max_value=12.0,
|
max_value=12.0,
|
||||||
@@ -156,20 +158,18 @@ def display_controls() -> None:
|
|||||||
step=0.1,
|
step=0.1,
|
||||||
key="input_voltage",
|
key="input_voltage",
|
||||||
)
|
)
|
||||||
engine.set_input_voltage(input_voltage)
|
|
||||||
|
|
||||||
output_enabled = st.sidebar.toggle(
|
st.sidebar.toggle(
|
||||||
"Output Enabled",
|
"Output Enabled",
|
||||||
value=engine.is_output_enabled,
|
value=False,
|
||||||
key="output_enabled",
|
key="output_enabled",
|
||||||
)
|
)
|
||||||
engine.set_output_enabled(output_enabled)
|
|
||||||
|
|
||||||
st.sidebar.divider()
|
st.sidebar.divider()
|
||||||
|
|
||||||
# Load controls
|
# Load controls
|
||||||
st.sidebar.subheader("Electronic Load")
|
st.sidebar.subheader("Electronic Load")
|
||||||
load_current_ma = st.sidebar.slider(
|
st.sidebar.slider(
|
||||||
"Load Current (mA)",
|
"Load Current (mA)",
|
||||||
min_value=0.0,
|
min_value=0.0,
|
||||||
max_value=500.0,
|
max_value=500.0,
|
||||||
@@ -177,7 +177,6 @@ def display_controls() -> None:
|
|||||||
step=10.0,
|
step=10.0,
|
||||||
key="load_current",
|
key="load_current",
|
||||||
)
|
)
|
||||||
engine.set_load_current(load_current_ma / 1000.0)
|
|
||||||
|
|
||||||
|
|
||||||
@st.fragment(run_every=0.1)
|
@st.fragment(run_every=0.1)
|
||||||
@@ -186,6 +185,9 @@ def simulation_display() -> None:
|
|||||||
engine: PhysicsEngine = st.session_state.engine
|
engine: PhysicsEngine = st.session_state.engine
|
||||||
history: SimulationHistory = st.session_state.history
|
history: SimulationHistory = st.session_state.history
|
||||||
|
|
||||||
|
# Sync engine parameters from UI controls
|
||||||
|
sync_engine_from_session_state()
|
||||||
|
|
||||||
# Step simulation if running
|
# Step simulation if running
|
||||||
if st.session_state.running:
|
if st.session_state.running:
|
||||||
step_simulation()
|
step_simulation()
|
||||||
@@ -220,7 +222,7 @@ def simulation_display() -> None:
|
|||||||
st.metric(
|
st.metric(
|
||||||
"Sim Time",
|
"Sim Time",
|
||||||
f"{engine.simulation_time:.1f} s",
|
f"{engine.simulation_time:.1f} s",
|
||||||
delta=f"{status} @ {st.session_state.time_multiplier:.0f}x",
|
delta=f"{status} @ {st.session_state.get('time_multiplier', 10):.0f}x",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Temperature chart
|
# Temperature chart
|
||||||
|
|||||||
Reference in New Issue
Block a user