Public Access
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