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)