Fitting Data and Making FOMs

Here I will go through an example of how to fit data to a transfer function. Later this TF will be used to make a full system model.

First imports:

%load_ext autoreload
%autoreload 2
import numpy as np
import matplotlib.pyplot as plt
import control
import scipy.signal as signal
from scipy import interpolate
import scipy.linalg
from scipy.stats import gmean
import gwinc
import yaml
from wield.iirrational.v2 import data2filter
from wield.control.AAA import tfAAA
from wield.utilities.file_io import load, save
from wield.control.ss_bare.ss import BareStateSpace
from scipy.signal import cheby2
from wield.control import SISO
from buzz import ssutil
from physunits import m, s, kg, Hz
from scipy.constants import c, G
/home/mcculler/local/projects_sync/wield-project-lab/wield-iirrational/src/wield/iirrational/_version.py:35: UserWarning: git base version 0.1 is different than the stored version 2.9.5
  warnings.warn(

Next we will define a function to grab the BNS waveform

# from https://github.com/wield/wield-control/blob/main/src/wield/control/AAA/test/test_AAA_present.py
def gen_waveform(**params):
    """Generate frequency-domain inspiral waveform

    Returns a tuple of (freq, h_plus^tilde, h_cross^tilde).

    The waveform is generated with the lalsimulation
    SimInspiralChooseFDWaveform() function.  Keyword arguments are
    used to update the default waveform parameters (see DEFAULT_PARAMS
    macro).  The mass parameters ('m1' and 'm2') should be specified
    in solar masses and the 'distance' parameter should be specified
    in parsecs**.  Waveform approximants may be given as string names
    (see `lalsimulation` documentation for more info).

    For example, to generate a 20/20 Msolar BBH waveform:

    >>> hp,hc = waveform.gen_waveform('m1'=20, 'm2'=20)

    **NOTE: The requirement that masses be specified in solar masses
    and distances in parsecs is different than that of the underlying
    lalsimulation method which expects mass and distance parameters to
    be in SI units.

    """
    import lalsimulation
    from inspiral_range import waveform
    from inspiral_range import const

    iparams = dict(waveform.DEFAULT_PARAMS)
    iparams.update(**params)

    # convert to SI units
    iparams["distance"] *= const.PC_SI
    iparams["m1"] *= const.MSUN_SI
    iparams["m2"] *= const.MSUN_SI
    iparams["approximant"] = lalsimulation.SimInspiralGetApproximantFromString(
        iparams["approximant"]
    )

    m = iparams["m1"] + iparams["m2"]

    # calculate delta F based on frequency of inner-most stable
    # circular orbit ("fisco")
    fisco = (const.c ** 3) / (const.G * (6 ** 1.5) * 2 * np.pi * m)
    df = 2 ** (np.max([np.floor(np.log(fisco / 4096) / np.log(2)), -6]))

    # FIXME: are these limits reasonable?
    if iparams["deltaF"] is None:
        iparams["deltaF"] = df
    # iparams['f_min'] = 0.1
    # iparams['f_max'] = 10000

    hp, hc = lalsimulation.SimInspiralChooseFDWaveform(**iparams)
    
    freq = hp.f0 + np.arange(len(hp.data.data)) * hp.deltaF

    print("f0", hp.f0)
    select = abs(hp.data.data) > 0

    return freq[select], hp.data.data[select], hc.data.data[select]

Next we will define the parameters of our BNS model and plot its PSD

params = dict()
params["m1"] = 1.4
params["m2"] = 1.4
# rest of params from first BNS detection see https://journals.aps.org/prl/pdf/10.1103/PhysRevLett.119.161101
params["f_min"] = 0.01
params["f_max"] = 1000000
params["deltaF"] = 0.01
params["distance"] = 1e6
F_Hz, hp, hc = gen_waveform(**params) # assuming that this is giving an ASD I.M. Jan 2024

BNS_intrp = interpolate.interp1d(F_Hz, abs(hp)**2) ## we add interpolation to put all of our data with the same FQ spacing

print("F_Hz max", max(F_Hz))

plt.loglog(F_Hz, abs(hp)**2, label = "hp")
plt.loglog(F_Hz, abs(hc)**2, linestyle = ":", label = "hc")
plt.title(str(params["m1"]) +"/"+str(params["m1"])+ "Solarmass BNS Spec")
plt.xlabel("Frequency [Hz]")
plt.ylabel("Power spectral density [strain^2/Hz^2]")
plt.legend()
plt.show()
/opt/conda/user_conda/mcculler/py312/lib/python3.12/site-packages/lalsimulation/lalsimulation.py:8: UserWarning: Wswiglal-redir-stdio:

SWIGLAL standard output/error redirection is enabled in IPython.
This may lead to performance penalties. To disable locally, use:

with lal.no_swig_redirect_standard_output_error():
    ...

To disable globally, use:

lal.swig_redirect_standard_output_error(False)

Note however that this will likely lead to error messages from
LAL functions being either misdirected or lost when called from
Jupyter notebooks.

To suppress this warning, use:

import warnings
warnings.filterwarnings("ignore", "Wswiglal-redir-stdio")
import lal

  import lal
f0 0.0
F_Hz max 14501.800000000001
../../_images/902c24633b551e2140e992b2e213609be1c8c1a89ea2c678e569bb0f466730f1.png
# # compare the waveform with part of equation 3 from https://arxiv.org/abs/1709.08079
m1 = (params["m1"] * 1.988416e30) * kg
m2 = (params["m2"] * 1.988416e30) * kg
chirp_mass = (m1*m2)**(3/5)/(m1+m2)**(1/5)
print('chirpmass: \t', chirp_mass, ' kg\n\t\t', chirp_mass/1.988416e30, ' solar masses')


# N = kg* m/(s**2)
#c = c #* m/s
# G = G * N * m**2 / (kg**2)
# F_Hz = F_Hz * Hz
# eq3 = ((5/24)**0.5 * c * ( G * chirp_mass * (c**3))**(5/6)* 1/(np.pi**(-2/3)))**2 * F_Hz**(-7/3)
# m2Mpc = 1/3.086e22
# eq3_Mpc = eq3

# print("eq3[0]", eq3[0])
# print("eq3_Mpc[0]", eq3_Mpc[0])

# print("BNS hp[0]", abs(hp[0])**2)

# plt.loglog(F_Hz, eq3_Mpc, label="eq3")
# plt.loglog(F_Hz, abs(hp)**2, label="BNS Strain from LAL Simulation")
# plt.title(str(params["m1"]) +"/"+str(params["m1"])+ "Solarmass BNS Spec")
# plt.xlabel("Frequency [Hz]")
# plt.ylabel("Power spectral density [strain^2/Hz^2]")
# plt.legend()
# plt.show()
chirpmass: 	 2.423423336413827e+30  kg
		 1.2187707886145691  solar masses

Getting the LIGO Sensitivity Curve

Now I must multiply this by the GWINC curve to get our final FOM

F_bug = np.logspace(np.log10(min(F_Hz)), np.log10(max(F_Hz)-1), 10000)
budget = gwinc.load_budget('aLIGO', freq=F_bug)
trace = budget.run(freq=F_bug)

plt.title("ALIGO BUDGET")
plt.loglog(F_bug, trace.psd)
plt.xlabel("Frequency [Hz]")
plt.ylabel("Power Spectral Density [strain/hz]")
# plt.xlim([6, max(F_Hz)])
# plt.ylim([1e-20, 1e-17])
Text(0, 0.5, 'Power Spectral Density [strain/hz]')
../../_images/7a4f2617a6de652a26cbac89a8fbb72acaca957399a105e443795b70c5913ed9.png
prefactor = (2*(5/96)**0.5 * c * ( G * chirp_mass * (c**3))**(5/6) * 1/(np.pi**(-2/3))* 2 / 2.26)**2 
I7 = np.trapz(F_bug**(-7/3)/trace.psd, F_bug)
eq3 = prefactor * I7**0.5
print("eq3: ", eq3/3.086e22, ' Mpc')
eq3:  4.867082672729032e+92  Mpc
/tmp/ipykernel_1398697/2399436929.py:2: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.
  I7 = np.trapz(F_bug**(-7/3)/trace.psd, F_bug)
from inspiral_range import inspiral_range as ir
from inspiral_range import waveform
from inspiral_range import const

DETECTION_SNR = 8.0
def ian_sensemon_range(freq, m1=1.4, m2=1.4, horizon=False, integrate=False, detection_snr=DETECTION_SNR):
    """Detector inspiral range from closed form expression

    Masses `m1` and `m2` should be specified in solar masses (default:
    m1=m2=1.4).  If the `horizon` keyword is specified the "horizon"
    range will be returned, which differs from the angle-averaged
    range by ~2.26.

    @returns distance in Mpc as a float

    """
    if horizon:
        theta = 4
    else:
        theta = 1.77
    theta /= 1e6 * const.PC_SI
    M_chirp = waveform.M_chirp(m1, m2) * const.MSUN_SI

    i73 = freq ** (-7/3)
    val = theta / detection_snr \
        * waveform.habs_nsp_prefactor(M_chirp) \
        * np.sqrt(i73) / 2

    return val
irdata = ian_sensemon_range(F_bug, integrate=False, horizon=True)**2

range_ir = ir.sensemon_range(F_bug, psd=trace.psd, m1=1.4, m2=1.4, horizon=False, integrate=True, detection_snr=DETECTION_SNR)
print("range: ", range_ir)

#np.savetxt('FBNS_Current_range.txt', [range])

BNS_PSD = BNS_intrp(F_bug)
IR_interp = interpolate.interp1d(F_bug, irdata)

midpoint = len(F_bug)//2
print('relative difference: ', BNS_PSD[midpoint]/irdata[midpoint])


plt.loglog(F_bug, BNS_PSD)
plt.loglog(F_bug, irdata)
plt.scatter(F_bug[midpoint], BNS_PSD[midpoint])
plt.scatter(F_bug[midpoint], irdata[midpoint])
plt.xlabel("Frequency [Hz]")
plt.ylabel("Power spectral density");
range:  194.97198453267936
relative difference:  15.834426264720078
../../_images/5cf3a6f6e8931851c90323cf76534686fbd7d1a6c33c2b811482f193c125cccf.png

Choose which inspiral waveform PSD to use

#BNS_PSD = BNS_intrp(F_bug) # us the custom inspiral equatin from LAL
BNS_PSD = IR_interp(F_bug) # use the inspiral range aproximation and calibration 

Now I will put the BNS waveform in the Fq space of the GWINC curve

print("BNS_PSD", BNS_PSD)
print("irdata", irdata)
plt.loglog(F_bug, BNS_PSD)
plt.xlabel("Frequency [Hz]")
plt.ylabel("Power spectral density")
BNS_PSD [2.45847163e-35 2.45034592e-35 2.44224707e-35 ... 1.03982333e-49
 1.03638652e-49 1.03296107e-49]
irdata [2.45847163e-35 2.45034592e-35 2.44224707e-35 ... 1.03982333e-49
 1.03638652e-49 1.03296107e-49]
Text(0, 0.5, 'Power spectral density')
../../_images/dfbe6686801454e930ccbe674884958aab4c8366e530ad43ea3d58ba516f494a.png

Lastly for this step we will combine the twu curves to make a FOM. we divide the BNS PSD by the LIGO Noise spectrum without the controls noise. From the paper: $$\mathrm{SNR}^2 = 4\int_{0}^{\infty} \frac{\left |h_\mathrm{gw}(f)\right |^2}{S_h(f)} df$$

where $S_h(f)$ is the noise spectrum of the detector. This can be written as:

$$ S_h(f) = S_{\mathrm{det}}(f) + |C(f)|^2 S_{\mathrm{p}}(f)$$

where $S_{\mathrm{det}}(f)$ is the detector noise spectrum without controls noise, $S_{\mathrm{p}}(f)$ is the control noise spectrum, and $C(f)$ is the coupling function from the controls noise in the control loop to DARM. By using the taylor series of A/(B+x) to linearize the integral. i.e.:

$$\frac{A}{B+x}=\frac{A}{B} - \frac{Ax}{B^2} + \frac{Ax^2}{B^3} - \frac{Ax^3}{B^4} + \frac{Ax^4}{B^5} - \frac{Ax^5}{B^6} + O(x^6)$$

taking the first two terms of the taylor series and applying it to the SNR equation we get:

$$\mathrm{SNR}^2 = 4\int_{0}^{\infty} \frac{\left | h_{\mathrm{signal}}(f)\right |^2}{S_{\mathrm{det}}(f)} \ df - 4\int_{0}^{\infty} \frac{\left |C\right |^2\left | h_{\mathrm{signal}}(f)\right |^2 }{S_{\mathrm{det}}(f)^2} S_{\mathrm{p}}(f) \ df$$

To get range we need to use the $\mathrm{SNR}$ not the $\mathrm{SNR}^2$ so we take the square root of the above equation which has a different linearization. as $A \rightarrow \infty$

$$\sqrt{A+B} = \sqrt{A} \sqrt{1+\frac{B}{A}} = \sqrt{A} (1+\frac{B}{2 \sqrt{A}})$$

Div_PSD = BNS_PSD / (trace.psd)**2 # divide the BNS PSD by the aLIGO noise psd squared. this will give a PSD of LIGO's sensitivity to a BNS signal
#Div_PSD = Div_PSD * 4000**2 # to put it in units of displacement
F_Div = F_bug
plt.loglog(F_Div, Div_PSD)
plt.xlabel("Frequency [Hz]")
plt.ylabel("Power spectral density")
plt.title("PSD of FOM for BNS Signal")
Text(0.5, 1.0, 'PSD of FOM for BNS Signal')
../../_images/3f64dcbb5eee779c0fecb4440625e0f08888d4302a968bb85b6e293a78eec7f0.png

Fitting the Data to a Transfer Function

First we will Define a function to reduce the number of points to fit to

# edited from https://git.ligo.org/wield/wield-ligo-mcculler/-/blob/main/src/wield/LIGO/mcculler/filter_cavity/test_FC1_SUSPOINT_fits.py
def reduce(F_Hz, PSD):
    F_groups = np.logspace(-2, 4, 50) # originally 200 length
    F_groups = np.geomspace(min(F_Hz), max(F_Hz), 50) # originally 200 length
    
    idx_groups = np.searchsorted(F_Hz, F_groups)
    idx_pairs = list(zip(idx_groups[:-1], idx_groups[1:]))

    lPSDs_min = []
    lPSDs_max = []
    lPSDs_med = []
    lPSDs_mean = []
    lF_Hz = []
    for idx1, idx2 in idx_pairs:
        if idx1 == idx2:
            continue
        lPSDs_max.append(
            np.nanmax(PSD[idx1:idx2])
        )
        lPSDs_med.append(
            np.nanmedian(PSD[idx1:idx2])
        )
        lPSDs_min.append(
            np.nanmin(PSD[idx1:idx2])
        )
        lPSDs_mean.append(
            np.nanmean(PSD[idx1:idx2])
        )
        lF_Hz.append(np.mean(F_Hz[idx1:idx2]))

    return np.asarray(lF_Hz), np.asarray(lPSDs_min), np.asarray(lPSDs_med), np.asarray(lPSDs_max), np.asarray(lPSDs_mean)

Now we will reduce the LIGO sensitivity curve and its reduced form

F_FOM_dwn, PSD_min, PSD_med, PSD_max, PSD_mean = reduce(F_bug, Div_PSD)
FOM_PSD = PSD_mean
# The current form of FOM_PSD is the ASD
FOM_ASD = FOM_PSD**0.5

plt.loglog(F_bug, Div_PSD**0.5, label = 'FOM ASD')
plt.loglog(F_FOM_dwn, FOM_ASD, label = 'Downsampled FOM ASD')
plt.legend()
<matplotlib.legend.Legend at 0x7fad19ccbd40>
../../_images/e6a20221495a8d10927d6be2958cd4ad83ecb2293d7285dab498c3c365fb434e.png

Now we will define some functions to work with these transfer functions

def FBNSsimpSS(gain=1, return_name=False, lo_ord=4):
    if return_name:
        name = "FOM BNS Simple"
        return name
    F_Fq_lo = 10 * 2 * np.pi
    F_Fq_hi = 120 * 2 * np.pi
    hp_order = lo_ord
    lp_order = 2
    F_p = []
    F_z = []
    for ord in range(hp_order):
        F_p.append(-F_Fq_lo + 0*1j*F_Fq_lo)
        F_p.append(-F_Fq_lo - 0*1j*F_Fq_lo)
        F_z.append(0)
        F_z.append(0)

    for ord in range(lp_order):
        F_p.append(-F_Fq_hi)
    F_k = 1
    c_zpk = cheby2(8, 170, 1.25*2*np.pi, btype='high', analog=True, output='zpk')
    F_z.extend(c_zpk[0])
    F_p.extend(c_zpk[1])
    F_k *= c_zpk[2]

    ian_lfq = -0.7
    ian_lfq2 = 2
    ian_lfq3 = 0.5
    F_z.append(0)
    F_p.append(ian_lfq)
    F_z.append(0)
    F_p.append(ian_lfq)

    F_z.append(ian_lfq3)
    F_z.append(ian_lfq3)
    F_p.append(ian_lfq2)
    F_p.append(ian_lfq2)
    
    F_p = F_p
    F_z = F_z

    #F_mod = ws_tf2ss(F_z, F_p, F_k)
    #F_mod = ssutil.normalize_gain(F_mod) * gain 
    #F_iod = {"FBNS.in": 0, "FBNS.out": 0}
    F_mod = SISO.zpk(F_z, F_p, F_k, angular=True, fiducial_rtol=1e-5, fiducial_atol=1e-10)
    F_mod = F_mod * F_mod
    F_mod = F_mod.asSS
    F_mod = F_mod / abs(F_mod.asSS.Linf_norm()[0]) 


    F_mod = F_mod * gain
    F_mod.balance_and_truncate()

    #F = ssutil.wieldSS(F_mod, F_iod)
    
    return F_mod.mimo("FBNS.in", "FBNS.out")

plt.loglog(F_bug, Div_PSD**0.5, label = 'FOM ASD')
plt.loglog(F_FOM_dwn, FOM_ASD, label = 'Downsampled FOM ASD')
mag, phase, omega = control.bode(FBNSsimpSS(gain=4 * 100**2).mod, Hz=False, plot=False, omega=F_FOM_dwn*2*np.pi, label = "BNS Simple")
#plt.loglog(omega/(2*np.pi), mag, label="BNS Simple")
plt.legend()
/home/mcculler/local/projects_sync/wield-project-lab/wield-control/src/wield/control/SISO/zpk.py:164: NumericalWarning: StateSpace is large (>50 states), using reduced response fiducial auditing heuristics. TODO to make this smarter
  warnings.warn(f"StateSpace is large (>{self.N_MAX_FID} states), using reduced response fiducial auditing heuristics. TODO to make this smarter", util.NumericalWarning)
/opt/conda/user_conda/mcculler/py312/lib/python3.12/site-packages/control/freqplot.py:435: FutureWarning: bode_plot() return value of mag, phase, omega is deprecated; use frequency_response()
  warnings.warn(
<matplotlib.legend.Legend at 0x7fad1bb86ba0>
../../_images/e6a20221495a8d10927d6be2958cd4ad83ecb2293d7285dab498c3c365fb434e.png
from scipy.signal import cheby2
from wield.control import SISO

def FBNSsimpSS(gain=1, return_name=False, lo_ord=4, return_scale=False):
    if return_name:
        name = "FOM BNS Simple"
        return name
    
    F_Fq_lo = 40 * 2 * np.pi
    # aggressive version
    # F_Fq_lo = 30 * 2 * np.pi
    F_Fq_hi = 300 * 2 * np.pi
    hp_order = 1 #lo_ord
    lp_order = 2
    F_p = []
    F_z = []
    for ord in range(hp_order):
        F_p.append(-F_Fq_lo + 0*1j*F_Fq_lo)
        F_p.append(-F_Fq_lo - 0*1j*F_Fq_lo)
        F_z.append(0)
        F_z.append(0)
    for ord in range(lp_order):
        F_p.append(-F_Fq_hi)
    F_k = gain * 1.5e19
    c_zpk = cheby2(8, 160, 4*2*np.pi, btype='high', analog=True, output='zpk')
    # aggressive version
    # c_zpk = cheby2(8, 120, 4*2*np.pi, btype='high', analog=True, output='zpk')
    F_z.extend(c_zpk[0])
    F_p.extend(c_zpk[1])
    F_k *= c_zpk[2]
    
    F = SISO.zpk(F_z, F_p, F_k)
    return F*F
sys_FBNS_simp = FBNSsimpSS()

zpk_dict = {
            'z' : [str(zero) for zero in np.asarray(tuple(sys_FBNS_simp.z)).tolist()],
            'p' : [str(pole) for pole in np.asarray(tuple(sys_FBNS_simp.p)).tolist()],
            'k' : float(sys_FBNS_simp.k)
            }

save('FBNSsimp_FOM.yml', zpk_dict)
with open('BNS_FOM_handfit.yml', 'r') as file:
    filt_dict = yaml.safe_load(file)
p_hand = np.array(filt_dict['p'], dtype=np.complex128)
z_hand = np.array(filt_dict['z'], dtype=np.complex128)
k_hand = np.float64(filt_dict['k'])

hand_zpk = SISO.zpk(z_hand, p_hand, k_hand)
hand_xfr = hand_zpk.fresponse(f=F_FOM_dwn)
BNSsimp_xfr = sys_FBNS_simp.fresponse(f=F_FOM_dwn)

plt.loglog(F_bug, Div_PSD**0.5, label = 'FOM ASD')
plt.loglog(F_FOM_dwn, FOM_ASD, label = 'Downsampled FOM ASD')
plt.loglog(F_FOM_dwn, hand_xfr.mag, label = 'Handfit ASD')
plt.loglog(F_FOM_dwn, BNSsimp_xfr.mag, label = 'BNSSimp ASD')
plt.legend()
/home/mcculler/local/projects_sync/wield-project-lab/wield-control/src/wield/control/SISO/zpk.py:164: NumericalWarning: StateSpace is large (>50 states), using reduced response fiducial auditing heuristics. TODO to make this smarter
  warnings.warn(f"StateSpace is large (>{self.N_MAX_FID} states), using reduced response fiducial auditing heuristics. TODO to make this smarter", util.NumericalWarning)
<matplotlib.legend.Legend at 0x7fad07144c20>
../../_images/9062e1e11634bba851695354024f43def54d45baae2c2ff7eb39a79fbc70bbdc.png
# Divide the FOM ASD by the hand fit to get the reduced ASD
reduced_ASD = FOM_ASD/hand_xfr.mag

plt.loglog(F_FOM_dwn, reduced_ASD, label = 'reduced ASD')
plt.legend()
<matplotlib.legend.Legend at 0x7fad19c22480>
../../_images/5ab8449f1e78dc3b5954edbd799f15f12581d78b9ce01fd62c0baad7fe73a194.png

Now we form a guess of the TF

#results = tfAAA(F_Hz=F_FOM_dwn, xfer=FOM_ASD)
results = tfAAA(F_Hz=F_FOM_dwn, xfer=reduced_ASD)

Now we play with the poles and zeros to get a good fit

#print("poles", results.poles)
#print("zeros", results.zeros)
#print("gain", results.gain)

all_z = results.zeros
all_p = results.poles
k = results.gain

for i in range(0, len(all_z)):
    if all_z[i] >= 0:
        all_z[i] = -all_z[i]
        
for i in range(0, len(all_p)):
    if all_p[i] >= 0:
        all_p[i] = -all_p[i]

AAA_zpk = SISO.zpk(all_z, all_p, k, angular=False, fiducial_rtol=1e-5, fiducial_atol=1e-10)
recalibrated_zpk =  hand_zpk * AAA_zpk 
# recalibrated_zpk =  AAA_zpk 
print(recalibrated_zpk.zeros)
2π·[-0.3958406743523140, -0.3958406743523140, -0.3958406743523140,
 -0.3958406743523140, -0.3958406743523140, -0.3958406743523140,
 -0.3958406743523140, -0.3958406743523140, -0.3958406743523140,
 -0.3958406743523140, -0.3958406743523140, -0.3958406743523140,
 -0.3958406743523140, -0.3958406743523140, -0.3958406743523140,
 -0.3958406743523140, -0.3958406743523140, -0.3958406743523140,
 -5.305505757497158e-10, -0.005431630862136328, -0.005431630295139218,
 -0.04216327861663196, -0.04216327868321049, -3.049643520855844,
 -3.049643519812004, -2707.242418662691, -2707.242418662458,
 -2.957619742415325e-12 ± 92.58406532411048j,
 -14.98934980857282     ± 21.76848865621670j,
 -14.98934980875151     ± 21.76848865620463j,
 -2.069960897503006e-10 ± 10.00487816878042j,
 -1.178440698489668e-11 ± 2.829913488939144j,
 -1.029654952340069e-11 ± 1.332579977525743j,
 -0.01709138866381974   ± 0.2654485123713641j,
 -0.01709138868276358   ± 0.2654485123375496j,
 -6.152212595327936e-12 ± 0.3571372397086687j,
 -0.4720203451684382    ± 2.629597995989603j,
 -0.4720203452849284    ± 2.629597996216710j]
plt.loglog(F_FOM_dwn, reduced_ASD, label = 'Reduced ASD')
plt.loglog(F_bug, AAA_zpk.fresponse(f=F_bug).mag, label = 'AAA Fit', linestyle = '--')
plt.legend()
<matplotlib.legend.Legend at 0x7fad196fca70>
../../_images/e4f1056665bf43df76a1af364d5e9d4b9f07e0d2a3e478e2bd2ce0a8d608219f.png
# Get the ZPK and the minreal ZPK for all poles and zeros
B_res_all = control.zpk(all_z, all_p, k)
B_res_all_minreal = control.minreal(B_res_all)
minreal_all_z, minreal_all_p, minreal_all_k = signal.tf2zpk(B_res_all_minreal.num[0][0], B_res_all_minreal.den[0][0])

# Get only the real poles and zeros
z = [lz for lz in all_z if lz.real < 0]
p = [lp for lp in all_p if lp.real < 0]

# Get the ZPK for the real poles and zeros and the minreal ZPK for only the real poles and zeros
B_res = control.zpk(z, p, k)
B_res_minreal = control.minreal(B_res)
minreal_z, minreal_p, minreal_k = signal.tf2zpk(B_res_minreal.num[0][0], B_res_minreal.den[0][0])
0 states have been removed from the model
0 states have been removed from the model
/opt/conda/user_conda/mcculler/py312/lib/python3.12/site-packages/control/xferfcn.py:1087: ComplexWarning: Casting complex values to real discards the imaginary part
  den[j, :maxindex+1] = poly(poles[j])
/opt/conda/user_conda/mcculler/py312/lib/python3.12/site-packages/control/xferfcn.py:1117: ComplexWarning: Casting complex values to real discards the imaginary part
  num[i, j, maxindex+1-len(numpoly):maxindex+1] = numpoly

Now we will plot our guess and our othe tfs

_, TF_all = scipy.signal.freqs_zpk(all_z, all_p, k, worN = F_Hz)
_, TF_minreal = scipy.signal.freqs_zpk(minreal_all_z, minreal_all_p, minreal_all_k, worN = F_Hz)

recalibrated_zpk_xfr = recalibrated_zpk.fresponse(f=F_Hz)

plt.loglog(F_bug, Div_PSD**0.5, label = 'Full FOM ASD')
plt.loglog(F_FOM_dwn, hand_xfr.mag, label = 'Handfit ASD')
plt.loglog(F_Hz, recalibrated_zpk_xfr.mag, label = 'Recalibrated AAA')
plt.loglog(F_FOM_dwn, FOM_ASD, label = 'Downsampled FOM ASD')
#plt.loglog(F_Hz, abs(TF_all), label = 'ALL ZPK Fit Bary. (order {})'.format(results.order))
#plt.loglog(F_Hz, abs(TF_minreal), label = 'Minreal ALL ZPK Fit Bary.', linestyle = '--')
plt.legend()
<matplotlib.legend.Legend at 0x7fad1898d460>
../../_images/cf92ad7b9d0166af591c821c0d124df7456a1e6c5c04447b303d10da07c978d0.png

Now we fit for the poles and zeros

snr = np.ones_like(F_FOM_dwn)
snr[:-1] = (F_FOM_dwn[1:] - F_FOM_dwn[:-1])**-0.001
from wield.iirrational import fitters_ZPK

all_z = (np.array(recalibrated_zpk.zeros))
all_p = (np.array(recalibrated_zpk.poles))
k = float(recalibrated_zpk.k)

z_iir = tuple(np.array(all_z) / (np.pi * 2))
p_iir = tuple(np.array(all_p) / (np.pi * 2))
print(z_iir)
print(p_iir)

iir_results = data2filter(
    F_Hz=F_FOM_dwn,
    xfer=FOM_ASD,
    #xfer=reduced_ASD,
    mode='reduce',
    zeros=z_iir, 
    poles=p_iir,
    gain=k * (2*np.pi)**(len(z_iir) - len(p_iir)),
    SNR_phase_rel=0,
    SNR=snr,
    #relative_degree=-4,
    # resavg_RthreshOrdDn=1.01,
    baseline_only=True,
    #coding_map=fitters_ZPK.codings_s.coding_maps.RI
    # trust_SNR = True,
)
print("C", iir_results.fit_aid._fitters[0].fitter.poles.fullplane)
print(tuple(np.array(all_p) / (np.pi * 2)))
(np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-0.395840674352314), np.float64(-5.305505757497158e-10), np.float64(-0.005431630862136328), np.float64(-0.005431630295139218), np.float64(-0.04216327861663196), np.float64(-0.042163278683210494), np.float64(-3.0496435208558443), np.float64(-3.049643519812004), np.float64(-2707.2424186626913), np.float64(-2707.242418662458), np.complex128(-2.957619742415325e-12+92.58406532411048j), np.complex128(-2.957619742415325e-12-92.58406532411048j), np.complex128(-14.989349808572818+21.768488656216697j), np.complex128(-14.989349808572818-21.768488656216697j), np.complex128(-14.989349808751511+21.768488656204628j), np.complex128(-14.989349808751511-21.768488656204628j), np.complex128(-2.0699608975030063e-10+10.004878168780424j), np.complex128(-2.0699608975030063e-10-10.004878168780424j), np.complex128(-1.1784406984896683e-11+2.8299134889391437j), np.complex128(-1.1784406984896683e-11-2.8299134889391437j), np.complex128(-1.0296549523400693e-11+1.3325799775257434j), np.complex128(-1.0296549523400693e-11-1.3325799775257434j), np.complex128(-0.017091388663819738+0.2654485123713641j), np.complex128(-0.017091388663819738-0.2654485123713641j), np.complex128(-0.017091388682763577+0.2654485123375496j), np.complex128(-0.017091388682763577-0.2654485123375496j), np.complex128(-6.152212595327936e-12+0.3571372397086687j), np.complex128(-6.152212595327936e-12-0.3571372397086687j), np.complex128(-0.4720203451684382+2.629597995989603j), np.complex128(-0.4720203451684382-2.629597995989603j), np.complex128(-0.47202034528492837+2.6295979962167104j), np.complex128(-0.47202034528492837-2.6295979962167104j))
(np.float64(-200.0), np.float64(-200.0), np.float64(-1999.9999999999998), np.float64(-1.1743521290869434e-10), np.float64(-0.011159044867910854), np.float64(-0.011159044751801689), np.float64(-1302.7841836435434), np.float64(-1302.7841836432744), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-1.276683601197908e-11+91.63193908076074j), np.complex128(-1.276683601197908e-11-91.63193908076074j), np.complex128(-18.709468807770158+25.224614971813303j), np.complex128(-18.709468807770158-25.224614971813303j), np.complex128(-18.709468807798835+25.224614971785446j), np.complex128(-18.709468807798835-25.224614971785446j), np.complex128(-3.5224484988923e-11+10.490717255985867j), np.complex128(-3.5224484988923e-11-10.490717255985867j), np.complex128(-7.755934678337948e-12+2.81092371100195j), np.complex128(-7.755934678337948e-12-2.81092371100195j), np.complex128(-3.1553850493935663e-12+1.2246948964676j), np.complex128(-3.1553850493935663e-12-1.2246948964676j), np.complex128(-8.200117750311727e-13+0.29012748368774854j), np.complex128(-8.200117750311727e-13-0.29012748368774854j), np.complex128(-0.03924083547004946+0.07982846579002265j), np.complex128(-0.03924083547004946-0.07982846579002265j), np.complex128(-0.0392408354694464+0.07982846579497013j), np.complex128(-0.0392408354694464-0.07982846579497013j), np.complex128(-4.26914787276891e-11+0.5783185011865986j), np.complex128(-4.26914787276891e-11-0.5783185011865986j), np.complex128(-4.995095343193837e-11+0.6196917699694076j), np.complex128(-4.995095343193837e-11-0.6196917699694076j), np.complex128(-0.7658207288552369+6.119579611317334j), np.complex128(-0.7658207288552369-6.119579611317334j), np.complex128(-0.7658207289076394+6.119579611415145j), np.complex128(-0.7658207289076394-6.119579611415145j))
TEE_LOGFILE None
A [-2.00000000e+02+0.00000000e+00j -2.00000000e+02+0.00000000e+00j
 -2.00000000e+03+0.00000000e+00j -1.17435213e-10+0.00000000e+00j
 -1.11590449e-02+0.00000000e+00j -1.11590448e-02+0.00000000e+00j
 -1.30278418e+03+0.00000000e+00j -1.30278418e+03+0.00000000e+00j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -1.27668360e-11+9.16319391e+01j -1.27668360e-11-9.16319391e+01j
 -1.87094688e+01+2.52246150e+01j -1.87094688e+01-2.52246150e+01j
 -1.87094688e+01+2.52246150e+01j -1.87094688e+01-2.52246150e+01j
 -3.52244850e-11+1.04907173e+01j -3.52244850e-11-1.04907173e+01j
 -7.75593468e-12+2.81092371e+00j -7.75593468e-12-2.81092371e+00j
 -3.15538505e-12+1.22469490e+00j -3.15538505e-12-1.22469490e+00j
 -8.20011775e-13+2.90127484e-01j -8.20011775e-13-2.90127484e-01j
 -3.92408355e-02+7.98284658e-02j -3.92408355e-02-7.98284658e-02j
 -3.92408355e-02+7.98284658e-02j -3.92408355e-02-7.98284658e-02j
 -4.26914787e-11+5.78318501e-01j -4.26914787e-11-5.78318501e-01j
 -4.99509534e-11+6.19691770e-01j -4.99509534e-11-6.19691770e-01j
 -7.65820729e-01+6.11957961e+00j -7.65820729e-01-6.11957961e+00j
 -7.65820729e-01+6.11957961e+00j -7.65820729e-01-6.11957961e+00j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j]
B [-2.00000000e+03+0.00000000e+00j -3.90376294e-03+0.00000000e+00j
 -1.30278418e+03+2.64289979e-05j -1.30278418e+03-2.64289979e-05j
 -1.11590448e-02+1.16415322e-10j -1.11590448e-02-1.16415322e-10j
 -2.00000000e+02+3.81469727e-06j -2.00000000e+02-3.81469727e-06j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -7.65820729e-01+6.11957961e+00j -7.65820729e-01-6.11957961e+00j
 -7.65820729e-01+6.11957961e+00j -7.65820729e-01-6.11957961e+00j
 -4.64082010e-04+6.19691770e-01j -4.64082010e-04-6.19691770e-01j
 -4.33097913e-04+5.78318501e-01j -4.33097913e-04-5.78318501e-01j
 -3.92408355e-02+7.98284658e-02j -3.92408355e-02-7.98284658e-02j
 -3.92408355e-02+7.98284658e-02j -3.92408355e-02-7.98284658e-02j
 -9.04325228e-03+2.90127484e-01j -9.04325228e-03-2.90127484e-01j
 -8.84127110e-02+1.22469490e+00j -8.84127110e-02-1.22469490e+00j
 -2.88099878e-03+2.81092371e+00j -2.88099878e-03-2.81092371e+00j
 -3.07907738e+00+1.04907173e+01j -3.07907738e+00-1.04907173e+01j
 -1.87094688e+01+2.52246150e+01j -1.87094688e+01-2.52246150e+01j
 -1.87094688e+01+2.52246150e+01j -1.87094688e+01-2.52246150e+01j
 -2.69399238e+01+9.16319391e+01j -2.69399238e+01-9.16319391e+01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j]
/home/mcculler/local/projects_sync/wield-project-lab/wield-iirrational/src/wield/iirrational/fitters_ZPK/codings_s/cplx_sos_NL.py:176: RuntimeWarning: divide by zero encountered in scalar divide
  V_D_c1 = -pD_c1 * c1 / disc * V_D
/home/mcculler/local/projects_sync/wield-project-lab/wield-iirrational/src/wield/iirrational/fitters_ZPK/codings_s/cplx_sos_NL.py:176: RuntimeWarning: invalid value encountered in scalar multiply
  V_D_c1 = -pD_c1 * c1 / disc * V_D
/home/mcculler/local/projects_sync/wield-project-lab/wield-iirrational/src/wield/iirrational/fitters_ZPK/codings_s/cplx_sos_NL.py:177: RuntimeWarning: divide by zero encountered in scalar divide
  V_D_c2 = -pD_c2 / (2 * disc) * V_D
/home/mcculler/local/projects_sync/wield-project-lab/wield-iirrational/src/wield/iirrational/fitters_ZPK/codings_s/cplx_sos_NL.py:177: RuntimeWarning: invalid value encountered in scalar multiply
  V_D_c2 = -pD_c2 / (2 * disc) * V_D
3W   0.56  Fitter_checkpoint improvement succeed, None
------------:Q-ranked order reduction:
4P   1.13    order reduced annealing
3W   3.35    Fitter_checkpoint improvement succeed, None
3W   7.24  Fitter_checkpoint improvement succeed, None
5P   7.25  zero flipping, maxzp 44, residuals=-1.04e-01, -1.04e-01, reldeg=-3
5P   7.80  zero flipped, maxzp 44, residuals=-1.02e-01, reldeg=-3
5P   8.60  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P   9.30  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P   9.77  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  10.69  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  11.89  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  12.52  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  13.09  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  13.91  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  14.55  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  14.94  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  15.45  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  16.18  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  16.60  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  16.79  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  16.99  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  17.22  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  17.35  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  17.54  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  18.09  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  18.35  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  18.68  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  18.98  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  19.32  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  19.65  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  20.06  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  20.33  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  20.76  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  21.65  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
5P  21.86  zero flipped, maxzp 44, residuals=-1.01e-01, reldeg=-3
2A  88.66  Baseline fit residuals: -1.01e-01, at order 44
BASELINE:  44
------------:investigations:
2I  88.68    max(z, p)       ChiSq.
                   order    avg. res.    med. res.    max. res.
             -----------  -----------  -----------  -----------
                      42    -0.132534    0.0284283      1.05963
                      52    -0.136876    0.011756       4.5478
C [-2.00000000e+03+0.00000000e+00j -3.90376294e-03+0.00000000e+00j
 -1.30278418e+03+2.64289979e-05j -1.30278418e+03-2.64289979e-05j
 -1.11590448e-02+1.16415322e-10j -1.11590448e-02-1.16415322e-10j
 -2.00000000e+02+3.81469727e-06j -2.00000000e+02-3.81469727e-06j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j
 -7.65820729e-01+6.11957961e+00j -7.65820729e-01-6.11957961e+00j
 -7.65820729e-01+6.11957961e+00j -7.65820729e-01-6.11957961e+00j
 -4.64082010e-04+6.19691770e-01j -4.64082010e-04-6.19691770e-01j
 -4.33097913e-04+5.78318501e-01j -4.33097913e-04-5.78318501e-01j
 -3.92408355e-02+7.98284658e-02j -3.92408355e-02-7.98284658e-02j
 -3.92408355e-02+7.98284658e-02j -3.92408355e-02-7.98284658e-02j
 -9.04325228e-03+2.90127484e-01j -9.04325228e-03-2.90127484e-01j
 -8.84127110e-02+1.22469490e+00j -8.84127110e-02-1.22469490e+00j
 -2.88099878e-03+2.81092371e+00j -2.88099878e-03-2.81092371e+00j
 -3.07907738e+00+1.04907173e+01j -3.07907738e+00-1.04907173e+01j
 -1.87094688e+01+2.52246150e+01j -1.87094688e+01-2.52246150e+01j
 -1.87094688e+01+2.52246150e+01j -1.87094688e+01-2.52246150e+01j
 -2.69399238e+01+9.16319391e+01j -2.69399238e+01-9.16319391e+01j
 -8.48230016e+00+8.48230016e-01j -8.48230016e+00-8.48230016e-01j]
(np.float64(-200.0), np.float64(-200.0), np.float64(-1999.9999999999998), np.float64(-1.1743521290869434e-10), np.float64(-0.011159044867910854), np.float64(-0.011159044751801689), np.float64(-1302.7841836435434), np.float64(-1302.7841836432744), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-8.482300164692441+0.8482300164692441j), np.complex128(-8.482300164692441-0.8482300164692441j), np.complex128(-1.276683601197908e-11+91.63193908076074j), np.complex128(-1.276683601197908e-11-91.63193908076074j), np.complex128(-18.709468807770158+25.224614971813303j), np.complex128(-18.709468807770158-25.224614971813303j), np.complex128(-18.709468807798835+25.224614971785446j), np.complex128(-18.709468807798835-25.224614971785446j), np.complex128(-3.5224484988923e-11+10.490717255985867j), np.complex128(-3.5224484988923e-11-10.490717255985867j), np.complex128(-7.755934678337948e-12+2.81092371100195j), np.complex128(-7.755934678337948e-12-2.81092371100195j), np.complex128(-3.1553850493935663e-12+1.2246948964676j), np.complex128(-3.1553850493935663e-12-1.2246948964676j), np.complex128(-8.200117750311727e-13+0.29012748368774854j), np.complex128(-8.200117750311727e-13-0.29012748368774854j), np.complex128(-0.03924083547004946+0.07982846579002265j), np.complex128(-0.03924083547004946-0.07982846579002265j), np.complex128(-0.0392408354694464+0.07982846579497013j), np.complex128(-0.0392408354694464-0.07982846579497013j), np.complex128(-4.26914787276891e-11+0.5783185011865986j), np.complex128(-4.26914787276891e-11-0.5783185011865986j), np.complex128(-4.995095343193837e-11+0.6196917699694076j), np.complex128(-4.995095343193837e-11-0.6196917699694076j), np.complex128(-0.7658207288552369+6.119579611317334j), np.complex128(-0.7658207288552369-6.119579611317334j), np.complex128(-0.7658207289076394+6.119579611415145j), np.complex128(-0.7658207289076394-6.119579611415145j))
3W  88.65  Fitter_checkpoint improvement succeed, None
iir_results.fit_aid._fitters
[Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19543fe0>,
     log_idx = 0,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19b17530>,
     log_idx = 1,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1879d070>,
     log_idx = 12,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1879db20>,
     log_idx = 14,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad187db170>,
     log_idx = 36,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad187da210>,
     log_idx = 38,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18cab770>,
     log_idx = 62,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18700740>,
     log_idx = 73,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18703620>,
     log_idx = 75,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186412e0>,
     log_idx = 100,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18760cb0>,
     log_idx = 101,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18643e00>,
     log_idx = 126,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad189d49b0>,
     log_idx = 127,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18641700>,
     log_idx = 152,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad187d9970>,
     log_idx = 153,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18643d10>,
     log_idx = 178,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18ae9df0>,
     log_idx = 179,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18640bc0>,
     log_idx = 204,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18641cd0>,
     log_idx = 205,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18641e50>,
     log_idx = 230,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad187da180>,
     log_idx = 231,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186a1040>,
     log_idx = 256,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad201cba40>,
     log_idx = 257,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186dc260>,
     log_idx = 282,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad188cdb50>,
     log_idx = 283,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186a02c0>,
     log_idx = 308,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186a0680>,
     log_idx = 309,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186df350>,
     log_idx = 334,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186de660>,
     log_idx = 335,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18672330>,
     log_idx = 360,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18671250>,
     log_idx = 361,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18641d60>,
     log_idx = 386,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186717c0>,
     log_idx = 387,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18672030>,
     log_idx = 412,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18642fc0>,
     log_idx = 413,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186416d0>,
     log_idx = 438,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad186701d0>,
     log_idx = 439,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18641d00>,
     log_idx = 464,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad188cf950>,
     log_idx = 465,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18640ec0>,
     log_idx = 490,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1855c3b0>,
     log_idx = 491,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad187031d0>,
     log_idx = 516,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18643d70>,
     log_idx = 517,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18640470>,
     log_idx = 542,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1855c470>,
     log_idx = 543,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad185ca570>,
     log_idx = 568,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad185c92b0>,
     log_idx = 569,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1b3321e0>,
     log_idx = 594,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19da6600>,
     log_idx = 595,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19eba180>,
     log_idx = 620,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19dce9c0>,
     log_idx = 621,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad188ce0f0>,
     log_idx = 646,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19ebabd0>,
     log_idx = 647,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19540fb0>,
     log_idx = 672,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19c97ad0>,
     log_idx = 673,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18c5e810>,
     log_idx = 698,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18c5da60>,
     log_idx = 699,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19eb9e80>,
     log_idx = 724,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad188cd790>,
     log_idx = 725,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19dceff0>,
     log_idx = 750,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19ebab10>,
     log_idx = 751,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19c52090>,
     log_idx = 776,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad188cfb90>,
     log_idx = 777,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19daf680>,
     log_idx = 802,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad196ac2f0>,
     log_idx = 803,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1964e870>,
     log_idx = 828,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad19dae660>,
     log_idx = 829,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1964d610>,
     log_idx = 854,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad1972dc70>,
     log_idx = 855,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad18b08cb0>,
     log_idx = 988,
     valid = True,
     ),
 Bunch(
     checkpoint_idx = -1,
     fitter = <wield.iirrational.fitters_ZPK.MRF.MultiReprFilterS at 0x7fad442f8680>,
     log_idx = 990,
     valid = True,
     )]

And plot the result

#_, TF_all = scipy.signal.freqs_zpk(all_z, all_p, k, worN = F_Hz)
#_, TF_minreal = scipy.signal.freqs_zpk(minreal_all_z, minreal_all_p, minreal_all_k, worN = F_Hz)


plt.loglog(F_bug, Div_PSD**0.5, label = "Full FOM ASD")
plt.loglog(F_FOM_dwn, FOM_ASD, label = "Downsampled FOM ASD")
plt.loglog(F_FOM_dwn, hand_xfr.mag, label = 'Handfit ASD')
plt.loglog(F_Hz, recalibrated_zpk_xfr.mag, label = 'Recalibrated AAA')
plt.loglog(F_FOM_dwn, reduced_ASD, label = "reduced ASD")
#plt.loglog(F_Hz, abs(TF_all), label = 'ALL ZPK Fit Bary. (order {})'.format(results.order))
#plt.loglog(F_Hz, abs(TF_minreal), label = 'Minreal ALL ZPK Fit Bary.', linestyle = '--')
plt.loglog(F_Hz, np.abs(iir_results.fitter.xfer_eval(F_Hz)), label = "data2filter Fit FOM", ls='--', linewidth=4)
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x7fad18762480>
../../_images/a696d07b8ca4d6b97b0260446bdc07d6151ecc5e47097385772b3976b64210ee.png
iir_results.fitter.xfer_eval(F_Hz)
array([-4.98039622e-01-1.74495439e+00j,  1.12787318e+00-3.58889136e+00j,
        3.36453718e+00-4.56701571e+00j, ...,
       -7.24288676e+18-3.58464631e+19j, -7.24286678e+18-3.58463869e+19j,
       -7.24284680e+18-3.58463107e+19j])
# Python code to merge dict using a single 
# expression
def Merge(dict1, dict2):
	res = {**dict1, **dict2}
	return res
	
# Driver code
dict1 = {'a': 10, 'b': 8}
dict2 = {'d': 6, 'c': 4}
dict3 = Merge(dict1, dict2)
print(dict3)
print(dict1)
print(dict2)
{'a': 10, 'b': 8, 'd': 6, 'c': 4}
{'a': 10, 'b': 8}
{'d': 6, 'c': 4}
# Hand Fit the DARM**2 ZPK
shift_sq = 0.9
z_hand_sq = np.array([-0.07]*18) * 2 * np.pi * shift_sq
mp_sq = -0.75 -0.075j
mul_sq = 9
p_hand_sq = np.array([mp_sq]*mul_sq + [np.real(mp_sq)-np.imag(mp_sq)*1j]*mul_sq)*2 * 2 * np.pi * shift_sq
p_hand_sq = np.append(p_hand_sq, [-200]*2 +[-2000]*1 + [-10000]*0)
# k_hand_sq = 9e39
k_hand_sq = 7e32

#plt.loglog(F_bug, Div_PSD**0.5, label = "Full FOM ASD")
plt.loglog(F_FOM_dwn, FOM_ASD, label = "Downsampled FOM ASD")
#plt.loglog(F_Hz, abs(TF_all), label = 'ALL ZPK Fit Bary. (order {})'.format(results.order))
plt.loglog(F_Hz, np.abs(iir_results.fitter.xfer_eval(F_Hz)), label = "data2filter Fit FOM")
fq_plot = np.logspace(-2, 5, 10000)


hand_sys = SISO.zpk(z_hand_sq, p_hand_sq, k_hand_sq, convention='IIRrational')
fr = hand_sys.fresponse(f=fq_plot)

plt.loglog(-np.real(p_hand_sq), np.array([1e27]*len(p_hand_sq)), color='black', linestyle='', marker='o')
plt.loglog(-np.real(z_hand_sq), np.array([1e27]*len(z_hand_sq)), color='r', linestyle='', marker='x')
plt.loglog(*fr.fplot_mag, label = 'Hand fit to DARM**2 ZPK')
plt.xlabel("Frequency [Hz]")
plt.ylabel("ASD")

plt.grid()
plt.legend()

#plt.savefig('FOM_BNS_fit.pdf', bbox_inches='tight')
/home/mcculler/local/projects_sync/wield-project-lab/wield-control/src/wield/control/SISO/zpk.py:164: NumericalWarning: StateSpace is large (>50 states), using reduced response fiducial auditing heuristics. TODO to make this smarter
  warnings.warn(f"StateSpace is large (>{self.N_MAX_FID} states), using reduced response fiducial auditing heuristics. TODO to make this smarter", util.NumericalWarning)
<matplotlib.legend.Legend at 0x7fad183ba480>
../../_images/4d002c9a73dbdf7f3a7d5287f410b5e4fcfa3ba7629afb7a0a64037d285058f4.png

Now we will save our result so it can be loaded by the make full system example file

out_p = iir_results.fitter.poles.fullplane
out_z = iir_results.fitter.zeros.fullplane
out_k = iir_results.fitter.gain

# out_z = z_hand_sq
# out_p = p_hand_sq
# out_k = k_hand_sq

pre_save_sys = SISO.zpk(out_z, out_p, out_k, convention='IIRrational')
from wield.utilities.mpl import mplfigB
plotting_omega = np.logspace(-2, 4, 1000)
plt.close()
axB = mplfigB(Nrows = 2)
fr = pre_save_sys.fresponse(f=plotting_omega)
axB.ax0.loglog(*fr.fplot_mag, label='test')
axB.ax1.semilogx(*fr.fplot_deg225, label='test')


sys_save = SISO.zpk(out_z, out_p, out_k, convention='IIRrational')
zpk_dict = {
            'z' : [str(zero) for zero in np.asarray(tuple(sys_save.z)).tolist()],
            'p' : [str(pole) for pole in np.asarray(tuple(sys_save.p)).tolist()],
            'k' : float(sys_save.k)
            }

save('BNS_FOM.yml', zpk_dict)
../../_images/a2a4c606ffff6d4c671ec23b067cbe08ef6eface2931ae1c5eb494d934b07cb0.png

Now it is saved. To open it use the following code

with open('BNS_FOM.yml', 'r') as file:
    filt_dict = yaml.safe_load(file)
p = np.array(filt_dict['p'], dtype=np.complex128)
z = np.array(filt_dict['z'], dtype=np.complex128)
k = np.float64(filt_dict['k'])
print(type(k))
print(len(z))
print(len(p))

print(k)
print(z)
print(p)
<class 'numpy.float64'>
39
42
-2.6027954830162637e+34
[-2.06499544e+01 +0.j         -2.31460520e+00 +0.j
 -2.36675714e+04 +0.j         -1.29081156e+01 +0.j
 -1.85249029e+04 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -4.94022086e+00 +0.j
 -1.29183303e+00 +0.j         -9.89052486e-01 +0.j
 -3.74963778e-02 +0.j         -7.10782084e-01 +1.50105556j
 -7.10782084e-01 -1.50105556j -3.98864393e+00+13.37090632j
 -3.98864393e+00-13.37090632j -3.98864401e+00+13.37090626j
 -3.98864401e+00-13.37090626j -5.87659068e-01 +1.28119215j
 -5.87659068e-01 -1.28119215j -5.87664308e-01 +1.28119005j
 -5.87664308e-01 -1.28119005j -4.05717328e-02 +0.04292108j
 -4.05717328e-02 -0.04292108j -1.19928970e-01+17.71003385j
 -1.19928970e-01-17.71003385j -7.03816332e-02 +2.25773904j
 -7.03816332e-02 -2.25773904j]
[-5.07240137e+03+0.00000000e+00j -8.37254095e-02+0.00000000e+00j
 -1.35956576e-01+0.00000000e+00j -5.63690459e-02+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -8.76206516e+01+0.00000000e+00j -3.15322191e+01+0.00000000e+00j
 -5.73782567e+00+4.07488474e+01j -5.73782567e+00-4.07488474e+01j
 -5.73782567e+00+4.07488474e+01j -5.73782567e+00-4.07488474e+01j
 -9.17494552e-01+4.67729536e+00j -9.17494552e-01-4.67729536e+00j
 -9.79111001e-03+3.76175886e+00j -9.79111001e-03-3.76175886e+00j
 -1.89534220e-01+6.05891549e-01j -1.89534220e-01-6.05891549e-01j
 -1.82100115e+00+1.68934241e+01j -1.82100115e+00-1.68934241e+01j
 -1.26126746e+00+1.65072231e+00j -1.26126746e+00-1.65072231e+00j
 -1.89534220e-01+6.05891549e-01j -1.89534220e-01-6.05891549e-01j
 -6.24505932e+02+8.48909812e+02j -6.24505932e+02-8.48909812e+02j
 -7.85926170e+03+1.19790252e+04j -7.85926170e+03-1.19790252e+04j]
"""
This File has the sole purpose of creating the ASC DHARD Y Model that is then exported to the buzz repository.
"""

import os
import contextlib

import numpy as np
import matplotlib.pyplot as plt
import control

import pytest
import scipy
from scipy.signal import cheby2
from scipy import signal

from wield.bunch import Bunch
#from wield.control import MIMO
from wield.control import SISO
from wield.control.ss_bare.ss import BareStateSpace as RawStateSpace
from wield.control.ss_bare.ssprint import print_dense_nonzero
from wield.utilities.file_io import load, load_ls, save
from wield.utilities.mpl import mplfigB

from wield.pytest.fixtures import ( 
    tpath_join,
    plot,
    dprint,
    tpath,
    tpath_preclear,
    fpath_join,
    test_trigger,
)

from icecream import ic
from buzz import ssutil

import scipy.optimize
from wield.control import SISO


def bode(
    sys,
    axB=None,
    F_Hz=None,
    omega_limits=None,
    include_zp = True,
    label=None,
    **kwargs
):
    """
    sys should be a wield.control.SISO object
    """
    if axB is None:
        axB = mplfigB(Nrows = 2)

    if include_zp:
        z, p = sys._zp
        z = z[z.imag > 0]
        p = p[p.imag > 0]
        F_include = np.sort(np.concatenate(
            [
                z.imag,
                p.imag,
                z.imag - abs(z.real) - 1e-6,
                z.imag + abs(z.real) + 1e-6,
                p.imag - abs(p.real) - 1e-6,
                p.imag + abs(p.real) + 1e-6,
            ]
        )) / (2 * np.pi)
        F_include = F_include[F_include > 0]

        if omega_limits is None:
            omega_limits = (
                (F_include[0] + 1e-6) / 3,
                F_include[-1] * 3
            )

    if F_Hz is None:
        F_Hz = np.geomspace(omega_limits[0], omega_limits[1], 1000)

    if include_zp:
        print("F_include", F_include)
        F_Hz = np.sort(np.concatenate([F_Hz, F_include]))

    fr = sys.fresponse(f=F_Hz)
    axB.ax0.loglog(*fr.fplot_mag, label=label, **kwargs)
    if hasattr(axB, 'ax1'):
        axB.ax1.semilogx(*fr.fplot_deg225, label=label, **kwargs)
    return axB
FBNS_mod = SISO.zpk(z,p,k, convention='IIRrational')#.asSS
# FBNS_iod = {'F1.in':0, 'F1.out':0}
# FBNS = ssutil.makeSys(FBNS_mod, FBNS_iod)
# omega_lim = [min(F_Hz), max(F_Hz)]

#control.bode(FBNS.mod, Hz=True, wrap_phase=True, omega_limits=omega_lim)

from wield.utilities.mpl import mplfigB
plotting_omega = np.logspace(-2, 4, 1000)
plt.close()
axB = mplfigB(Nrows = 2)
fr = FBNS_mod.fresponse(f=plotting_omega)
axB.ax0.loglog(*fr.fplot_mag, label='test')
axB.ax1.semilogx(*fr.fplot_deg225, label='test')

# tol_list = range(10, 16)
# for tol in tol_list:
#     FBNS_tmp = ssutil.balance_sys_gain(FBNS, nr=tol)
#     nstates_tmp = FBNS.A.shape[0]
#     K_zpk_tmp = SISO.SISOStateSpace(BareStateSpace(FBNS_tmp.A, FBNS_tmp.B, FBNS_tmp.C, FBNS_tmp.D, None)).asZPK
#     control.bode(FBNS.mod, Hz=True, wrap_phase=True, omega_limits=omega_lim, label='sts: {}, tol: {}'.format(nstates_tmp, tol))

plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.savefig('postsave.png', dpi=300, bbox_inches='tight')
plt.show()
plt.close()
/home/mcculler/local/projects_sync/wield-project-lab/wield-control/src/wield/control/SISO/zpk.py:164: NumericalWarning: StateSpace is large (>50 states), using reduced response fiducial auditing heuristics. TODO to make this smarter
  warnings.warn(f"StateSpace is large (>{self.N_MAX_FID} states), using reduced response fiducial auditing heuristics. TODO to make this smarter", util.NumericalWarning)
../../_images/959b84f3ff179e8ef458ae0d67d8ed9a6d88bc8d1a22c3e9ad735be4b780e17d.png