Allow a Sud step to combine a ramp and a hold

A step can now carry both 'ramp' and 'hold': it ramps to the target
temp, then holds there for the given duration, instead of needing two
separate schedule entries. Sud.temp_reached() switches such a step
from its ramp phase into its hold phase in place (re-firing the
step-changed callback so SudTask/demo_sud re-apply the hold's stirrer
settings); user_wait_for_continue still applies once the whole step -
both phases - is done.

Merges sud_0010.json's three ramp/hold pairs into combined steps.
This commit is contained in:
2026-06-21 09:01:04 +02:00
parent 56de5cf4d6
commit 9bd9889cb0
6 changed files with 57 additions and 37 deletions
+8 -4
View File
@@ -53,8 +53,8 @@ if __name__ == '__main__':
heater.set_on_changed('power_set', ctrl.set_model_power)
heater.set_on_changed('power_eff', plant.set_power)
def apply_stirrer(step):
stirrer_cfg = step.get('ramp', step.get('hold', {})).get('stirrer', {})
def apply_stirrer(phase):
stirrer_cfg = phase.get('stirrer', {})
speed = stirrer_cfg.get('speed', 0)
interval_time = stirrer_cfg.get('interval_time', 0)
on_ratio = stirrer_cfg.get('on_ratio', 1.0)
@@ -72,13 +72,17 @@ if __name__ == '__main__':
ctrl.set_model_params(params['M'], params['C'])
def on_step_changed(step):
# A step may carry both 'ramp' and 'hold' (ramp to temp, then hold);
# sud.state tells us which phase is currently active.
if step is not None:
ramping = sud.state == SudState.RAMPING
phase = step['ramp'] if ramping and 'ramp' in step else step.get('hold', {})
print(f"Step {step['number']}: {step['descr']}")
apply_plant_params(step)
if 'ramp' in step:
if ramping and 'ramp' in step:
ctrl.set_theta_soll(step['ramp']['temp'])
ctrl.set_heatrate_soll(step['ramp']['rate'])
apply_stirrer(step)
apply_stirrer(phase)
def on_state_changed(state):
if state == SudState.WAIT_USER and sud.user_message: