overview_of_noise_sources

# Overview of Noise Sources¶

Use this notebook to check the properties of the noise. The next few cells just contain a couple of convenience functions and you can skip directly to the content below.

You should have at least 8 GB of RAM if you want to run the whole notebook because all noise streams are kept in memory for analysis. The data rates below were measured on an Intel Xeon W-1270.

In [1]:

    %matplotlib inline
    import pyplnoise
    import time
    import numpy as np
    import scipy.signal
    import matplotlib.pyplot as plt

In [2]:

    def autocorr(x):
        corr_raw = scipy.signal.fftconvolve(x, x[::-1], mode='full')
        corr_raw = corr_raw[corr_raw.size//2:]
        # scale the result to get an unbiased estimate
        result = np.divide(corr_raw, corr_raw.size - np.arange(0, corr_raw.size, 1))
        return result
    def plot_welch_and_autocorr(x, fs, nperseg=250000, ac_lag_max=6000):
        ac = autocorr(x)
        f, S_f = scipy.signal.welch(x, fs=fs, nperseg=nperseg,
                                    scaling='density', return_onesided=False,
                                    detrend='constant')
        fig, axs = plt.subplots(1, 2, figsize=(14,5))
        fig.suptitle("Welch Periodogram & Autocorrelation")
        axs[0].grid(True)
        axs[0].loglog(f[2:f.size//2], S_f[2:f.size//2])
        axs[0].set_xlabel("f (Hz)")
        axs[0].set_ylabel("Two-sided power spectral density (unit$^2$/Hz)")
        axs[1].plot(ac[0:ac_lag_max])
        axs[1].grid(True)
        axs[1].yaxis.tick_right()
        axs[1].yaxis.set_label_position('right')
        axs[1].set_xlabel("Lag $j$")
        axs[1].set_ylabel("Autocorrelation $<x_{i}x_{i-j}>$")
        return (fig, axs)
    def plot_time_series_and_histogram(t, x):
        fig, axs = plt.subplots(1, 2, figsize=(14,5))
        fig.suptitle("Time series & Histogram")
        axs[0].grid(True)
        axs[0].plot(t/3600., x)
        axs[0].set_xlabel("Time (h)")
        axs[0].set_ylabel("Signal (a.u.)")
        n, bins, _ = axs[1].hist(x, 40)
        axs[1].plot(bins, n.max()*np.exp(-(bins-x.mean())**2./(2.*x.std()**2.)))
        axs[1].grid(True)
        axs[1].yaxis.tick_right()
        axs[1].yaxis.set_label_position('right')
        axs[1].set_xlabel("Signal (a.u.)")
        axs[1].set_ylabel("# Samples")
        return (fig, axs)

In [3]:

    fs = 100.
    npts = 60000000
    t = np.linspace(0., npts/fs, num=npts)

## General $1/f^{\alpha}$ Power Law Noise¶

Parameters $\alpha=1.5$, $f_{min} = 10^{-2}\text{ Hz}$, $f_{max} = 10\text{ Hz}$. As you can see, the noise becomes white below $f_{min}$ and above $f_{max}$.

In [4]:

    plnoise = pyplnoise.AlphaNoise(fs, 1e-2, 10., alpha=1.5)
    t0 = time.time()
    x_pl = plnoise.get_series(npts)
    t1 = time.time()
    print("Data rate: {:g} samples/sec".format(npts/(t1 - t0)))

    Data rate: 1.3793e+07 samples/sec

In [5]:

    fig, axs = plot_welch_and_autocorr(x_pl, fs, nperseg=600000)

In [6]:

    fig, axs = plot_time_series_and_histogram(t, x_pl)

## Pink Noise¶

A convenience alias is provided for the special case $\alpha=1.0$. Here: $f_{min} = 10^{-2}\text{ Hz}$, $f_{max} = 50\text{ Hz}$.

In [7]:

    pknoise = pyplnoise.PinkNoise(fs, 1e-2, 50.)
    x_pk = pknoise.get_series(npts)

In [8]:

    fig, axs = plot_welch_and_autocorr(x_pk, fs, nperseg=600000)

In [9]:

    fig, axs = plot_time_series_and_histogram(t, x_pk)

## Red Noise¶

Parameter $f_{min} = 10^{-2}\text{ Hz}$. If you also like to adjust an upper frequency limit, use `AlphaNoise` with $\alpha = 2.0$ (note however that `AlphaNoise` is slower than the `RedNoise` class).

In [10]:

    rdnoise = pyplnoise.RedNoise(fs, 1e-2)
    t0 = time.time()
    x_rd = rdnoise.get_series(npts)
    t1 = time.time()
    print("Data rate: {:g} samples/sec".format(npts/(t1 - t0)))

    Data rate: 6.17235e+07 samples/sec

In [11]:

    fig, axs = plot_welch_and_autocorr(x_rd, fs, nperseg=600000)

In [12]:

    fig, axs = plot_time_series_and_histogram(t, x_rd)

## White Noise¶

White noise is the basis for everything and is generated using NumPy's default random number generator. Starting with NumPy version 1.17, it is of the family of "permuted congruential generators".

In [13]:

    whnoise = pyplnoise.WhiteNoise(fs, psd=1.0)
    t0 = time.time()
    x_wh = whnoise.get_series(npts)
    t1 = time.time()
    print("Data rate: {:g} samples/sec".format(npts/(t1 - t0)))

    Data rate: 1.04429e+08 samples/sec

In [14]:

    fig, axs = plot_welch_and_autocorr(x_wh, fs, nperseg=10000)

In [15]:

    fig, axs = plot_time_series_and_histogram(t, x_wh)