Two root causes for the visible power dip at every ramp-to-ramp step boundary: 1. One-tick cascade delay: heatrate_soll was computed from pid_hold.get_y() before pid_hold.process() ran in that tick, so the first tick of a new ramp used the stale hold-phase output (≈0) as the rate setpoint, driving pid_heat to near zero. Fix: move heatrate_soll computation inside process_pid(), after pid_hold.process(). 2. Cold-start reset: pid_heat.reset() at HOLD→HEAT discarded the hold-phase integral, so pid_heat had to ramp up from zero on every new step. Fix: remove the reset (bumpless transfer) — the hold-phase integral is a warm starting point that carries the baseline hold power into the new ramp. Together these eliminate the ~1s dip to near-zero and replace the slow 20–30s integral ramp-up with an immediate start at roughly hold-level power, climbing monotonically to the target. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
23 lines
738 B
Python
23 lines
738 B
Python
from components.pid.temp_controller_base import TempControllerBase
|
|
|
|
|
|
class TempController(TempControllerBase):
|
|
def __init__(self, dt):
|
|
TempControllerBase.__init__(self, dt)
|
|
# last_theta_ist / theta_ist_filtered / beta / dt all live in the base -
|
|
# see TempControllerBase.__init__ and _compute_heatrate().
|
|
|
|
def process(self):
|
|
self._require_params()
|
|
|
|
self.theta_ist = self.theta_ist_set
|
|
self._compute_heatrate(self.theta_ist)
|
|
|
|
# Compensate for max heat rate to reduce overshoot
|
|
hold_scale = 1.0/self.heatrate_soll_set if self.heatrate_soll_set > 0 else 1.0
|
|
|
|
theta_err = self.theta_soll_set - self.theta_ist
|
|
diff = self.theta_soll_set - self.theta_ist
|
|
self.process_fsm(diff)
|
|
self.process_pid(theta_err, hold_scale)
|