Toggle Light / Dark / Auto color theme
Toggle table of contents sidebar
Source code for wield.control.fitting.SISO.fitters_rational.rational_disc
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: © 2021 Massachusetts Institute of Technology.
# SPDX-FileCopyrightText: © 2021 Lee McCuller <mcculler@caltech.edu>
# NOTICE: authors should document their contributions in concisely in NOTICE
# with details inline in source files, comments, and docstrings.
"""
"""
import numpy as np
from wield.bunch.depbunch import depB_property , NOARG
from .. import representations
from ..representations.polynomials import standard
from .rational_algorithms import PolyFilterAlgorithms
from .rational_attributes import PolyFit
from .rational_bases import ZFilterBase
[docs]
class RootConstraints ( representations . RootConstraints ):
branch_separated = frozenset ( "branch_separated" )
root_constraints = RootConstraints ()
# must be in this order for the ZPKz to be set in the correct order
[docs]
class RationalDiscFilter ( ZFilterBase , PolyFit , PolyFilterAlgorithms ):
phase_missing = False
poly = standard
stablize_pos_method = "ignore"
stablize_neg_method = "ignore"
@depB_property
def zeros_phase_adjust ( self , val = NOARG ):
if val is NOARG :
return None
else :
return val
@depB_property
def poles_phase_adjust ( self , val = NOARG ):
if val is NOARG :
return None
else :
return val
@depB_property
def zeros_phasing ( self ):
if self . zeros_phase_adjust is None :
return self . Xn_grid ** self . nzeros
elif self . zeros_phase_adjust < 0 :
return self . Xn_grid ** ( self . nzeros + self . zeros_phase_adjust )
else :
return self . Xn_grid ** ( self . zeros_phase_adjust )
return
@depB_property
def poles_phasing ( self ):
if self . poles_phase_adjust is None :
return self . Xn_grid ** self . npoles
elif self . poles_phase_adjust < 0 :
return self . Xn_grid ** ( self . npoles + self . poles_phase_adjust )
else :
return self . Xn_grid ** ( self . poles_phase_adjust )
return
def _phasing_roots ( self , roots ):
return self . Xn_grid ** len ( roots )
def _phasing_vec ( self , vec ):
return self . Xn_grid ** ( len ( vec ) - 1 )
def _phasing_afit ( self ):
return self . poles_phasing
def _phasing_bfit ( self ):
return self . zeros_phasing
[docs]
def root_stabilize (
self ,
rB ,
method = None ,
real_neg = None ,
real_pos = None ,
):
if method is None :
return rB
if real_neg is None :
real_neg = self . stablize_neg_method
if real_pos is None :
real_pos = self . stablize_pos_method
r_r = np . copy ( rB . r )
r_c = np . copy ( rB . c )
if real_neg == "use" :
select_r = r_r < - 1
elif real_neg == "ignore" :
select_r = np . zeros ( r_r . shape , dtype = bool )
else :
raise RuntimeError ( "Bad Argument" )
if real_pos == "use" :
select_r = r_r > 1 | select_r
elif real_pos == "ignore" :
pass
else :
raise RuntimeError ( "Bad Argument" )
select_c = abs ( r_c ) > 1
if method == "flip" :
r_r [ select_r ] = 1 / r_r [ select_r ]
r_c [ select_c ] = 1 / r_c [ select_c ] . conjugate ()
elif method == "remove" :
r_r = r_r [ ~ select_r ]
r_c = r_c [ ~ select_c ]
else :
raise RuntimeError ( "Bad Argument" )
rB = representations . RootBunch (
constraint = self . root_constraint ,
r = r_r ,
c = r_c ,
)
return rB
[docs]
def clear_unstable_poles ( self ):
new_poles = []
for r in self . poles :
if abs ( r ) < 1 :
new_poles . append ( r )
self . poles = new_poles
[docs]
def clear_bigdelay_zeros ( self ):
new_zeros = []
for r in self . zeros :
if abs ( r ) < 1 :
new_zeros . append ( r )
self . zeros = new_zeros
[docs]
def phi_rep_Snative ( self , rB ):
"""
Maps the internal representation to Snative, the output RootBunch can
have a specialty constraint added.
"""
rB = self . RBalgo . expect ( rB , self . RBalgo . root_constraints . mirror_real )
# TODO
# ok to modify?
rB . constraint = rB . constraint | root_constraints . branch_separated
select_pos = rB . r > 0
rB . nyquist_branch = ( - rB . r [ ~ select_pos ] - 1 ) * self . F_nyquist_Hz
rB . r = ( rB . r [ select_pos ] - 1 ) * self . F_nyquist_Hz
real = ( abs ( rB . c ) - 1 ) * self . F_nyquist_Hz
imag = np . angle ( rB . c ) / np . pi * self . F_nyquist_Hz
rB . c = real + 1 j * imag
return rB
[docs]
def phi_Snative_rep ( self , rB ):
""" """
assert root_constraints . mirror_real == (
rB . constraint - root_constraints . branch_separated
)
rB . c = ( 1 + rB . c . real / self . F_nyquist_Hz ) * np . exp (
1 j * rB . c . imag * np . pi / self . F_nyquist_Hz
)
if root_constraints . branch_separated <= rB . constraint :
rB . r = np . concatenate (
[
( rB . r / self . F_nyquist_Hz + 1 ),
- ( rB . nyquist_branch / self . F_nyquist_Hz + 1 ),
]
)
else :
rB . r = rB . r / self . F_nyquist_Hz + 1
rB . constraint = rB . constraint - root_constraints . branch_separated
rB = self . RBalgo . expect ( rB , self . RBalgo . root_constraints . mirror_real )
return rB