Creating an op-amp 1/f noise spectra in code

So-called \(1/f\) or "pink" noise is noise with a power spectral density that is inversely proportional to frequency. It manifests itself in op-amps as both an input voltage and input current noise, where it is commonly called flicker noise. It is typically characterised on op-amp datasheets in terms of a white noise that does not vary with frequency and a "corner" frequency below which the noise rises.

When I want to take the flat noise and corner frequency from the datasheet and plot it on top of some measurements, I often forget how to generate the noise vector given those two numbers. For the benefit of anyone else wondering how to do this, and/or too lazy to think about it, here is some Python code I made to do it. It assumes an array-like input vector \(f\) such as a NumPy array.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import numpy as np

def opamp_noise(f, flat_noise, corner_frequency):
    """Calculate op-amp noise spectral density given the specified frequency
    vector (in e.g. Hz), flat noise (in e.g. V/sqrt(Hz) or A/sqrt(Hz)), and
    corner frequency (in e.g. Hz).

    Parameters
    ----------
    f : array-like
        The 1xN dimensional frequency vector.
    flat_noise : float
        The flat noise value above the corner frequency, e.g.
        4.3 nV/sqrt(Hz).
    corner_frequency : float
        The frequency at which the flat noise starts to rise towards lower
        frequencies (the -3 dB point), e.g. 21 Hz.

    Returns
    -------
    array-like
        The combined flat and 1/f op-amp noise vector, of identical size to
        the supplied `f` parameter.
    """
    # The 1/f noise contribution.
    flicker_noise = flat_noise * np.sqrt(corner_frequency / f)
    # Combine in quadrature with the flat noise contribution.
    return np.sqrt(flicker_noise ** 2 + flat_noise ** 2)

The above function is valid for both op-amp voltage and current noise spectra. Note that this noise actually follows a \(1/\sqrt{f}\) shape when plotted as per the function above. This is because datasheets define the flat noise in volts or amperes per square-root Hz, which are amplitudes, whereas the \(1/f\) behaviour of the noise is defined in terms of power (i.e. amplitude squared, so e.g. volts-squared per Hz).

Fun fact that I just learned from the Wikipedia page linked above: this noise is given the description "pink" because white light passed through a filter that applies a \(1/f\) power spectrum (where \(f\) in this case is the light frequency) is pink.