dagghe/pyOMA2

Using FDD or EFDD in Multistep configuration

keltouny opened this issue · 3 comments

Hello,
I am getting the following error when trying to use either FDD or EFDD with multistep configuration with 1 reference sensor and 3 roving sensors:

Cell In[1], line 303
msp.MPE_fromPlot("FDD", freqlim=(0,freq_threshold))

File C:\Python39\envs\pyoma2\lib\site-packages\pyoma2\OMA.py:202 in MPE_fromPlot
self[name].mpe_fromPlot(*args, **kwargs)

File C:\Python39\envs\pyoma2\lib\site-packages\pyoma2\algorithm\fdd.py:191 in mpe_fromPlot
Fn_FDD, Phi_FDD = FDD_funct.FDD_MPE(

File C:\Python39\envs\pyoma2\lib\site-packages\pyoma2\functions\FDD_funct.py:293 in FDD_MPE
diffS1S2 = Sval[0, 0, idxlim[0] : idxlim[1]] / Sval[1, 1, idxlim[0] : idxlim[1]]

IndexError: index 1 is out of bounds for axis 0 with size 1

Dear @keltouny,
thank you for the feedback and for using our module.
You encountered this error because with only one reference sensor, the algorithm fails when it tries to verify that the peak you selected is indeed the point with the maximum ratio between the first and second singular values (since you only have one). While this check isn't strictly necessary to obtain a result, it is the expected behavior of the algorithm (as described in the books by Brinker & Ventura and Rainieri & Fabbrocino).
I will consider adding only a warning in such situations and will get back to you after further consideration.

Thank you for your response.

I have made changes to the FDD_MPE function "in src/pyoma2/functions/FDD_funct.py" to allow single-ref-channel FDD/EFDD to accommodate my project. I am sharing them here with you in case they help fix the problem. Also, thanks to your suggestion, I have added the warning message.

`def FDD_MPE(
Sval,
Svec,
freq,
sel_freq,
DF=0.1,
):
"""
Extracts modal parameters using the Frequency Domain Decomposition (FDD) method.

Parameters
----------
Sval : ndarray
    A 3D array of singular values. Dimensions are [Nch, Nref, Nf], where Nch is the
    number of channels, Nref is the number of reference channels, and Nf is the
    number of frequency points.
Svec : ndarray
    A 3D array of singular vectors corresponding to Sval. Dimensions are the same as Sval.
freq : ndarray
    1D array of frequency values corresponding to the singular values and vectors.
sel_freq : list or ndarray
    Selected frequencies around which modal parameters are to be extracted.
DF : float, optional
    Frequency bandwidth around each selected frequency within which the function
    searches for a peak. Default is 0.1.

Returns
-------
tuple
    Fn : ndarray
        Extracted modal frequencies.
    Phi : ndarray
        Corresponding normalized mode shapes (each column corresponds to a mode shape).

Note
-----
The function assumes that the first singular value and vector correspond to the dominant
mode at each frequency point.
"""
# Sval, Svec = SD_svalsvec(Sy)
Nch, Nref, Nf = Sval.shape

Freq = []
Fi = []
index = []
maxSy_diff = []
logger.info("Extracting FDD modal parameters")
if Nref == 1:
    logging.warning("Only 1 reference channel is used - Peak-searching is disabled")
for sel_fn in tqdm(sel_freq):
    if Nref > 1:    # peak serching is not available for single ref. ch.
        # Frequency bandwidth where the peak is searched
        lim = (sel_fn - DF, sel_fn + DF)
        idxlim = (
            np.argmin(np.abs(freq - lim[0])),
            np.argmin(np.abs(freq - lim[1])),
        )  # Indices of the limits
        # Ratios between the first and second singular value
        diffS1S2 = Sval[0, 0, idxlim[0] : idxlim[1]] / Sval[1, 1, idxlim[0] : idxlim[1]]
        maxDiffS1S2 = np.max(diffS1S2)  # Looking for the maximum difference
        idx1 = np.argmin(np.abs(diffS1S2 - maxDiffS1S2))  # Index of the max diff
        idxfin = idxlim[0] + idx1  # Final index
        maxSy_diff.append(maxDiffS1S2)
    else:
        idxfin = np.argmin(np.abs(freq - sel_fn))
    # Modal properties
    fn_FDD = freq[idxfin]  # Frequency
    phi_FDD = Svec[0, :, idxfin]  # Mode shape
    # Normalized (unity displacement)
    phi_FDDn = phi_FDD / phi_FDD[np.argmax(np.abs(phi_FDD))]

    Freq.append(fn_FDD)
    Fi.append(phi_FDDn)
    index.append(idxfin)
logger.debug("Done!")

Fn = np.array(Freq)
Phi = np.array(Fi).T
index = np.array(index)
return Fn, Phi`

Hi @keltouny thank you for your suggestion. @dagghe If you think we can apply these changes we can ask @keltouny to open a pr