This Jupyter notebook can be downloaded from rednoise-fit-example.ipynb, or viewed as a python script at rednoise-fit-example.py.

Red noise and DM noise fitting examples

This notebook provides an example on how to fit for red noise and DM noise using PINT using simulated datasets.

We will use the PLRedNoise and PLDMNoise models to generate noise realizations (these models provide Fourier Gaussian process descriptions of achromatic red noise and DM noise respectively).

We will fit the generated datasets using the WaveX and DMWaveX models, which provide deterministic Fourier representations of achromatic red noise and DM noise respectively.

Finally, we will convert the WaveX/DMWaveX amplitudes into spectral parameters and compare them with the injected values.

[1]:
from pint import DMconst
from pint.models import get_model
from pint.simulation import make_fake_toas_uniform
from pint.logging import setup as setup_log
from pint.fitter import WLSFitter
from pint.utils import (
    dmwavex_setup,
    find_optimal_nharms,
    wavex_setup,
    plrednoise_from_wavex,
    pldmnoise_from_dmwavex,
)

from io import StringIO
import numpy as np
import astropy.units as u
from matplotlib import pyplot as plt
from copy import deepcopy

setup_log(level="WARNING")
[1]:
1

Red noise fitting

Simulation

The first step is to generate a simulated dataset for demonstration. Note that we are adding PHOFF as a free parameter. This is required for the fit to work properly.

[2]:
par_sim = """
    PSR           SIM3
    RAJ           05:00:00     1
    DECJ          15:00:00     1
    PEPOCH        55000
    F0            100          1
    F1            -1e-15       1
    PHOFF         0            1
    DM            15           1
    TNREDAMP      -13
    TNREDGAM      3.5
    TNREDC        30
    TZRMJD        55000
    TZRFRQ        1400
    TZRSITE       gbt
    UNITS         TDB
    EPHEM         DE440
    CLOCK         TT(BIPM2019)
"""

m = get_model(StringIO(par_sim))
[3]:
# Now generate the simulated TOAs.
ntoas = 2000
toaerrs = np.random.uniform(0.5, 2.0, ntoas) * u.us
freqs = np.linspace(500, 1500, 8) * u.MHz

t = make_fake_toas_uniform(
    startMJD=53001,
    endMJD=57001,
    ntoas=ntoas,
    model=m,
    freq=freqs,
    obs="gbt",
    error=toaerrs,
    add_noise=True,
    add_correlated_noise=True,
    name="fake",
    include_bipm=True,
    include_gps=True,
    multi_freqs_in_epoch=True,
)

Optimal number of harmonics

The optimal number of harmonics can be estimated by minimizing the Akaike Information Criterion (AIC). This is implemented in the pint.utils.find_optimal_nharms function.

[4]:
m1 = deepcopy(m)
m1.remove_component("PLRedNoise")

nharm_opt, d_aics = find_optimal_nharms(m1, t, "WaveX", 30)

print("Optimum no of harmonics = ", nharm_opt)
Optimum no of harmonics =  15
[5]:
print(np.argmin(d_aics))
15
[6]:
# The Y axis is plotted in log scale only for better visibility.
plt.scatter(list(range(len(d_aics))), d_aics + 1)
plt.axvline(nharm_opt, color="red", label="Optimum number of harmonics")
plt.axvline(
    int(m.TNREDC.value), color="black", ls="--", label="Injected number of harmonics"
)
plt.xlabel("Number of harmonics")
plt.ylabel("AIC - AIC$_\\min{} + 1$")
plt.legend()
plt.yscale("log")
# plt.savefig("sim3-aic.pdf")
../_images/examples_rednoise-fit-example_9_0.png
[7]:
# Now create a new model with the optimum number of harmonics
m2 = deepcopy(m1)
Tspan = t.get_mjds().max() - t.get_mjds().min()
wavex_setup(m2, T_span=Tspan, n_freqs=nharm_opt, freeze_params=False)

ftr = WLSFitter(t, m2)
ftr.fit_toas(maxiter=10)
m2 = ftr.model

print(m2)
# Created: 2024-05-02T16:05:31.075095
# PINT_version: 1.0+54.g0e607ed
# User: docs
# Host: build-24258979-project-85767-nanograv-pint
# OS: Linux-5.19.0-1028-aws-x86_64-with-glibc2.35
# Python: 3.11.6 (main, Feb  1 2024, 16:47:41) [GCC 11.4.0]
# Format: pint
PSR                                  SIM3
EPHEM                               DE440
CLOCK                        TT(BIPM2019)
UNITS                                 TDB
START              53000.9999999567007408
FINISH             56985.0000000464821181
DILATEFREQ                              N
DMDATA                                  N
NTOA                                 2000
CHI2                   1984.3477915130732
CHI2R                  1.0108750848258141
TRES                0.9920729073072599945
RAJ                      5:00:00.00016465 1 0.00009374255810320811
DECJ                    14:59:59.98018029 1 0.01086956282910487952
PMRA                                  0.0
PMDEC                                 0.0
PX                                    0.0
F0                  100.00000000000040225 1 4.4588321254685192691e-13
F1              -9.997288392948596479e-16 1 1.8054883758439291037e-19
PEPOCH             55000.0000000000000000
PLANET_SHAPIRO                          N
DM                 14.9999913842997639225 1 4.8266415168836399315e-06
WXEPOCH            55000.0000000000000000
WXFREQ_0001         0.0002510040160586007
WXSIN_0001         -5.439024192239741e-06 1 4.995057063379143e-07
WXCOS_0001         -1.796772940101199e-05 1 1.0905494259799844e-05
WXFREQ_0002         0.0005020080321172014
WXSIN_0002          8.256780834724877e-08 1 2.532985280450281e-07
WXCOS_0002         2.9927834111956714e-06 1 2.769130247390268e-06
WXFREQ_0003         0.0007530120481758023
WXSIN_0003         -1.235377849743115e-06 1 1.7585702104330788e-07
WXCOS_0003        -2.4739641154344977e-06 1 1.2664747315060804e-06
WXFREQ_0004         0.0010040160642344029
WXSIN_0004         -4.033703454601264e-07 1 1.3993427211435445e-07
WXCOS_0004          1.369635004940161e-06 1 7.446896974646336e-07
WXFREQ_0005         0.0012550200802930037
WXSIN_0005          5.962832090800399e-07 1 1.2197587497784874e-07
WXCOS_0005        -1.3335494252881996e-06 1 5.070611465130173e-07
WXFREQ_0006         0.0015060240963516046
WXSIN_0006         -2.246535583492585e-07 1 1.1247551589346571e-07
WXCOS_0006          6.811563095339189e-07 1 3.8590358396689103e-07
WXFREQ_0007         0.0017570281124102052
WXSIN_0007          8.273914038226498e-08 1 1.1204751192159644e-07
WXCOS_0007         -5.527642939098721e-07 1 3.2146842059727164e-07
WXFREQ_0008         0.0020080321284688058
WXSIN_0008         -6.509557726010107e-08 1 1.2008002972624713e-07
WXCOS_0008          3.703148530406356e-07 1 2.9765833025084734e-07
WXFREQ_0009          0.002259036144527407
WXSIN_0009         3.1294103519263826e-08 1 1.485185562444591e-07
WXCOS_0009         -6.481791483216267e-07 1 3.1849128689326337e-07
WXFREQ_0010         0.0025100401605860074
WXSIN_0010        -3.9659664380630315e-07 1 2.526657401875636e-07
WXCOS_0010           7.40973805471102e-07 1 4.774513807235659e-07
WXFREQ_0011          0.002761044176644608
WXSIN_0011        -1.9683952741710575e-06 1 2.043563952673017e-06
WXCOS_0011          5.993850506867757e-06 1 3.3766113292352807e-06
WXFREQ_0012          0.003012048192703209
WXSIN_0012         4.3212501994757195e-08 1 1.487697650599433e-07
WXCOS_0012           -3.5376790745702e-07 1 2.108490091665782e-07
WXFREQ_0013         0.0032630522087618097
WXSIN_0013        -1.2078026697892692e-07 1 7.080981378052525e-08
WXCOS_0013         1.0968973177218232e-07 1 8.673363787514832e-08
WXFREQ_0014         0.0035140562248204103
WXSIN_0014         1.0567904972761383e-07 1 4.8253848543838934e-08
WXCOS_0014         -1.169003640726403e-07 1 5.202010072404461e-08
WXFREQ_0015          0.003765060240879011
WXSIN_0015        -1.3504549682384328e-07 1 3.8933018828683806e-08
WXCOS_0015         1.6664885061599313e-07 1 3.963109745695271e-08
TZRMJD             55000.0000000000000000
TZRSITE                               gbt
TZRFRQ                             1400.0
PHOFF             -0.00036635413801635783 1 0.0009019379476080309

Estimating the spectral parameters from the WaveX fit.

[8]:
# Get the Fourier amplitudes and powers and their uncertainties.
idxs = np.array(m2.components["WaveX"].get_indices())
a = np.array([m2[f"WXSIN_{idx:04d}"].quantity.to_value("s") for idx in idxs])
da = np.array([m2[f"WXSIN_{idx:04d}"].uncertainty.to_value("s") for idx in idxs])
b = np.array([m2[f"WXCOS_{idx:04d}"].quantity.to_value("s") for idx in idxs])
db = np.array([m2[f"WXCOS_{idx:04d}"].uncertainty.to_value("s") for idx in idxs])
print(len(idxs))

P = (a**2 + b**2) / 2
dP = ((a * da) ** 2 + (b * db) ** 2) ** 0.5

f0 = (1 / Tspan).to_value(u.Hz)
fyr = (1 / u.year).to_value(u.Hz)
15
[9]:
# We can create a `PLRedNoise` model from the `WaveX` model.
# This will estimate the spectral parameters from the `WaveX`
# amplitudes.
m3 = plrednoise_from_wavex(m2)
print(m3)
# Created: 2024-05-02T16:05:31.119253
# PINT_version: 1.0+54.g0e607ed
# User: docs
# Host: build-24258979-project-85767-nanograv-pint
# OS: Linux-5.19.0-1028-aws-x86_64-with-glibc2.35
# Python: 3.11.6 (main, Feb  1 2024, 16:47:41) [GCC 11.4.0]
# Format: pint
PSR                                  SIM3
EPHEM                               DE440
CLOCK                        TT(BIPM2019)
UNITS                                 TDB
START              53000.9999999567007408
FINISH             56985.0000000464821181
DILATEFREQ                              N
DMDATA                                  N
NTOA                                 2000
CHI2                   1984.3477915130732
CHI2R                  1.0108750848258141
TRES                0.9920729073072599945
RAJ                      5:00:00.00016465 1 0.00009374255810320811
DECJ                    14:59:59.98018029 1 0.01086956282910487952
PMRA                                  0.0
PMDEC                                 0.0
PX                                    0.0
F0                  100.00000000000040225 1 4.4588321254685192691e-13
F1              -9.997288392948596479e-16 1 1.8054883758439291037e-19
PEPOCH             55000.0000000000000000
PLANET_SHAPIRO                          N
DM                 14.9999913842997639225 1 4.8266415168836399315e-06
TZRMJD             55000.0000000000000000
TZRSITE                               gbt
TZRFRQ                             1400.0
PHOFF             -0.00036635413801635783 1 0.0009019379476080309
TNREDAMP               -12.72025964748686 0 0.10922880304129169
TNREDGAM                2.865568038534513 0 0.5109021810016983
TNREDC                               15.0

[10]:
# Now let us plot the estimated spectrum with the injected
# spectrum.
plt.subplot(211)
plt.errorbar(
    idxs * f0,
    b * 1e6,
    db * 1e6,
    ls="",
    marker="o",
    label="$\\hat{a}_j$ (WXCOS)",
    color="red",
)
plt.errorbar(
    idxs * f0,
    a * 1e6,
    da * 1e6,
    ls="",
    marker="o",
    label="$\\hat{b}_j$ (WXSIN)",
    color="blue",
)
plt.axvline(fyr, color="black", ls="dotted")
plt.axhline(0, color="grey", ls="--")
plt.ylabel("Fourier coeffs ($\mu$s)")
plt.xscale("log")
plt.legend(fontsize=8)

plt.subplot(212)
plt.errorbar(
    idxs * f0, P, dP, ls="", marker="o", label="Spectral power (PINT)", color="k"
)
P_inj = m.components["PLRedNoise"].get_noise_weights(t)[::2][:nharm_opt]
plt.plot(idxs * f0, P_inj, label="Injected Spectrum", color="r")
P_est = m3.components["PLRedNoise"].get_noise_weights(t)[::2][:nharm_opt]
print(len(idxs), len(P_est))
plt.plot(idxs * f0, P_est, label="Estimated Spectrum", color="b")
plt.xscale("log")
plt.yscale("log")
plt.ylabel("Spectral power (s$^2$)")
plt.xlabel("Frequency (Hz)")
plt.axvline(fyr, color="black", ls="dotted", label="1 yr$^{-1}$")
plt.legend()
15 15
[10]:
<matplotlib.legend.Legend at 0x7feb62a23790>
../_images/examples_rednoise-fit-example_14_2.png

Note the outlier in the 1 year^-1 bin. This is caused by the covariance with RA and DEC, which introduce a delay with the same frequency.

DM noise fitting

Let us now do a similar kind of analysis for DM noise.

[11]:
par_sim = """
    PSR           SIM4
    RAJ           05:00:00     1
    DECJ          15:00:00     1
    PEPOCH        55000
    F0            100          1
    F1            -1e-15       1
    PHOFF         0            1
    DM            15           1
    TNDMAMP       -13
    TNDMGAM       3.5
    TNDMC         30
    TZRMJD        55000
    TZRFRQ        1400
    TZRSITE       gbt
    UNITS         TDB
    EPHEM         DE440
    CLOCK         TT(BIPM2019)
"""

m = get_model(StringIO(par_sim))
[12]:
# Generate the simulated TOAs.
ntoas = 2000
toaerrs = np.random.uniform(0.5, 2.0, ntoas) * u.us
freqs = np.linspace(500, 1500, 8) * u.MHz

t = make_fake_toas_uniform(
    startMJD=53001,
    endMJD=57001,
    ntoas=ntoas,
    model=m,
    freq=freqs,
    obs="gbt",
    error=toaerrs,
    add_noise=True,
    add_correlated_noise=True,
    name="fake",
    include_bipm=True,
    include_gps=True,
    multi_freqs_in_epoch=True,
)
[13]:
# Find the optimum number of harmonics by minimizing AIC.
m1 = deepcopy(m)
m1.remove_component("PLDMNoise")

m2 = deepcopy(m1)

nharm_opt, d_aics = find_optimal_nharms(m2, t, "DMWaveX", 30)
print("Optimum no of harmonics = ", nharm_opt)
Optimum no of harmonics =  30
[14]:
# The Y axis is plotted in log scale only for better visibility.
plt.scatter(list(range(len(d_aics))), d_aics + 1)
plt.axvline(nharm_opt, color="red", label="Optimum number of harmonics")
plt.axvline(
    int(m.TNDMC.value), color="black", ls="--", label="Injected number of harmonics"
)
plt.xlabel("Number of harmonics")
plt.ylabel("AIC - AIC$_\\min{} + 1$")
plt.legend()
plt.yscale("log")
# plt.savefig("sim3-aic.pdf")
../_images/examples_rednoise-fit-example_20_0.png
[15]:
# Now create a new model with the optimum number of
# harmonics
m2 = deepcopy(m1)

Tspan = t.get_mjds().max() - t.get_mjds().min()
dmwavex_setup(m2, T_span=Tspan, n_freqs=nharm_opt, freeze_params=False)

ftr = WLSFitter(t, m2)
ftr.fit_toas(maxiter=10)
m2 = ftr.model

print(m2)
# Created: 2024-05-02T16:06:37.969014
# PINT_version: 1.0+54.g0e607ed
# User: docs
# Host: build-24258979-project-85767-nanograv-pint
# OS: Linux-5.19.0-1028-aws-x86_64-with-glibc2.35
# Python: 3.11.6 (main, Feb  1 2024, 16:47:41) [GCC 11.4.0]
# Format: pint
PSR                                  SIM4
EPHEM                               DE440
CLOCK                        TT(BIPM2019)
UNITS                                 TDB
START              53000.9999999567933913
FINISH             56985.0000000470963310
DILATEFREQ                              N
DMDATA                                  N
NTOA                                 2000
CHI2                   1971.1115203337804
CHI2R                  1.0197162546993173
TRES                1.0004871879404677873
RAJ                      5:00:00.00000422 1 0.00000191519383133734
DECJ                    14:59:59.99997957 1 0.00016071879954330197
PMRA                                  0.0
PMDEC                                 0.0
PX                                    0.0
F0                 100.000000000000047094 1 3.677924536715014598e-14
F1               -9.99999429996255119e-16 1 8.282426390657092134e-22
PEPOCH             55000.0000000000000000
PLANET_SHAPIRO                          N
DM                  14.999992892620425964 1 4.8888067530853088514e-06
DMWXEPOCH          55000.0000000000000000
DMWXFREQ_0001       0.0002510040160585677
DMWXSIN_0001         0.004784432696479563 1 5.9608433044230135e-06
DMWXCOS_0001       -0.0020701710711931325 1 6.5945090384257316e-06
DMWXFREQ_0002       0.0005020080321171354
DMWXSIN_0002       -0.0002151868593995677 1 4.631239922972655e-06
DMWXCOS_0002        0.0006672364199749057 1 4.399411780002452e-06
DMWXFREQ_0003       0.0007530120481757032
DMWXSIN_0003      -0.00021604023233196928 1 4.372853292790847e-06
DMWXCOS_0003        -0.000729812432969959 1 4.291029428816e-06
DMWXFREQ_0004       0.0010040160642342708
DMWXSIN_0004       -5.908809238702459e-05 1 4.396702705141925e-06
DMWXCOS_0004       -0.0001284441765185486 1 4.181737444241144e-06
DMWXFREQ_0005       0.0012550200802928387
DMWXSIN_0005        0.0001841957594462948 1 4.306864875420353e-06
DMWXCOS_0005       0.00019004741443962893 1 4.2238166013350605e-06
DMWXFREQ_0006       0.0015060240963514064
DMWXSIN_0006       0.00010506191267328568 1 4.298760058450302e-06
DMWXCOS_0006       -8.583179491469642e-05 1 4.193105184188948e-06
DMWXFREQ_0007       0.0017570281124099742
DMWXSIN_0007        0.0001190916182627555 1 4.2767783340648995e-06
DMWXCOS_0007       -4.081589258631969e-05 1 4.208895339810137e-06
DMWXFREQ_0008       0.0020080321284685417
DMWXSIN_0008       0.00010029966887087978 1 4.302231133444963e-06
DMWXCOS_0008        6.038599065081691e-05 1 4.167100129781713e-06
DMWXFREQ_0009       0.0022590361445271098
DMWXSIN_0009       -3.235810677116201e-05 1 4.290208376311054e-06
DMWXCOS_0009       -3.068426585762246e-05 1 4.188673423408253e-06
DMWXFREQ_0010       0.0025100401605856774
DMWXSIN_0010      -4.0112820073472066e-05 1 4.222242692959873e-06
DMWXCOS_0010      -2.0535791598738445e-05 1 4.338908873352654e-06
DMWXFREQ_0011        0.002761044176644245
DMWXSIN_0011       -7.554544470005492e-05 1 6.789499623293527e-06
DMWXCOS_0011       -7.075012563769556e-05 1 6.901572166551911e-06
DMWXFREQ_0012       0.0030120481927028127
DMWXSIN_0012       -1.633251080813954e-05 1 4.27433220916863e-06
DMWXCOS_0012      -1.8783933995431607e-05 1 4.207576440222235e-06
DMWXFREQ_0013       0.0032630522087613804
DMWXSIN_0013      -2.2458047013499387e-05 1 4.1845619858112104e-06
DMWXCOS_0013        6.842471154080898e-06 1 4.278253321789589e-06
DMWXFREQ_0014       0.0035140562248199485
DMWXSIN_0014      -3.8478396078044365e-05 1 4.210056598165244e-06
DMWXCOS_0014        2.851713555829453e-05 1 4.24520104656374e-06
DMWXFREQ_0015        0.003765060240878516
DMWXSIN_0015       -4.197920462969455e-05 1 4.192390796538004e-06
DMWXCOS_0015       -3.364114449998145e-05 1 4.267581600577844e-06
DMWXFREQ_0016        0.004016064256937083
DMWXSIN_0016        2.966682098885399e-05 1 4.2892613833473216e-06
DMWXCOS_0016        -7.63082183855059e-06 1 4.163436310734253e-06
DMWXFREQ_0017        0.004267068272995652
DMWXSIN_0017      -2.8523496939134686e-05 1 4.237765400705771e-06
DMWXCOS_0017       -7.535686584559696e-06 1 4.219315505193638e-06
DMWXFREQ_0018       0.0045180722890542195
DMWXSIN_0018       -8.321536599350788e-06 1 4.267410098869098e-06
DMWXCOS_0018       1.0527192645439128e-06 1 4.196931114909494e-06
DMWXFREQ_0019        0.004769076305112787
DMWXSIN_0019       1.5045160307102342e-05 1 4.2629076134210345e-06
DMWXCOS_0019      -2.5794399645040813e-05 1 4.193437351616618e-06
DMWXFREQ_0020        0.005020080321171355
DMWXSIN_0020       2.9036849558188502e-05 1 4.215839274535906e-06
DMWXCOS_0020       1.1749032665739599e-05 1 4.249124447083484e-06
DMWXFREQ_0021       0.0052710843372299225
DMWXSIN_0021        4.673534589649611e-06 1 4.3280221129121635e-06
DMWXCOS_0021        6.140856969891847e-06 1 4.132987608651971e-06
DMWXFREQ_0022         0.00552208835328849
DMWXSIN_0022         -5.4401258928555e-06 1 4.25364137450981e-06
DMWXCOS_0022      -1.1546888230350273e-05 1 4.217292884197121e-06
DMWXFREQ_0023        0.005773092369347058
DMWXSIN_0023        8.714297354117749e-06 1 4.2675784527202946e-06
DMWXCOS_0023       1.9103373469970348e-06 1 4.199208957197699e-06
DMWXFREQ_0024       0.0060240963854056254
DMWXSIN_0024       -7.361978125662888e-06 1 4.256721297018583e-06
DMWXCOS_0024      -1.3178900123540535e-07 1 4.210376245826402e-06
DMWXFREQ_0025        0.006275100401464193
DMWXSIN_0025       -7.863110893271246e-06 1 4.249319639860948e-06
DMWXCOS_0025       1.6758575591721533e-07 1 4.212037381818677e-06
DMWXFREQ_0026        0.006526104417522761
DMWXSIN_0026      -1.1616918523461777e-05 1 4.290363546015798e-06
DMWXCOS_0026        2.977989935023756e-05 1 4.178868618478103e-06
DMWXFREQ_0027        0.006777108433581329
DMWXSIN_0027       -6.921700101008301e-06 1 4.176379820254314e-06
DMWXCOS_0027       1.0698102469977588e-05 1 4.298188660911003e-06
DMWXFREQ_0028        0.007028112449639897
DMWXSIN_0028       3.3046800007363966e-05 1 4.258806820832094e-06
DMWXCOS_0028       1.2907251016112718e-05 1 4.223361008452143e-06
DMWXFREQ_0029        0.007279116465698465
DMWXSIN_0029      -1.4875084825331147e-05 1 4.232290162346857e-06
DMWXCOS_0029       -4.862136871371481e-06 1 4.24299875499507e-06
DMWXFREQ_0030        0.007530120481757032
DMWXSIN_0030      -1.0276476915932796e-05 1 4.20243641829311e-06
DMWXCOS_0030       3.4497579194968614e-06 1 4.277231825877769e-06
TZRMJD             55000.0000000000000000
TZRSITE                               gbt
TZRFRQ                             1400.0
PHOFF              -0.0004719283334695277 1 5.528398407307158e-06

Estimating the spectral parameters from the DMWaveX fit.

[16]:
# Get the Fourier amplitudes and powers and their uncertainties.
# Note that the `DMWaveX` amplitudes have the units of DM.
# We multiply them by a constant factor to convert them to dimensions
# of time so that they are consistent with `PLDMNoise`.
scale = DMconst / (1400 * u.MHz) ** 2

idxs = np.array(m2.components["DMWaveX"].get_indices())
a = np.array(
    [(scale * m2[f"DMWXSIN_{idx:04d}"].quantity).to_value("s") for idx in idxs]
)
da = np.array(
    [(scale * m2[f"DMWXSIN_{idx:04d}"].uncertainty).to_value("s") for idx in idxs]
)
b = np.array(
    [(scale * m2[f"DMWXCOS_{idx:04d}"].quantity).to_value("s") for idx in idxs]
)
db = np.array(
    [(scale * m2[f"DMWXCOS_{idx:04d}"].uncertainty).to_value("s") for idx in idxs]
)
print(len(idxs))

P = (a**2 + b**2) / 2
dP = ((a * da) ** 2 + (b * db) ** 2) ** 0.5

f0 = (1 / Tspan).to_value(u.Hz)
fyr = (1 / u.year).to_value(u.Hz)
30
[17]:
# We can create a `PLDMNoise` model from the `DMWaveX` model.
# This will estimate the spectral parameters from the `DMWaveX`
# amplitudes.
m3 = pldmnoise_from_dmwavex(m2)
print(m3)
# Created: 2024-05-02T16:06:38.031908
# PINT_version: 1.0+54.g0e607ed
# User: docs
# Host: build-24258979-project-85767-nanograv-pint
# OS: Linux-5.19.0-1028-aws-x86_64-with-glibc2.35
# Python: 3.11.6 (main, Feb  1 2024, 16:47:41) [GCC 11.4.0]
# Format: pint
PSR                                  SIM4
EPHEM                               DE440
CLOCK                        TT(BIPM2019)
UNITS                                 TDB
START              53000.9999999567933913
FINISH             56985.0000000470963310
DILATEFREQ                              N
DMDATA                                  N
NTOA                                 2000
CHI2                   1971.1115203337804
CHI2R                  1.0197162546993173
TRES                1.0004871879404677873
RAJ                      5:00:00.00000422 1 0.00000191519383133734
DECJ                    14:59:59.99997957 1 0.00016071879954330197
PMRA                                  0.0
PMDEC                                 0.0
PX                                    0.0
F0                 100.000000000000047094 1 3.677924536715014598e-14
F1               -9.99999429996255119e-16 1 8.282426390657092134e-22
PEPOCH             55000.0000000000000000
PLANET_SHAPIRO                          N
DM                  14.999992892620425964 1 4.8888067530853088514e-06
TZRMJD             55000.0000000000000000
TZRSITE                               gbt
TZRFRQ                             1400.0
PHOFF              -0.0004719283334695277 1 5.528398407307158e-06
TNDMAMP               -12.936911815504295 0 0.04222323071628055
TNDMGAM                 3.296563514796768 0 0.19423551642629294
TNDMC                                30.0

[18]:
# Now let us plot the estimated spectrum with the injected
# spectrum.
plt.subplot(211)
plt.errorbar(
    idxs * f0,
    b * 1e6,
    db * 1e6,
    ls="",
    marker="o",
    label="$\\hat{a}_j$ (DMWXCOS)",
    color="red",
)
plt.errorbar(
    idxs * f0,
    a * 1e6,
    da * 1e6,
    ls="",
    marker="o",
    label="$\\hat{b}_j$ (DMWXSIN)",
    color="blue",
)
plt.axvline(fyr, color="black", ls="dotted")
plt.axhline(0, color="grey", ls="--")
plt.ylabel("Fourier coeffs ($\mu$s)")
plt.xscale("log")
plt.legend(fontsize=8)

plt.subplot(212)
plt.errorbar(
    idxs * f0, P, dP, ls="", marker="o", label="Spectral power (PINT)", color="k"
)
P_inj = m.components["PLDMNoise"].get_noise_weights(t)[::2][:nharm_opt]
plt.plot(idxs * f0, P_inj, label="Injected Spectrum", color="r")
P_est = m3.components["PLDMNoise"].get_noise_weights(t)[::2][:nharm_opt]
print(len(idxs), len(P_est))
plt.plot(idxs * f0, P_est, label="Estimated Spectrum", color="b")
plt.xscale("log")
plt.yscale("log")
plt.ylabel("Spectral power (s$^2$)")
plt.xlabel("Frequency (Hz)")
plt.axvline(fyr, color="black", ls="dotted", label="1 yr$^{-1}$")
plt.legend()
30 30
[18]:
<matplotlib.legend.Legend at 0x7feb54d259d0>
../_images/examples_rednoise-fit-example_25_2.png