Skip to content

Nyquist_min_samples

timecave.utils.Nyquist_min_samples(fs, freq_limit)

Compute the minimum number of samples the series should have for the Nyquist theorem to be satisfied.

This function computes the minimum series length for capturing a given frequency, assuming the time series was sampled at a frequency of fs Hertz and the largest frequency of interest for modelling purposes is freq_limit Hertz. Additionally, the function computes the largest frequency that can be captured using fs as the sampling frequency, as well as the smallest sampling frequency that would be required to capture freq_limit. Both of these results are directly derived from the Nyquist sampling theorem.

Parameters:

Name Type Description Default
fs float | int

The time series' sampling frequency (Hz).

required
freq_limit float | int

Largest frequency of interest (Hz).

required

Returns:

Type Description
int

Minimum number of samples required to capture freq_limit with a sampling frequency of fs, according to the Nyquist sampling theorem.

Raises:

Type Description
TypeError

If either fs or freq_limit is neither a float nor an integer.

ValueError

If either fs or freq_limit are non-positive.

Warning

If the choice of fs and freq_limit does not satisfy the Nyquist sampling theorem.

See also

heuristic_min_samples: Performs the same computations using an heuristic rule.

Notes

The Nyquist sampling theorem is a fundamental result in digital signal processing. It states that, for one to be able to reconstruct a continuous-time signal from its discrete counterpart, the sampling frequency should be at least twice as high as the largest frequency of interest. Mathematically speaking, the condition on the sampling frequency is:

\[ f_s >= 2 \cdot f \]

where \(f_s\) is the sampling frequency and \(f\) is the frequency of interest. The Nyquist sampling theorem is discussed in several reference books, of which [1] is but an example.

Since time series are essentially signals, the minimum number of samples that need to be collected if one needs [is] to capture a given frequency [if a given frequency is to be captured] can be computed using the Nyquist theorem.

References

1

A. Oppenheim, R. Schafer, and J. Buck. Discrete-Time Signal Processing. Prentice Hall, 1999.

Examples:

>>> from timecave.utils import Nyquist_min_samples
>>> n_samples = Nyquist_min_samples(100, 20);
Nyquist theorem results
-----------------------
Maximum frequency that can be extracted using a sampling frequency of 100 Hz : 50.0 Hz
Sampling rate required to capture a frequency of 20 Hz : 40 Hz
------------------------------------------------------------------------------------------
Minimum number of samples required to capture a frequency of 20 Hz with a
sampling frequency of 100 Hz: 10 samples
>>> n_samples
10

If the frequency of interest cannot be captured using the sampling frequency provided by the user according to the Nyquist theorem, an exception is thrown:

>>> samples = Nyquist_min_samples(1, 2);
Traceback (most recent call last):
...
Warning: According to the Nyquist theorem, the selected frequency cannot be captured using this sampling frequency.

If negative frequencies are passed, or if their values are neither integers nor floats, exceptions are thrown as well:

>>> samples = Nyquist_min_samples(-2, 1);
Traceback (most recent call last):
...
ValueError: Frequencies should be non-negative.
>>> samples = Nyquist_min_samples(1, "a");
Traceback (most recent call last):
...
TypeError: Both 'fs' and 'freq_limit' should be either integers or floats.
Source code in timecave/utils.py
def Nyquist_min_samples(fs: float | int, freq_limit: float | int) -> int:

    """
    Compute the minimum number of samples the series should have
    for the Nyquist theorem to be satisfied.

    This function computes the minimum series length for capturing a given frequency,
    assuming the time series was sampled at
    a frequency of `fs` Hertz and the largest frequency of interest
    for modelling purposes is `freq_limit` Hertz. Additionally,
    the function computes the largest frequency that can be captured
    using `fs` as the sampling frequency, as well as the smallest sampling 
    frequency that would be required to capture `freq_limit`. Both of these 
    results are directly derived from the Nyquist sampling theorem.

    Parameters
    ----------
    fs : float | int
        The time series' sampling frequency (Hz).

    freq_limit : float | int
        Largest frequency of interest (Hz).

    Returns
    -------
    int
        Minimum number of samples required to capture `freq_limit`
        with a sampling frequency of `fs`, according to the Nyquist
        sampling theorem.

    Raises
    ------
    TypeError
        If either `fs` or `freq_limit` is neither a float nor an integer.

    ValueError
        If either `fs` or `freq_limit` are non-positive.

    Warning
        If the choice of `fs` and `freq_limit` does not satisfy the Nyquist sampling theorem.

    See also
    --------
    [heuristic_min_samples](heuristic.md):
        Performs the same computations using an heuristic rule.

    Notes
    -----
    The Nyquist sampling theorem is a fundamental result in digital signal processing. It states that, \
    for one to be able to reconstruct a continuous-time signal from its discrete counterpart, the sampling \
    frequency should be at least twice as high as the largest frequency of interest.
    Mathematically speaking, the condition on the sampling frequency is:

    $$
    f_s >= 2 \cdot f
    $$

    where $f_s$ is the sampling frequency and $f$ is the frequency of interest. \
    The Nyquist sampling theorem is discussed in several reference books, of which [[1]](#1) is but an example.

    Since time series are essentially signals, the minimum number of samples that need to be collected if one needs [is] to capture a given frequency [if a given frequency is to be captured] can be computed \
    using the Nyquist theorem.

    References
    ----------
    ##1
    A. Oppenheim, R. Schafer, and J. Buck. Discrete-Time Signal Processing.
    Prentice Hall, 1999.

    Examples
    --------
    >>> from timecave.utils import Nyquist_min_samples
    >>> n_samples = Nyquist_min_samples(100, 20);
    Nyquist theorem results
    -----------------------
    Maximum frequency that can be extracted using a sampling frequency of 100 Hz : 50.0 Hz
    Sampling rate required to capture a frequency of 20 Hz : 40 Hz
    ------------------------------------------------------------------------------------------
    Minimum number of samples required to capture a frequency of 20 Hz with a
    sampling frequency of 100 Hz: 10 samples
    >>> n_samples
    10

    If the frequency of interest cannot be captured using the sampling frequency provided \
    by the user according to the Nyquist theorem, an exception is thrown:

    >>> samples = Nyquist_min_samples(1, 2);
    Traceback (most recent call last):
    ...
    Warning: According to the Nyquist theorem, the selected frequency cannot be captured using this sampling frequency.

    If negative frequencies are passed, or if their values are neither integers nor floats, exceptions are thrown as well:

    >>> samples = Nyquist_min_samples(-2, 1);
    Traceback (most recent call last):
    ...
    ValueError: Frequencies should be non-negative.
    >>> samples = Nyquist_min_samples(1, "a");
    Traceback (most recent call last):
    ...
    TypeError: Both 'fs' and 'freq_limit' should be either integers or floats.
    """

    _check_frequencies(fs, freq_limit);
    _check_Nyquist(fs, freq_limit);

    ts = 1 / fs;
    T_limit = 1 / freq_limit;
    t_final = 2 * T_limit;
    n_samples = int(np.ceil(t_final / ts));

    print("Nyquist theorem results");
    print("-----------------------");

    print(f"Maximum frequency that can be extracted using a sampling frequency of {fs} Hz : {fs/2} Hz");
    print(f"Sampling rate required to capture a frequency of {freq_limit} Hz : {2*freq_limit} Hz");
    print("------------------------------------------------------------------------------------------");
    print(f"Minimum number of samples required to capture a frequency of {freq_limit} Hz with a");
    print(f"sampling frequency of {fs} Hz: {n_samples} samples");

    return n_samples;