Code documentation

The Model class

class pyEMA.Model(frf=None, freq=None, dt=None, lower=50, upper=10000, pol_order_high=100, pyfrf=False, get_partfactors=False, driving_point=None, frf_type='accelerance')[source]

Modal model of frequency response functions.

__init__(frf=None, freq=None, dt=None, lower=50, upper=10000, pol_order_high=100, pyfrf=False, get_partfactors=False, driving_point=None, frf_type='accelerance')[source]
Parameters:
  • frf (ndarray) – Frequency response function matrix A ndarray with shape (n_locations, n_frequency_points).

  • freq (array) – Frequency array

  • lower (int, float) – Lower limit for pole determination [Hz]

  • upper (int, float) – Upper limit for pole determination [Hz]

  • pol_order_high (int) – Highest order of the polynomial

  • pyfrf (bool) – add FRFs directly from the pyFRF object

  • get_partfactors (bool) – calculate the participation factors.

  • point (driving) – the index of the driving point (used to scale the modal constants to modal shapes)

  • frf_type – type of the Frequency Response Function. Must be ‘receptance’, ‘mobility’ or ‘accelerance’. The correct FRF type selection is important for the LSFD algorithm.

add_frf(pyfrf_object)[source]

Add an FRF at a next location.

This method can be used in relation to pyFRF from Open Modal (https://github.com/openmodal)

Parameters:

pyfrf_object (object) – FRF object from pyFRF

get_poles(method='lscf', show_progress=True)[source]

Compute poles based on polynomial approximation of FRF.

Source: https://github.com/openmodal/OpenModal/blob/master/OpenModal/analysis/lscf.py

The LSCF method is an frequency-domain Linear Least Squares estimator optimized for modal parameter estimation. The choice of the most important algorithm characteristics is based on the results in [1] (Section 5.3.3.) and can be summarized as:

  • Formulation: the normal equations [1]

(Eq. 5.26: [sum(Tk - Sk.H * Rk^-1 * Sk)]*ThetaA=D*ThetaA = 0) are constructed for the common denominator discrete-time model in the Z-domain. Consequently, by looping over the outputs and inputs, the submatrices Rk, Sk, and Tk are formulated through the use of the FFT algorithm as Toeplitz structured (n+1) square matrices. Using complex coefficients, the FRF data within the frequency band of interest (FRF-zoom) is projected in the Z-domain in the interval of [0, 2*pi] in order to improve numerical conditioning. (In the case that real coefficients are used, the data is projected in the interval of [0, pi].) The projecting on an interval that does not completely describe the unity circle, say [0, alpha*2*pi] where alpha is typically 0.9-0.95. Deliberately over-modeling is best applied to cope with discontinuities. This is justified by the use of a discrete time model in the Z-domain, which is much more robust for a high order of the transfer function polynomials.

  • Solver: the normal equations can be solved for the

denominator coefficients ThetaA by computing the Least-Squares (LS) or mixed Total-Least-Squares (TLS) solution. The inverse of the square matrix D for the LS solution is computed by means of a pseudo inverse operation for reasons of numerical stability, while the mixed LS-TLS solution is computed using an SVD (Singular Value Decomposition).

Literature:
[1] Verboven, P., Frequency-domain System Identification for

Modal Analysis, Ph. D. thesis, Mechanical Engineering Dept. (WERK), Vrije Universiteit Brussel, Brussel, (Belgium), May 2002, (http://mech.vub.ac.be/avrg/PhD/thesis_PV_web.pdf)

[2] Verboven, P., Guillaume, P., Cauberghe, B., Parloo, E. and

Vanlanduit S., Stabilization Charts and Uncertainty Bounds For Frequency-Domain Linear Least Squares Estimators, Vrije Universiteit Brussel(VUB), Mechanical Engineering Dept. (WERK), Acoustic and Vibration Research Group (AVRG), Pleinlaan 2, B-1050 Brussels, Belgium, e-mail: Peter.Verboven@vub.ac.be, url: (http://sem-proceedings.com/21i/sem.org-IMAC-XXI-Conf-s02p01 -Stabilization-Charts-Uncertainty-Bounds-Frequency-Domain- Linear-Least.pdf)

[3] P. Guillaume, P. Verboven, S. Vanlanduit, H. Van der

Auweraer, B. Peeters, A Poly-Reference Implementation of the Least-Squares Complex Frequency-Domain Estimator, Vrije Universiteit Brussel, LMS International

Parameters:
  • method – The method of poles calculation.

  • show_progress – Show progress bar

select_poles()[source]

Select stable poles from stability chart.

Interactive pole selection is possible. Identification of natural frequency and damping coefficients is executed on-the-fly, as well as computing reconstructed FRF and modal constants.

The identification can be done in two ways:

# 1. Using stability chart
>>> a.select_poles() # pick poles
>>> a.nat_freq # natural frequencies
>>> a.nat_xi # damping coefficients
>>> a.H # reconstructed FRF matrix
>>> a.A # modal constants (a.A[:, -2:] are Lower and Upper residual)

# 2. Using approximate natural frequencies
>>> approx_nat_freq = [234, 545]
>>> a.select_closest_poles(approx_nat_freq)
>>> a.nat_freq # natural frequencies
>>> a.nat_xi # damping coefficients
>>> H, A = a.get_constants(whose_poles='own', FRF_ind='all) # reconstruction
select_closest_poles(approx_nat_freq, f_window=50, fn_temp=0.001, xi_temp=0.05)[source]

Identification of natural frequency and damping.

If approx_nat_freq is used, the method finds closest poles of the polynomial.

Parameters:
  • approx_nat_freq (list) – Approximate natural frequency value

  • f_window (float, int) – width of the optimization frequency window when searching for stable poles

get_constants(method='lsfd', whose_poles='own', FRF_ind='all', f_lower=None, f_upper=None, complex_mode=True, upper_r=True, lower_r=True, least_squares_type='new')[source]

Least square frequency domain 1D (Participation factor excluded)

Parameters:
  • whose_poles (object or string ('own'), optional) – Whose poles to use, defaults to ‘own’

  • FRF_ind (int or 'all', optional) – FRF at which location to reconstruct, defaults to ‘all’

  • f_lower (float, optional) – lower limit on frequency for reconstruction. If None, self.lower is used, defaults to None

  • f_upper (float, optional) – upper limit on frequency for reconstruction. If None, self.lower is used, defaults to None

  • complex_mode (bool, optional) – Return complex modes, defaults to True

  • upper_r (bool, optional) – Compute upper residual, defaults to True

  • lower_r (bool, optional) – Compute lower residual, defaults to True

Returns:

modal constants if FRF_ind=None, otherwise reconstructed FRFs and modal constants

FRF_reconstruct(FRF_ind)[source]

Reconstruct FRF based on modal constants.

Parameters:

FRF_ind – Reconstruct FRF on location with this index, int

Returns:

Reconstructed FRF

autoMAC()[source]

Auto Modal Assurance Criterion.

Returns:

autoMAC matrix

normal_mode()[source]

Transform the complex mode shape matrix self.A to normal mode shape.

The real mode shape should have the maximum correlation with the original complex mode shape. The vector that is most correlated with the complex mode, is the real part of the complex mode when it is rotated so that the norm of its real part is maximized. [1]

Literature:
[1] Gladwell, H. Ahmadian GML, and F. Ismail.

“Extracting Real Modes from Complex Measured Modes.”

Returns:

normal mode shape

print_modal_data()[source]

Show modal data in a table-like structure.

Stable pole selection

The SelectPoles class is called from the Model class by calling select_poles() method:

# Initiating the ``Model`` class
m = Model(...)
m.get_poles()

# Selecting the poles
m.select_poles()

In this case, the Model argument is passed automatically.

class pyEMA.pole_picking.SelectPoles(Model)[source]
__init__(Model)[source]

Plot the measured Frequency Response Functions and computed poles.

Picking the poles is done with pressing the SHIFT key + left mouse button. To unselect last pole: SHIFT + right mouse button. To unselect closest pole: SHIFT + middle mouse button.

For more information check the HELP menu tab in the chart window.

param model: object of pyEMA.Model

plot_frf(initial=False)[source]

Reconstruct and plot the Frequency Response Function.

This is done on the fly.

Parameters:

initial – if True, the frf is not computed, only the measured FRFs are shown.

get_stability(fn_temp=0.001, xi_temp=0.05)[source]

Get the stability matrix.

Parameters:
  • fn_temp – Natural frequency stability criterion.

  • xi_temp – Damping stability criterion.

plot_stability(update_ticks=False)[source]
plot_cluster(update_ticks=False)[source]

Plot clusters - damping with respect to frequency.

Parameters:

update_ticks – if True, only ticks are updated, not the whole plot.

get_closest_poles_stability()[source]

On-the-fly selection of the closest poles.

get_closest_poles_cluster()[source]

On-the-fly selection of the closest poles.

on_click(event)[source]
on_key_press(event)[source]

Function triggered on key press (SHIFT).

on_key_release(event)[source]

Function triggered on key release (SHIFT).

on_closing()[source]
toggle_legend(x)[source]
toggle_chart_type(x)[source]
toggle_mif_frf(x)[source]
sort_selected_poles()[source]
show_help()[source]
save_this_figure()[source]

Tools

pyEMA.tools.complex_freq_to_freq_and_damp(sr)[source]

Convert the complex natural frequencies to natural frequencies and the corresponding dampings.

A complex natural frequency is defined:

\[\lambda_r = -\zeta\,\omega_r \pm \mathrm{i}\,\omega_r\,\sqrt{1-\zeta^2},\]

where \(\lambda_r\) is the \(r\) th complex natural frequency and \(\omega_r\) and \(\zeta_r\) are the \(r\) th natural frequency [rad/s] and damping, respectively.

Parameters:

sr – complex natural frequencies

Returns:

natural frequency [Hz] and damping

pyEMA.tools.MAC(phi_X, phi_A)[source]

Modal Assurance Criterion.

The number of locations (axis 0) must be the same for phi_X and phi_A. The nubmer of modes (axis 1) is arbitrary.

Literature:
[1] Maia, N. M. M., and J. M. M. Silva.

“Modal analysis identification techniques.” Philosophical Transactions of the Royal Society of London. Series A: Mathematical, Physical and Engineering Sciences 359.1778 (2001): 29-40.

Parameters:
  • phi_X – Mode shape matrix X, shape: (n_locations, n_modes) or n_locations.

  • phi_A – Mode shape matrix A, shape: (n_locations, n_modes) or n_locations.

Returns:

MAC matrix. Returns MAC value if both phi_X and phi_A are one-dimensional arrays.

pyEMA.tools.MSF(phi_X, phi_A)[source]

Modal Scale Factor.

If phi_X and phi_A are matrices, multiple msf are returned.

The MAF scales phi_X to phi_A when multiplying: msf*phi_X. Also takes care of 180 deg phase difference.

Parameters:
  • phi_X – Mode shape matrix X, shape: (n_locations, n_modes) or n_locations.

  • phi_A – Mode shape matrix A, shape: (n_locations, n_modes) or n_locations.

Returns:

np.ndarray, MSF values

pyEMA.tools.MCF(phi)[source]

Modal complexity factor.

The MCF ranges from 0 to 1. It returns 0 for real modes and 1 for complex modes. When dtype of phi is complex, the modes can still be real, if the angles of all components are the same.

Additional information on MCF: http://www.svibs.com/resources/ARTeMIS_Modal_Help/Generic%20Complexity%20Plot.html

Parameters:

phi – Complex mode shape matrix, shape: (n_locations, n_modes) or n_locations.

Returns:

MCF (a value between 0 and 1)

Normal modes

pyEMA.normal_modes.complex_to_normal_mode(mode, max_dof=50, long=True)[source]

Transform a complex mode shape to normal mode shape.

The real mode shape should have the maximum correlation with the original complex mode shape. The vector that is most correlated with the complex mode, is the real part of the complex mode when it is rotated so that the norm of its real part is maximized. [1]

max_dof and long arguments are given for modes that have a large number of degrees of freedom. See _large_normal_mode_approx() for more details.

Literature:
[1] Gladwell, H. Ahmadian GML, and F. Ismail.

“Extracting Real Modes from Complex Measured Modes.”

Parameters:
  • mode – np.ndarray, a mode shape to be transformed. Can contain a single mode shape or a modal matrix (n_locations, n_modes).

  • max_dof – int, maximum number of degrees of freedom that can be in a mode shape. If larger, _large_normal_mode_approx() function is called. Defaults to 50.

  • long – bool, If True, the start in stepping itartion is altered, the angles of rotation are averaged (more in _large_normal_mode_approx()). This is needed only when max_dof is exceeded. The normal modes are more closely related to the ones computed with an entire matrix. Defaults to True.

Returns:

normal mode-shape

pyEMA.normal_modes._large_normal_mode_approx(mode, step, long)[source]

Get normal mode approximation for large modes.

In cases, where mode has n coordinates and n is large, this would result in a matrix U of size n x n. To find eigenvalues of this non-sparse matrix is computationally expensive. The solution is to find the angle of the rotation for the vector - this is done using only every step element of mode. The entire mode is then rotated, thus the full normal mode is obtained.

To ensure the influence of all the coordinates, a long parameter can be used. Multiple angles of rotation are computed and then averaged.

Parameters:
  • mode – a 2D mode shape or modal matrix (n_locations x n_modes)

  • step – int, every step elemenf of mode will be taken into account for angle of rotation calculation.

  • long – bool, if True, the angle of rotation is computed iteratively for different starting positions (from 0 to step), when every step element is taken into account.

Returns:

normal mode or modal matrix of mode.