"""Cohen-Coon tuning rules for FOPDT processes. Reference --------- G. H. Cohen and G. A. Coon, "Theoretical Consideration of Retarded Control", *Trans. ASME*, 75, 827–834, 1953. Survey context: ``docs/design/03_tuning_methods.md`` §3. """ from __future__ import annotations from typing import Any, ClassVar from pidtune.models.base import ProcessModel from pidtune.models.fopdt import FOPDT from pidtune.tuners.base import ControllerType, Tuner, TuningResult, register_tuner __all__ = ["CohenCoonTuner"] @register_tuner class CohenCoonTuner(Tuner): """Cohen-Coon open-loop tuning from a FOPDT model. With ``K`` the process gain, ``τ`` the time constant, ``θ`` the dead time, and ``r = θ/τ``, the rules are: ========== ================================ ============================= ===================== Controller Kp Ti Td ========== ================================ ============================= ===================== P (1/(K·r)) · (1 + r/3) — — PI (1/(K·r)) · (0.9 + r/12) θ·(30 + 3r) / (9 + 20r) — PD (1/(K·r)) · (1.25 + r/6) — θ·(6 − 2r)/(22 + 3r) PID (1/(K·r)) · (4/3 + r/4) θ·(32 + 6r) / (13 + 8r) θ·4 / (11 + 2r) ========== ================================ ============================= ===================== Compared with Ziegler-Nichols step rules, Cohen-Coon corrects for larger dead-time ratios and is the customary choice for ``0.3 ≤ θ/τ ≤ 4`` — but it still targets quarter-amplitude damping and tends to be oscillatory. Applicability and failure modes ------------------------------- * ``θ == 0`` raises :class:`~pidtune.exceptions.TuningError` (the rules divide by ``r``); the error message suggests IMC/AMIGO instead. * ``θ/τ`` outside ``[0.1, 4]`` emits a :class:`~pidtune.exceptions.TuningApplicabilityWarning`. ``TuningResult.metadata`` keys: ``{"theta_over_tau": float}``. """ name: ClassVar[str] = "cohen-coon" supported_controller_types: ClassVar[frozenset] = frozenset( {ControllerType.P, ControllerType.PI, ControllerType.PD, ControllerType.PID} ) def supports(self, model: ProcessModel) -> bool: """Accept only :class:`~pidtune.models.fopdt.FOPDT` models.""" return isinstance(model, FOPDT) def tune( self, model: ProcessModel, *, controller_type: ControllerType = ControllerType.PID, **options: Any, ) -> TuningResult: """Apply the Cohen-Coon table to a FOPDT model. Parameters ---------- model: A :class:`~pidtune.models.fopdt.FOPDT` instance with ``θ > 0``. controller_type: One of P, PI, PD, PID. **options: No options are accepted; any keyword raises :class:`TypeError`. Returns ------- TuningResult """ raise NotImplementedError("Implemented in Milestone 3.")