PyDMD / PyDMD

Python Dynamic Mode Decomposition

Home Page:https://pydmd.github.io/PyDMD/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Interest in adding frequency spectrum capabilities

roxyboy opened this issue · comments

Discussed in #491

Originally posted by roxyboy February 6, 2024
Hi PyDMD developers and users,

I was wondering if the community had any interest in having the capability to compute DMD-based frequency spectra.
The parts are already there (I think) within PyDMD to make this work.

The workflow would look something like this basing it off of Kutz et al. (2016):

def _freq(N, delta_x):
    # calculate frequencies from coordinates to be used for normalization
    # coordinates are always loaded eagerly, so we use numpy
    fftfreq = [numpy.fft.fftfreq] * len(N)
    k = [fftfreq(Nx, dx) for (fftfreq, Nx, dx) in zip(fftfreq, N, delta_x)]

    return k

def frequency_spectrum(X, delta_t, scaling='density'):
    """
    Compute frequency power spectrum based on DMD.

    Parameters
    ----------
    X : numpy.Array
        Data to take the power spectrum
    delta_t : float
        Spacing in time.
    scaling : str, optional
        If 'density', it will normalize the output to power spectral density.
        If 'spectrum', it will normalize the output to power spectrum.

    Returns
    --------
    freqs : numpy.Array
        Frequencies
    ps : numpy.Array
        Frequency power spectrum.
    """
    U, s, V, Atilde = compute_operator(X)   # imported from dmdoperator.py
    lamb, W = scipy.linalg.eig(Atilde)

    fbDMDfreqs = (numpy.log(lamb) / (2 * numpy.pi * delta_t)

    M = X.shape[-1]
    fbDMDpower = (numpy.abs(b) * (delta_t * M)) ** 2

    ftfreqs = _freq([M], [delta_t])  # frequencies to normalize the spectrum following Fourier convention

    if scaling == "density":
        ps = fbDMDpower * numpy.abs(ftfreqs)
    elif scaling == "spectrum":
        ps = fbDMDpower * numpy.abs(ftfreqs) ** 2

    return numpy.abs(fbDMDfreqs.imag), ps
``` </div>

I've realized that pyDMD outputs can be used in the following way so I'm going to close this :)

dmd = DMD(svd_rank=0)
dmd.fit(X.data.T)
fbDMDfreqs = numpy.abs((numpy.log(dmd.eigs) / (2 * np.pi * delta_t)).imag)
fbDMDpower = (numpy.abs(dmd.amplitudes) * (delta_t * len(X.time))) ** 2 * numpy.abs(ftfreqs)