Usage#

fourierror propagates measurement uncertainty through a discrete Fourier transform. It offers three entry points, and the point of this notebook is to show what each one is for and where they agree:

Function

Method

Cost

analytical.dft

exact propagation through the DFT matrix

one matrix product

numerical.dft

Monte Carlo sampling of the input distribution

n_samples transforms

numerical.fft

Monte Carlo sampling, via the FFT

n_samples transforms, faster

Everything is built on scipp data objects, so inputs carry units, coordinates and variances, and the frequency axis is derived for you.

[1]:
import numpy as np
import scipp as sc
import matplotlib.pyplot as plt

from fourierror import analytical, numerical

Input data#

A damped cosine, measured with noise that grows over time — so the input variances are not all equal. That is the interesting case: a single “average” error bar would not capture it.

The input is a scipp.DataArray whose data has variances and whose coordinate carries a unit.

[2]:
rng = np.random.default_rng(42)

N, dt = 128, 0.05
t = np.arange(N) * dt
truth = np.exp(-t / 1.5) * np.cos(2 * np.pi * 1.5 * t)

sigma = 0.05 + 0.15 * (t / t.max())  # noise grows with time
measured = truth + rng.normal(0.0, sigma)

data = sc.DataArray(
    data=sc.array(dims=["t"], values=measured, variances=sigma**2),
    coords={"t": sc.array(dims=["t"], values=t, unit="s")},
)
data
[2]:
Show/Hide data repr Show/Hide attributes
scipp.DataArray (3.86 KB)
    • t: 128
    • t
      (t)
      float64
      s
      0.0, 0.05, ..., 6.300, 6.350
      Values:
      array([0. , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 , 0.55, 0.6 , 0.65, 0.7 , 0.75, 0.8 , 0.85, 0.9 , 0.95, 1. , 1.05, 1.1 , 1.15, 1.2 , 1.25, 1.3 , 1.35, 1.4 , 1.45, 1.5 , 1.55, 1.6 , 1.65, 1.7 , 1.75, 1.8 , 1.85, 1.9 , 1.95, 2. , 2.05, 2.1 , 2.15, 2.2 , 2.25, 2.3 , 2.35, 2.4 , 2.45, 2.5 , 2.55, 2.6 , 2.65, 2.7 , 2.75, 2.8 , 2.85, 2.9 , 2.95, 3. , 3.05, 3.1 , 3.15, 3.2 , 3.25, 3.3 , 3.35, 3.4 , 3.45, 3.5 , 3.55, 3.6 , 3.65, 3.7 , 3.75, 3.8 , 3.85, 3.9 , 3.95, 4. , 4.05, 4.1 , 4.15, 4.2 , 4.25, 4.3 , 4.35, 4.4 , 4.45, 4.5 , 4.55, 4.6 , 4.65, 4.7 , 4.75, 4.8 , 4.85, 4.9 , 4.95, 5. , 5.05, 5.1 , 5.15, 5.2 , 5.25, 5.3 , 5.35, 5.4 , 5.45, 5.5 , 5.55, 5.6 , 5.65, 5.7 , 5.75, 5.8 , 5.85, 5.9 , 5.95, 6. , 6.05, 6.1 , 6.15, 6.2 , 6.25, 6.3 , 6.35])
    • (t)
      float64
      𝟙
      1.015, 0.809, ..., 0.277, -0.252
      σ = 0.05, 0.051, ..., 0.199, 0.2
      Values:
      array([ 1.01523585, 0.80856832, 0.58917249, 0.1919087 , -0.37721268, -0.67135198, -0.77136124, -0.80056683, -0.62064785, -0.38804442, 0.05435649, 0.36362863, 0.54653771, 0.71403224, 0.6275031 , 0.37069363, 0.20668971, -0.15596034, -0.25998516, -0.47658027, -0.52702706, -0.49339642, -0.18942248, -0.08459736, 0.10529232, 0.27930302, 0.44273893, 0.43149024, 0.35242448, 0.20897224, 0.18296753, -0.19673971, -0.32339875, -0.40117944, -0.25066536, -0.1170766 , -0.10361651, -0.03315085, 0.0873915 , 0.3053255 , 0.33587422, 0.28062699, 0.0786571 , 0.06071052, -0.05938984, -0.13521921, -0.11433556, -0.18257792, -0.09090245, -0.08136413, 0.03152995, 0.15252741, -0.01940359, 0.13280315, 0.10368981, 0.03960625, 0.01583035, 0.15199307, -0.18763645, -0.00878342, -0.33873726, -0.15750318, -0.054362 , 0.05377519, 0.12592388, 0.18157928, 0.06075973, 0.04614588, 0.19566747, 0.0203608 , -0.16925445, -0.19428093, -0.19755462, -0.01894012, -0.06114406, 0.03764645, -0.08424852, 0.03435813, 0.13256956, 0.01967711, 0.13548208, -0.03654173, -0.01510723, -0.046674 , -0.19722568, 0.03164807, -0.1252535 , -0.05243724, 0.03094935, 0.04589609, 0.10399917, 0.00635232, -0.02948021, 0.03175221, -0.23026097, -0.20492828, -0.20351416, -0.17028141, 0.04384758, -0.18401398, -0.09924699, 0.1892044 , -0.0803495 , 0.12154759, -0.15171368, -0.0143966 , -0.13866299, -0.0318959 , 0.17130967, -0.29674349, 0.07816205, 0.03183023, -0.12764973, -0.28814465, -0.00795747, -0.11369385, 0.03704517, 0.00727887, 0.31483683, -0.028737 , -0.17792187, 0.05036901, 0.0527715 , 0.26800869, 0.15910985, 0.05956833, 0.27667063, -0.25207801])

      Variances (σ²):
      array([0.0025 , 0.00261951, 0.0027418 , 0.00286689, 0.00299476, 0.00312543, 0.00325888, 0.00339513, 0.00353416, 0.00367599, 0.0038206 , 0.00396801, 0.0041182 , 0.00427119, 0.00442696, 0.00458553, 0.00474688, 0.00491103, 0.00507797, 0.00524769, 0.00542021, 0.00559551, 0.00577361, 0.00595449, 0.00613817, 0.00632463, 0.00651389, 0.00670593, 0.00690077, 0.00709839, 0.00729881, 0.00750202, 0.00770801, 0.0079168 , 0.00812837, 0.00834274, 0.00855989, 0.00877984, 0.00900257, 0.0092281 , 0.00945641, 0.00968752, 0.00992141, 0.0101581 , 0.01039758, 0.01063984, 0.0108849 , 0.01113274, 0.01138338, 0.0116368 , 0.01189302, 0.01215202, 0.01241382, 0.01267841, 0.01294578, 0.01321595, 0.0134889 , 0.01376465, 0.01404318, 0.01432451, 0.01460862, 0.01489553, 0.01518523, 0.01547771, 0.01577299, 0.01607105, 0.01637191, 0.01667555, 0.01698199, 0.01729121, 0.01760323, 0.01791804, 0.01823563, 0.01855602, 0.01887919, 0.01920516, 0.01953391, 0.01986546, 0.0201998 , 0.02053692, 0.02087684, 0.02121954, 0.02156504, 0.02191332, 0.0222644 , 0.02261827, 0.02297492, 0.02333437, 0.0236966 , 0.02406163, 0.02442944, 0.02480005, 0.02517345, 0.02554963, 0.02592861, 0.02631037, 0.02669493, 0.02708227, 0.02747241, 0.02786534, 0.02826105, 0.02865956, 0.02906085, 0.02946494, 0.02987181, 0.03028148, 0.03069394, 0.03110918, 0.03152722, 0.03194804, 0.03237166, 0.03279807, 0.03322726, 0.03365925, 0.03409402, 0.03453159, 0.03497194, 0.03541509, 0.03586103, 0.03630975, 0.03676127, 0.03721557, 0.03767267, 0.03813256, 0.03859523, 0.0390607 , 0.03952895, 0.04 ])
[3]:
fig, ax = plt.subplots(figsize=(8, 3))
ax.errorbar(t, measured, yerr=sigma, fmt="o", ms=3, lw=1, alpha=0.7, label="measured")
ax.plot(t, truth, "k-", lw=1.5, label="truth")
ax.set(xlabel="t / s", ylabel="signal")
ax.legend()
plt.show()
_images/usage_4_0.png

Exact propagation#

The DFT is linear, so an input covariance maps onto the output exactly: cos @ cov @ cos.T for the real part and sin @ cov @ sin.T for the imaginary part. No sampling, no tuning parameter — just one matrix product.

The result is a scipp.Dataset with real and imag entries, each carrying its own variances, on an omega axis.

[4]:
ana = analytical.dft(data, "t")
ana
[4]:
Show/Hide data repr Show/Hide attributes
scipp.Dataset (6.67 KB)
    • omega: 128
    • omega
      (omega)
      float64
      Hz
      0.0, 0.982, ..., -1.963, -0.982
      Values:
      array([ 0. , 0.9817477 , 1.96349541, 2.94524311, 3.92699082, 4.90873852, 5.89048623, 6.87223393, 7.85398163, 8.83572934, 9.81747704, 10.79922475, 11.78097245, 12.76272016, 13.74446786, 14.72621556, 15.70796327, 16.68971097, 17.67145868, 18.65320638, 19.63495408, 20.61670179, 21.59844949, 22.5801972 , 23.5619449 , 24.54369261, 25.52544031, 26.50718801, 27.48893572, 28.47068342, 29.45243113, 30.43417883, 31.41592654, 32.39767424, 33.37942194, 34.36116965, 35.34291735, 36.32466506, 37.30641276, 38.28816047, 39.26990817, 40.25165587, 41.23340358, 42.21515128, 43.19689899, 44.17864669, 45.1603944 , 46.1421421 , 47.1238898 , 48.10563751, 49.08738521, 50.06913292, 51.05088062, 52.03262833, 53.01437603, 53.99612373, 54.97787144, 55.95961914, 56.94136685, 57.92311455, 58.90486225, 59.88660996, 60.86835766, 61.85010537, -62.83185307, -61.85010537, -60.86835766, -59.88660996, -58.90486225, -57.92311455, -56.94136685, -55.95961914, -54.97787144, -53.99612373, -53.01437603, -52.03262833, -51.05088062, -50.06913292, -49.08738521, -48.10563751, -47.1238898 , -46.1421421 , -45.1603944 , -44.17864669, -43.19689899, -42.21515128, -41.23340358, -40.25165587, -39.26990817, -38.28816047, -37.30641276, -36.32466506, -35.34291735, -34.36116965, -33.37942194, -32.39767424, -31.41592654, -30.43417883, -29.45243113, -28.47068342, -27.48893572, -26.50718801, -25.52544031, -24.54369261, -23.5619449 , -22.5801972 , -21.59844949, -20.61670179, -19.63495408, -18.65320638, -17.67145868, -16.68971097, -15.70796327, -14.72621556, -13.74446786, -12.76272016, -11.78097245, -10.79922475, -9.81747704, -8.83572934, -7.85398163, -6.87223393, -5.89048623, -4.90873852, -3.92699082, -2.94524311, -1.96349541, -0.9817477 ])
    • imag
      (omega)
      float64
      𝟙
      0.0, -0.024, ..., -0.007, 0.024
      σ = 0.0, 0.016, ..., 0.017, 0.016
      Values:
      array([ 0.00000000e+00, -2.42925147e-02, 7.37462838e-03, 2.77815430e-02, 2.76505479e-02, 3.12804638e-02, 4.76239324e-02, 7.12011227e-02, 9.68103674e-02, 9.22395917e-02, -9.72072332e-02, -7.41970465e-02, -8.28404732e-02, -4.63209916e-02, -4.38481221e-02, -1.22799039e-02, -3.19985584e-02, -2.13160033e-02, -2.96641985e-02, -4.06257881e-02, -3.17651843e-02, -3.22528574e-02, -1.09772966e-02, -5.07539748e-02, -1.26344654e-02, -1.37505555e-02, -3.73460073e-03, -1.58720648e-02, -6.45967210e-03, -1.01083472e-02, -1.00863624e-02, -4.76137106e-04, -5.63879972e-03, 1.59355169e-03, -1.04705132e-02, -1.59965004e-02, -3.29952277e-02, -1.16480707e-02, -5.49759290e-03, 6.63451509e-03, 2.29316465e-03, -9.15515531e-03, -2.07503792e-02, -9.89378473e-03, -1.33797594e-02, 2.22176624e-03, -1.25902096e-02, -5.55705149e-04, -1.73897171e-02, -1.48574012e-02, -4.07827332e-02, -1.74806208e-02, 6.83935236e-03, -1.40633381e-02, -1.20596750e-03, -1.53921595e-02, -1.29611289e-03, 1.72316958e-03, 1.93167602e-02, -4.61407396e-03, -3.61461822e-03, -2.09518991e-02, 8.44340597e-04, 2.91968896e-03, -1.77308425e-16, -2.91968896e-03, -8.44340597e-04, 2.09518991e-02, 3.61461822e-03, 4.61407396e-03, -1.93167602e-02, -1.72316958e-03, 1.29611289e-03, 1.53921595e-02, 1.20596750e-03, 1.40633381e-02, -6.83935236e-03, 1.74806208e-02, 4.07827332e-02, 1.48574012e-02, 1.73897171e-02, 5.55705149e-04, 1.25902096e-02, -2.22176624e-03, 1.33797594e-02, 9.89378473e-03, 2.07503792e-02, 9.15515531e-03, -2.29316465e-03, -6.63451509e-03, 5.49759290e-03, 1.16480707e-02, 3.29952277e-02, 1.59965004e-02, 1.04705132e-02, -1.59355169e-03, 5.63879972e-03, 4.76137106e-04, 1.00863624e-02, 1.01083472e-02, 6.45967210e-03, 1.58720648e-02, 3.73460073e-03, 1.37505555e-02, 1.26344654e-02, 5.07539748e-02, 1.09772966e-02, 3.22528574e-02, 3.17651843e-02, 4.06257881e-02, 2.96641985e-02, 2.13160033e-02, 3.19985584e-02, 1.22799039e-02, 4.38481221e-02, 4.63209916e-02, 8.28404732e-02, 7.41970465e-02, 9.72072332e-02, -9.22395917e-02, -9.68103674e-02, -7.12011227e-02, -4.76239324e-02, -3.12804638e-02, -2.76505479e-02, -2.77815430e-02, -7.37462838e-03, 2.42925147e-02])

      Variances (σ²):
      array([0.00000000e+00, 2.71689986e-04, 2.75082221e-04, 2.75710404e-04, 2.75930259e-04, 2.76032011e-04, 2.76087272e-04, 2.76120581e-04, 2.76142188e-04, 2.76156989e-04, 2.76167562e-04, 2.76175372e-04, 2.76181298e-04, 2.76185895e-04, 2.76189527e-04, 2.76192442e-04, 2.76194810e-04, 2.76196756e-04, 2.76198368e-04, 2.76199714e-04, 2.76200843e-04, 2.76201793e-04, 2.76202595e-04, 2.76203271e-04, 2.76203839e-04, 2.76204313e-04, 2.76204706e-04, 2.76205025e-04, 2.76205277e-04, 2.76205469e-04, 2.76205603e-04, 2.76205682e-04, 2.76205709e-04, 2.76205682e-04, 2.76205603e-04, 2.76205469e-04, 2.76205277e-04, 2.76205025e-04, 2.76204706e-04, 2.76204313e-04, 2.76203839e-04, 2.76203271e-04, 2.76202595e-04, 2.76201793e-04, 2.76200843e-04, 2.76199714e-04, 2.76198368e-04, 2.76196756e-04, 2.76194810e-04, 2.76192442e-04, 2.76189527e-04, 2.76185895e-04, 2.76181298e-04, 2.76175372e-04, 2.76167562e-04, 2.76156989e-04, 2.76142188e-04, 2.76120581e-04, 2.76087272e-04, 2.76032011e-04, 2.75930259e-04, 2.75710404e-04, 2.75082221e-04, 2.71689986e-04, 1.81171480e-31, 2.71689986e-04, 2.75082221e-04, 2.75710404e-04, 2.75930259e-04, 2.76032011e-04, 2.76087272e-04, 2.76120581e-04, 2.76142188e-04, 2.76156989e-04, 2.76167562e-04, 2.76175372e-04, 2.76181298e-04, 2.76185895e-04, 2.76189527e-04, 2.76192442e-04, 2.76194810e-04, 2.76196756e-04, 2.76198368e-04, 2.76199714e-04, 2.76200843e-04, 2.76201793e-04, 2.76202595e-04, 2.76203271e-04, 2.76203839e-04, 2.76204313e-04, 2.76204706e-04, 2.76205025e-04, 2.76205277e-04, 2.76205469e-04, 2.76205603e-04, 2.76205682e-04, 2.76205709e-04, 2.76205682e-04, 2.76205603e-04, 2.76205469e-04, 2.76205277e-04, 2.76205025e-04, 2.76204706e-04, 2.76204313e-04, 2.76203839e-04, 2.76203271e-04, 2.76202595e-04, 2.76201793e-04, 2.76200843e-04, 2.76199714e-04, 2.76198368e-04, 2.76196756e-04, 2.76194810e-04, 2.76192442e-04, 2.76189527e-04, 2.76185895e-04, 2.76181298e-04, 2.76175372e-04, 2.76167562e-04, 2.76156989e-04, 2.76142188e-04, 2.76120581e-04, 2.76087272e-04, 2.76032011e-04, 2.75930259e-04, 2.75710404e-04, 2.75082221e-04, 2.71689986e-04])
    • real
      (omega)
      float64
      𝟙
      -0.004, 0.017, ..., 0.026, 0.017
      σ = 0.023, 0.017, ..., 0.017, 0.017
      Values:
      array([-4.34913327e-03, 1.70044689e-02, 2.61698261e-02, 2.47495808e-02, 1.21130717e-02, 1.58014536e-02, 2.74687203e-02, 3.75093372e-03, 3.40242829e-02, 1.35808242e-01, 2.11891923e-01, 3.67639399e-02, 1.54801213e-02, 2.87611653e-02, 2.39673096e-02, -8.63325519e-03, -4.36247226e-03, -1.60338161e-02, -2.51248172e-04, -1.47334190e-03, 5.85973102e-04, 6.69438609e-03, 1.80919304e-02, 8.68461768e-03, 9.01966344e-03, 1.06860341e-02, 2.10825463e-02, -1.55139779e-02, 3.72799128e-03, 1.41298161e-02, 1.54831104e-02, -1.31056705e-02, -1.40841388e-02, 6.48144273e-04, -5.44669579e-03, -4.82316152e-03, 1.16764933e-02, 1.33493433e-02, 2.64095015e-02, 1.90241199e-02, -1.45994720e-04, 3.02035304e-03, -2.66816509e-03, 1.84130850e-02, -7.27181377e-04, 1.25843150e-02, 2.44027451e-03, 1.43517773e-02, 1.84708667e-02, -1.04645671e-02, 2.22793188e-02, 4.29117503e-02, 2.01287398e-02, 8.94655554e-03, 9.00253056e-03, 8.69989906e-03, 4.44619373e-02, 1.55398008e-02, 1.21964807e-02, 5.44681874e-03, -1.65680772e-03, 9.49447943e-03, 8.90079732e-03, 3.94386994e-02, 1.40474515e-02, 3.94386994e-02, 8.90079732e-03, 9.49447943e-03, -1.65680772e-03, 5.44681874e-03, 1.21964807e-02, 1.55398008e-02, 4.44619373e-02, 8.69989906e-03, 9.00253056e-03, 8.94655554e-03, 2.01287398e-02, 4.29117503e-02, 2.22793188e-02, -1.04645671e-02, 1.84708667e-02, 1.43517773e-02, 2.44027451e-03, 1.25843150e-02, -7.27181377e-04, 1.84130850e-02, -2.66816509e-03, 3.02035304e-03, -1.45994720e-04, 1.90241199e-02, 2.64095015e-02, 1.33493433e-02, 1.16764933e-02, -4.82316152e-03, -5.44669579e-03, 6.48144273e-04, -1.40841388e-02, -1.31056705e-02, 1.54831104e-02, 1.41298161e-02, 3.72799128e-03, -1.55139779e-02, 2.10825463e-02, 1.06860341e-02, 9.01966344e-03, 8.68461768e-03, 1.80919304e-02, 6.69438609e-03, 5.85973102e-04, -1.47334190e-03, -2.51248172e-04, -1.60338161e-02, -4.36247226e-03, -8.63325519e-03, 2.39673096e-02, 2.87611653e-02, 1.54801213e-02, 3.67639399e-02, 2.11891923e-01, 1.35808242e-01, 3.40242829e-02, 3.75093372e-03, 2.74687203e-02, 1.58014536e-02, 1.21130717e-02, 2.47495808e-02, 2.61698261e-02, 1.70044689e-02])

      Variances (σ²):
      array([0.0005478 , 0.00027611, 0.00027272, 0.00027209, 0.00027187, 0.00027177, 0.00027171, 0.00027168, 0.00027166, 0.00027164, 0.00027163, 0.00027162, 0.00027162, 0.00027161, 0.00027161, 0.00027161, 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.00027161, 0.00027161, 0.00027161, 0.00027162, 0.00027162, 0.00027163, 0.00027164, 0.00027166, 0.00027168, 0.00027171, 0.00027177, 0.00027187, 0.00027209, 0.00027272, 0.00027611, 0.0005478 , 0.00027611, 0.00027272, 0.00027209, 0.00027187, 0.00027177, 0.00027171, 0.00027168, 0.00027166, 0.00027164, 0.00027163, 0.00027162, 0.00027162, 0.00027161, 0.00027161, 0.00027161, 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.00027159, 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.0002716 , 0.00027161, 0.00027161, 0.00027161, 0.00027162, 0.00027162, 0.00027163, 0.00027164, 0.00027166, 0.00027168, 0.00027171, 0.00027177, 0.00027187, 0.00027209, 0.00027272, 0.00027611])
[5]:
def plot_spectrum(ds, ax, label, **kw):
    """Plot the positive-frequency real part with a 1-sigma band."""
    w = ds.coords["omega"].values
    keep = w >= 0
    v = ds["real"].values[keep]
    e = np.sqrt(ds["real"].variances[keep])
    ax.plot(w[keep], v, label=label, **kw)
    ax.fill_between(w[keep], v - e, v + e, alpha=0.25, lw=0, **kw)


fig, ax = plt.subplots(figsize=(8, 3))
plot_spectrum(ana, ax, "analytical", color="C0")
ax.set(xlabel="omega / rad s$^{-1}$", ylabel="Re[F]")
ax.legend()
plt.show()
_images/usage_7_0.png

Monte Carlo#

The numerical route draws n_samples realisations from a multivariate normal built from the input values and variances, transforms every one of them, and takes the mean and covariance of the results.

It is (usually) slower and stochastic, but it makes no assumptions about how the uncertainty propagates — which is what makes it the reference when you want to check the analytical result, or when the analytical assumptions do not hold.

[10]:
num = numerical.dft(data, "t", n_samples=5_000)

fig, axes = plt.subplots(1, 2, figsize=(10, 3.2))
plot_spectrum(ana, axes[0], "analytical", color="C0")
plot_spectrum(num, axes[0], "numerical", color="C1")
axes[0].set(xlabel="omega / rad s$^{-1}$", ylabel="Re[F]")
axes[0].legend()

w = ana.coords["omega"].values
keep = w >= 0
axes[1].plot(
    w[keep], np.sqrt(ana["real"].variances[keep]), "o-", ms=3, label="analytical"
)
axes[1].plot(
    w[keep], np.sqrt(num["real"].variances[keep]), "x-", ms=4, label="numerical"
)
axes[1].set(xlabel="omega / rad s$^{-1}$", ylabel="sigma(Re[F])")
axes[1].legend()
plt.tight_layout()
plt.show()
_images/usage_9_0.png
[11]:
sd_a = np.sqrt(ana["real"].variances)
sd_n = np.sqrt(num["real"].variances)
print(f"max relative difference in sigma: {np.abs(sd_n / sd_a - 1).max():.2%}")
max relative difference in sigma: 2.44%

The two agree to within Monte Carlo noise, and the sampling error shrinks as n_samples grows — the usual \(1/\sqrt{n}\) convergence.

[12]:
for n in (100, 500, 2_500, 12_500):
    sd = np.sqrt(numerical.dft(data, "t", n_samples=n)["real"].variances)
    print(
        f"n_samples = {n:6d}   max relative difference = {np.abs(sd / sd_a - 1).max():.2%}"
    )
n_samples =    100   max relative difference = 15.38%
n_samples =    500   max relative difference = 9.37%
n_samples =   2500   max relative difference = 3.45%
n_samples =  12500   max relative difference = 1.58%

Fast Fourier transform#

numerical.fft samples in exactly the same way but uses np.fft.fft instead of an explicit DFT matrix, which is the difference between O(N²) and O(N log N) per sample.

We are in the process of developing an FFT analytical form.

[15]:
fast = numerical.fft(data, "t", n_samples=5_000)

fig, ax = plt.subplots(figsize=(8, 3))
plot_spectrum(fast, ax, "fft", color="C2")
ax.set(xlabel="omega / rad s$^{-1}$", ylabel="Re[F]")
ax.legend()
plt.show()
_images/usage_14_0.png