pydynamicestimator.devices.inverter_pll ======================================= .. py:module:: pydynamicestimator.devices.inverter_pll .. autoapi-nested-parse:: Inverter phase-locked-loop (frequency/phase estimator) strategies. The PLL is a measurement strategy, **separate from the angle source** -- the inverter analogue of the synchronous machine's PSS: it produces a signal (``omega_pll``) consumed by *another* strategy (the angle source), host-mediated via ``host.pll_frequency(dae)``, and never references its consumer. Keeping it a distinct axis is what lets a grid-forming converter carry a PLL for FRT/monitoring without baking it into "grid-following" (see ``docs/inverter_modernization_design.md`` ยง4.2). ``pll=None`` (the default) means no PLL block. It owns its integrator/angle states (``epsilon`` / ``delta_pll``), registered LAST in the state vector so that -- with the angle source owning ``Pc_tilde`` / ``delta_c`` near the front -- the original GridFollowing ordering is reproduced byte-for-byte. Attributes ---------- .. autoapisummary:: pydynamicestimator.devices.inverter_pll.PLL_REGISTRY Classes ------- .. autoapisummary:: pydynamicestimator.devices.inverter_pll.PLL pydynamicestimator.devices.inverter_pll.SRF_PLL Module Contents --------------- .. py:class:: PLL Bases: :py:obj:`abc.ABC` Abstract base class for inverter PLL (frequency estimator) strategies. Like the SG strategies, the PLL does NOT own state arrays or DAE indices; it declares them and the host ``Inverter`` registers them on itself. Its :meth:`fgcall` writes its own state equations into ``dae.f`` and publishes the estimated synchronizing frequency on ``host.omega_pll`` (an algebraic expression, not a registered variable), which the host exposes to consumers via ``host.pll_frequency(dae)`` and which the reference-frame machinery in ``system.py`` reads for grid-following devices. .. py:method:: states() -> List[str] :abstractmethod: .. py:method:: algebs() -> List[str] .. py:method:: algebs_units() -> Dict[str, str] .. py:method:: algebs_noise() -> Dict[str, float] .. py:method:: algebs_x0() -> Dict[str, float] .. py:method:: units() -> List[str] :abstractmethod: .. py:method:: params() -> Dict[str, float] :abstractmethod: .. py:method:: states_noise() -> Dict[str, float] :abstractmethod: .. py:method:: states_init_error() -> Dict[str, float] :abstractmethod: .. py:method:: x0() -> Dict[str, float] :abstractmethod: .. py:method:: descriptions() -> Dict[str, str] :abstractmethod: .. py:method:: fgcall(host, dae: pydynamicestimator.system.Dae, omega_ref_vec, omega_b) -> None :abstractmethod: Write the PLL state equations into ``dae.f`` and set ``host.omega_pll`` to the estimated synchronizing frequency (read by the angle source via ``host.pll_frequency(dae)``). .. py:method:: finit_sequential(host, dae: pydynamicestimator.system.Dae, Vfd_ext, Vfq_ext) -> Dict[str, numpy.ndarray] :abstractmethod: Steady-state init of the PLL from the filter voltage (decoupled). Returns its state values (e.g. ``epsilon``, ``delta_pll``). The base raises so a PLL without a sequential init falls under the joint init. .. py:class:: SRF_PLL Bases: :py:obj:`PLL` Synchronous-reference-frame PLL: locks the PLL frame to the filter voltage by driving its q-axis component to zero through a PI loop. States: ``epsilon`` (PI integrator), ``delta_pll`` (PLL-frame angle relative to the network). Equivalent to the PLL equations previously hardcoded in ``GridFollowing``; the trajectory is byte-identical. .. py:method:: states() -> List[str] .. py:method:: units() -> List[str] .. py:method:: params() -> Dict[str, float] .. py:method:: states_noise() -> Dict[str, float] .. py:method:: states_init_error() -> Dict[str, float] .. py:method:: x0() -> Dict[str, float] .. py:method:: descriptions() -> Dict[str, str] .. py:method:: fgcall(host, dae: pydynamicestimator.system.Dae, omega_ref_vec, omega_b) -> None Write the PLL state equations into ``dae.f`` and set ``host.omega_pll`` to the estimated synchronizing frequency (read by the angle source via ``host.pll_frequency(dae)``). .. py:method:: finit_sequential(host, dae: pydynamicestimator.system.Dae, Vfd_ext, Vfq_ext) -> Dict[str, numpy.ndarray] PLL lock at steady state: the PLL frame aligns so its q-axis voltage is zero (``Vfq_pll = 0``), the integrator settles (``epsilon = 0``), and ``delta_pll`` is the filter-voltage angle. Solved as a 3x3 Newton for (Vfq_pll, epsilon, delta_pll); the first is an intermediate. .. py:data:: PLL_REGISTRY :type: Dict[str, type]