Noise handling demo
The noise framework employed by the simulator might also be useful on its own, as it allows to generate the exact same noises as in the simulator, and provides access to the exact nosie definitions and PSDs.
This notebook shows the various noise types used in the simulator, demonstrates how to generate noise samples independent from the simulator, and how to obtain the PSDs for any noise type. It shows how to extract the default noise definitions from the simulator and plots those as examples.
import matplotlib_inline
%matplotlib inline
from matplotlib import pyplot as plt
plt.rcParams["figure.constrained_layout.use"] = True
plt.rcParams["figure.figsize"] = [9, 6]
plt.rcParams["figure.dpi"] = 50
plt.rcParams["font.size"] = 20
matplotlib_inline.backend_inline.set_matplotlib_formats("jpeg", dpi=50)
# reduces notebook file size
import numpy as np
from lisainstrument import Instrument, MosaID, SatID
from lisainstrument.noisy import (
NoiseDefBase,
NoiseDefCumSum,
NoiseDefPowerLaw,
NoiseDefRed,
NoiseDefViolet,
NoiseDefInfraRed,
NoiseDefFalloff6,
NoiseDefFalloff8,
NoiseDefWhite,
NoiseDefPink,
psd_twosided_from_asd_onesided,
NoiseDefModulation,
NoiseDefLaser,
NoiseDefBacklink,
NoiseDefTestMass,
LaserNoiseShape,
TestMassNoiseShape,
)
from lisainstrument.noisy.estimate_psd import estimate_psd_twosided, PSDEstimate
from lisainstrument.noisy import NoiseGen
def plotnoise(noisedef, fmin, nseg=25, nseeds=10, conf_prob=0.95, detrend="constant"):
"""Generate noise samples, compute actual and expected PSD, plot both"""
nperseg = int(noisedef.f_sample / fmin)
size = nperseg * nseg
plt.close()
for seed in np.arange(nseeds):
ngen = NoiseGen(noisedef, seed)
noise = ngen.generate(size)
est = estimate_psd_twosided(
noise, ndef.f_sample, nseg=nseg, conf_prob=conf_prob, detrend=detrend
)
lbl = "Welch estimate" if seed == 0 else None
plt.loglog(est.freq, est.psd_twosided, "k-", alpha=1 / nseeds, label=lbl)
f = np.exp(np.linspace(np.log(est.freq[0]), np.log(est.freq[-1]), 400))
psdex = noisedef.discrete_psd_twosided(f)
plt.loglog(f, psdex, "r-", label="Expected")
plt.xlabel(r"$f\,[\mathrm{Hz}]$")
plt.ylabel(r"PSD $[U/\mathrm{Hz}]$")
plt.title(f"{noisedef.name} ({noisedef.__class__.__name__})")
plt.legend()
White noise
fsamp = 4.0
asd1s = 10.0
ndef = NoiseDefWhite(f_sample=fsamp, asd_onesided_const=asd1s, name="White")
plotnoise(ndef, fsamp * 1e-3, nseeds=100)
print(ndef)
Noise type NoiseDefWhite
name = White
f_sample [Hz] = 4.0
asd_onesided_const [1/sqrt(Hz)] = 10.0
wnoise = NoiseGen(ndef, 13).generate(100000)
whist, wedge = np.histogram(wnoise, bins=100, density=True)
plt.close()
plt.stairs(whist, edges=wedge, color="k", label="Sample distribution")
x = np.linspace(wedge[0], wedge[-1], 500)
plt.plot(x, ndef.sample_distribution(x), "g-", label="expected")
plt.legend();
Red noise
ndef = NoiseDefRed(f_sample=fsamp, asd_onesided_at_1hz=asd1s, f_min_hz=1e-2, name="Red")
plotnoise(ndef, 1e-4)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
f = np.linspace(1e-3, 2, 200)
plt.loglog(
f,
psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz) * f**-2,
"k:",
label="$f^{-2}$",
)
plt.legend()
print(ndef)
Noise type NoiseDefRed
name = Red
f_sample [Hz] = 4.0
asd_onesided_at_1hz [1/sqrt(Hz)] = 10.0
f_min_hz [Hz] = 0.01
Infrared noise
ndef = NoiseDefInfraRed(
f_sample=fsamp, asd_onesided_at_1hz=asd1s, f_min_hz=1e-2, name="Infrared"
)
plotnoise(ndef, 1e-4)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
f = np.linspace(1e-3, 2, 200)
plt.loglog(
f,
psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz) * f**-4,
"k:",
label="$f^{-4}$",
)
plt.legend()
print(ndef)
Noise type NoiseDefInfraRed
name = Infrared
f_sample [Hz] = 4.0
asd_onesided_at_1hz [1/sqrt(Hz)] = 10.0
f_min_hz [Hz] = 0.01
Violet noise
ndef = NoiseDefViolet(f_sample=fsamp, asd_onesided_at_1hz=asd1s, name="Violet")
plotnoise(ndef, 1e-3, nseeds=20)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
f = np.linspace(1e-3, 2, 200)
plt.loglog(
f,
psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz) * f**2,
"k:",
label="$f^{2}$",
)
plt.legend()
print(ndef)
Noise type NoiseDefViolet
name = Violet
f_sample [Hz] = 4.0
asd_onesided_at_1hz [1/sqrt(Hz)] = 10.0
Pink noise
ndef = NoiseDefPink(
f_sample=fsamp, asd_onesided_at_1hz=asd1s, f_min_hz=1e-2, name="Pink"
)
plotnoise(ndef, 2e-4, nseeds=5)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
f = np.linspace(1e-3, 2, 200)
plt.loglog(
f,
psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz) * f**-1,
"k:",
label="$f^{-1}$",
)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefPink
name = Pink
f_sample [Hz] = 4.0
asd_onesided_at_1hz [1/sqrt(Hz)] = 10.0
f_min_hz [Hz] = 0.01
Simulator default noise parameters
For the examples below, we use the default parameters of the simulator for the instrumental noise types.
instru = Instrument()
defaults = instru.get_noise_defs()
Using default set of locking beatnote frequencies might cause interferometric beatnote frequencies to fall outside the requirement range of 5..25 MHz
Modulation noise
ndef = defaults.noise_def_modulation(mosa=MosaID.MOSA_12)
plotnoise(ndef, 1e-4, nseeds=5)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
f = np.linspace(1e-3, 2, 200)
plt.loglog(
f,
psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz) * (f ** (2 / 3)),
"k:",
label="$f^{2/3}$",
)
plt.legend()
print(ndef)
Noise type NoiseDefModulation
name = modulation_12
f_sample [Hz] = 16.0
asd_onesided_at_1hz [1/sqrt(Hz)] = 5.2e-14
f_min_hz [Hz] = 5e-05
Laser
ndef = defaults.noise_def_laser(MosaID.MOSA_12)
plotnoise(ndef, 5e-5, nseeds=5)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
plt.axvline(x=ndef.f_knee_hz, label=f"f_knee_hz = {ndef.f_knee_hz}")
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_const)],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefLaser
name = laser_12
f_sample [Hz] = 16.0
shape = white+infrared
asd_onesided_const [Hz/sqrt(Hz)] = 30.0
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
Backlink
ndef = defaults.noise_def_backlink(MosaID.MOSA_12)
plotnoise(ndef, 1e-4)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
plt.axvline(x=ndef.f_knee_hz, label=f"f_knee_hz = {ndef.f_knee_hz}")
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
f = np.linspace(1e-3, 2, 200)
plt.loglog(
f,
psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz) * (f**2),
"k:",
label="$f^2$",
)
plt.legend()
print(ndef)
Noise type NoiseDefBacklink
name = backlink_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 3e-12
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
Testmass
This noise definition is problematic because the PSD model has a low-frequency divergence for the “lowfreq-relax” option. Reproducing the model PSD for generated noise was unsucessful, even when tweaking the Welch method parameters. The default parameters of the simulator do not use the “lowfreq-relax” option. The small deviation in the plot below from the expected value converges when computing longer noise sequences.
ndef = defaults.noise_def_testmass(MosaID.MOSA_12)
plotnoise(ndef, 5e-5, nseeds=5)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
plt.axvline(x=ndef.f_knee_hz, label=f"f_knee_hz = {ndef.f_knee_hz}")
plt.loglog(
[1],
[
psd_twosided_from_asd_onesided(
ndef.accel_asd_onesided / (2 * np.pi * ndef.f_break_hz**2)
)
],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefTestMass
name = testmass_12
f_sample [Hz] = 16.0
shape = original
accel_asd_onesided [(m/s^2)/sqrt(Hz)] = 2.4e-15
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.0004
f_break_hz [Hz] = 0.008
f_relax_hz [Hz] = 8e-05
Clock noise
ndef = defaults.noise_def_clock(SatID.SAT_1)
plotnoise(ndef, 5e-5, nseeds=5)
plt.axvline(x=ndef.f_min_hz, label=f"f_min_hz = {ndef.f_min_hz}")
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
f = np.linspace(1e-3, 2, 200)
plt.legend()
print(ndef)
Noise type NoiseDefClock
name = clock_1
f_sample [Hz] = 16.0
asd_onesided_at_1hz [1/sqrt(Hz)] = 6.32e-14
f_min_hz [Hz] = 1e-05
Ranging noise
ndef = defaults.noise_def_ranging(MosaID.MOSA_12)
plotnoise(ndef, 5e-5, nseeds=5)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_const)],
"xg",
ms=10,
label="Fiducial amplitude",
)
f = np.linspace(1e-3, 2, 200)
plt.legend()
print(ndef)
Noise type NoiseDefRanging
name = ranging_12
f_sample [Hz] = 16.0
asd_onesided_const [s/sqrt(Hz)] = 3e-09
OMS SCI Carrier
ndef = defaults.noise_def_oms_sci_carrier(MosaID.MOSA_12)
plotnoise(ndef, 5e-5, nseeds=5)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefOMS
name = oms_sci_carrier_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 6.35e-12
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
OMS SCI upper sidebands
Same as OMS SCI carrier but different amplitude
ndef = defaults.noise_def_oms_sci_usb(MosaID.MOSA_12)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefOMS
name = oms_sci_usb_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 1.25e-11
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
OMS TMI carrier
Same as OMS SCI carrier but different amplitude
ndef = defaults.noise_def_oms_tmi_carrier(MosaID.MOSA_12)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefOMS
name = oms_tmi_carrier_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 1.42e-12
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
OMS TMI upper sidebands
Same as OMS SCI carrier but different amplitude
ndef = defaults.noise_def_oms_tmi_usb(MosaID.MOSA_12)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefOMS
name = oms_tmi_usb_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 3.38e-12
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
OMS REF Carrier
Same as OMS SCI carrier but different amplitude
ndef = defaults.noise_def_oms_ref_carrier(MosaID.MOSA_12)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefOMS
name = oms_ref_carrier_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 3.32e-12
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
OMS REF upper sideband
Same as OMS SCI carrier but different amplitude
ndef = defaults.noise_def_oms_ref_usb(MosaID.MOSA_12)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefOMS
name = oms_ref_usb_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 7.9e-12
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.002
DWS phi, eta
ndef = defaults.noise_def_dws_phi(MosaID.MOSA_12)
plotnoise(ndef, 5e-5, nseeds=5)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefDWS
name = dws_phi_12
f_sample [Hz] = 16.0
angle_asd_onesided [Rad/sqrt(Hz)] = 2.0895522388059703e-10
DWS eta is identical
ndef = defaults.noise_def_dws_eta(MosaID.MOSA_12)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefDWS
name = dws_eta_12
f_sample [Hz] = 16.0
angle_asd_onesided [Rad/sqrt(Hz)] = 2.0895522388059703e-10
MOC time correlation
ndef = defaults.noise_def_moc_time_correlation(SatID.SAT_1)
plotnoise(ndef, 1e-4 * ndef.f_sample)
plt.legend()
print(ndef)
Noise type NoiseDefMocTimeCorrelation
name = moc_time_correlation_1
f_sample [Hz] = 1.1574074074074073e-05
asd_onesided_const [s/sqrt(Hz)] = 0.42
MOSA longitudinal jitter
ndef = defaults.noise_def_mosa_jitter_xs(MosaID.MOSA_12)
plotnoise(ndef, 5e-5, nseeds=5)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefLongitudinalJitter
name = mosa_jitter_xs_12
f_sample [Hz] = 16.0
displacement_asd_onesided [m/sqrt(Hz)] = 2e-09
MOSA jitter phi, eta
ndef = defaults.noise_def_mosa_jitter_phis(MosaID.MOSA_12)
plotnoise(ndef, 5e-5, nseeds=5)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefAngularJitter
name = mosa_jitter_phi_12
f_sample [Hz] = 16.0
angle_asd_onesided [Rad/sqrt(Hz)] = 2e-09
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.0008
Jitter in eta is identical
ndef = defaults.noise_def_mosa_jitter_etas(MosaID.MOSA_12)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefAngularJitter
name = mosa_jitter_eta_12
f_sample [Hz] = 16.0
angle_asd_onesided [Rad/sqrt(Hz)] = 2e-09
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.0008
Spacecraft jitter phi, eta, theta
ndef = defaults.noise_def_sc_jitter_phis(SatID.SAT_1)
plotnoise(ndef, 5e-5, nseeds=5)
plt.loglog(
[1],
[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)],
"xg",
ms=10,
label="Fiducial amplitude",
)
plt.legend()
print(ndef)
Noise type NoiseDefAngularJitter
name = sc_jitter_phis_1
f_sample [Hz] = 16.0
angle_asd_onesided [Rad/sqrt(Hz)] = 5e-09
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.0008
Jitter for eta and theta angles is identical
ndef = defaults.noise_def_sc_jitter_etas(SatID.SAT_1)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefAngularJitter
name = sc_jitter_eta_1
f_sample [Hz] = 16.0
angle_asd_onesided [Rad/sqrt(Hz)] = 5e-09
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.0008
ndef = defaults.noise_def_sc_jitter_thetas(SatID.SAT_1)
# plotnoise(ndef, 5e-5, nseeds=5)
# plt.loglog([1],[psd_twosided_from_asd_onesided(ndef.asd_onesided_at_1hz)], "xg", ms=10, label="Fiducial amplitude")
# plt.legend()
print(ndef)
Noise type NoiseDefAngularJitter
name = sc_jitter_theta_1
f_sample [Hz] = 16.0
angle_asd_onesided [Rad/sqrt(Hz)] = 5e-09
f_min_hz [Hz] = 5e-05
f_knee_hz [Hz] = 0.0008