System Identification / Modal Analysis#
Covariance-driven SSI (BRSSICovRef) and PoGER multi-setup identification (PogerSSICovRef).
- class pyOMA.core.SSICovRef.BRSSICovRef(*args, **kwargs)[source]#
Bases:
ModalBaseReference-based Covariance-driven Stochastic Subspace Identification (SSI-Cov/Ref).
Builds a block-Toeplitz matrix from output cross-correlation functions, decomposes it via SVD, and identifies modal parameters at multiple model orders. The standard workflow is:
build_toeplitz_cov()— assemble and decompose the Toeplitz matrix.compute_modal_params()— run the multi-order modal identification.Pass the result to
StabilCalcfor stabilisation-diagram analysis.
- Parameters:
prep_signals (PreProcessSignals) – Pre-processed signal object providing correlation functions and channel metadata.
- build_toeplitz_cov(num_block_columns=None, num_block_rows=None, shift=0, num_blocks=None, training_blocks=None)[source]#
Builds a Block-Toeplitz Matrix of Covariances with varying time lags and decomposes it by a Singular Value decomposition.
<-num_block_columns * n_r -> _ [ R_m R_m-1 ... R_1 ]^ [ R_m+1 R_m ... R_2 ]num_block_rows * n_l [ ... ... ... ... ] [ R_2m-1 ... ... R_m ]v
The total number of block columns and block rows should not exceed the maximum time lag of pre-computed correlation functions:
num_block_columns + num_block_rows + shift < prep_signals.m_lags
- Parameters:
num_block_columns (integer, optional) – Number of block columns. By default, half the number of time lags are used
num_block_rows (integer, optional) – Number of block rows. By default it is set equal to num_block_columns
shift (integer, optional) – Allows the assembly of a shifted Block-Toeplitz matrix, s. t. the correlation function starting at shift is assembled into the block Toeplitz matrix
num_blocks (integer, optional) – The number of blocks to split the signal into for cross-validation. If given, correlation functions are (re-)estimated block-wise via
prep_signals.corr_blackman_tukey(m_lags, n_segments=num_blocks, refs_only=True)and only training_blocks are averaged into the Toeplitz matrix; the remaining blocks are then available forsynthesize_correlation()/compute_modal_params()via their validation_blocks argument. If not given (default), behaviour is unchanged: whatever correlation function is already cached inprep_signals(Welch or Blackman-Tukey, full signal) is used.training_blocks (list, optional) – The selected blocks to use for system identification (=training). Only meaningful together with num_blocks. Defaults to all blocks.
Note
Unlike the block handling in
PreProcessingTools.PreProcessSignalscorrelation estimation, num_blocks here does not persist any state on prep_signals beyond the per-block cache (corr_matrices_bt) thatcorr_blackman_tukeyitself maintains – the training-block average is used locally and does not overwriteprep_signals.corr_matrix_bt.
- compute_modal_params(max_model_order=None, max_modes=None, algo='svd', modal_contrib=True, validation_blocks=None)[source]#
Perform a multi-order computation of modal parameters. Successively calls
estimate_state(order, max_modes, algo)
modal_analysis(A,C)
synthesize_correlation(A,C, G), if modal_contrib == True
At ascending model orders, up to max_model_order. See the explanations in the the respective methods, for a detailed explanation of parameters.
- Parameters:
max_model_order (integer, optional) – Maximum model order, where to interrupt the algorithm. If not given, it is min(num_channels * (num_block_rows + 1), num_reference_channels * num_block_columns)
validation_blocks (list, optional) – Only meaningful if
build_toeplitz_cov()was called with num_blocks (cross-validation mode). Forwarded tosynthesize_correlation()at every order when modal_contrib is True.
- estimate_state(order, max_modes=None, algo='svd')[source]#
Compute the state matrix A, output matrix C and next-state-output covariance matrix G from the singular values and vectors of the block Toeplitz matrix, truncated at the requested order. Estimation of the state matrix can be performed by QR decomposition or Singular Value decomposition of the shifted observability matrix. If max_modes is specified, the singular value decomposition is truncated additionally, also known as Crystal Clear SSI.
- Parameters:
order (integer, required) – Model order, at which the state matrices should be estimated
max_modes (integer, optional) – Maximum number of modes, that are known to be present in the signal, to suppress noise modes
algo (str, optional) – Algorithm to use for estimation of A. Either ‘svd’ or ‘qr’.
- Returns:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
G (numpy.ndarray) – next-state-output covariance matrix : Array of shape (order, num_ref_channels)
- classmethod init_from_config(conf_file, prep_signals)[source]#
Initialise a modal analysis object from a text configuration file.
This is a stub that must be fully reimplemented by every derived class. Derived implementations typically read analysis parameters (e.g. model order, frequency range) from conf_file, call the relevant computation methods, and return the populated object.
- Parameters:
conf_file (str) – Path to a tab-separated key-value configuration file compatible with
ConfigFile.prep_signals (PreProcessSignals) – Pre-processed signal object for this setup.
- Returns:
Populated subclass instance.
- Return type:
- classmethod load_state(fname, prep_signals)[source]#
Restore a modal-analysis object from a previously saved archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Path to the
.npzarchive written bysave_state().prep_signals (PreProcessSignals) – Signal object for the same setup; used to validate the archive.
- Returns:
Restored subclass instance.
- Return type:
- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- modal_analysis(A, C, rescale_fun=None)[source]#
Computes the modal parameters from a given state space model as described by Peeters 1999 and Döhler 2012. Mode shapes are scaled to unit modal displacements. Complex conjugate and real modes are removed prior to further processing. Typically, order // 2 modes are in the returned arrays.
- Parameters:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
- Returns:
modal_frequencies ((order,) numpy.ndarray) – Array holding the modal frequencies for each mode
modal_damping ((order,) numpy.ndarray) – Array holding the modal damping ratios (0,100) for each mode
mode_shapes ((n_l, order,) numpy.ndarray) – Complex array holding the mode shapes
eigenvalues ((order,) numpy.ndarray) – Complex array holding the eigenvalues for each mode
- save_state(fname)[source]#
Save the current computation state to a compressed NumPy archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Destination file path (without
.npzextension).- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- synthesize_correlation(A, C, G, validation_blocks=None)[source]#
Correlation function synthetization in a modal decoupled form follows Reynders-2012-SystemIdentificationMethodsFor(Operational)ModalAnalysisReviewAndComparison Eq. 161 p. 74 (24) where Lambda are the correlation functions of the identified system
- Parameters:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
G (numpy.ndarray) – next-state-output covariance matrix : Array of shape (order, num_ref_channels)
validation_blocks (list, optional) – Only meaningful if
build_toeplitz_cov()was called with num_blocks (cross-validation mode). The selected blocks whose (block-wise, Blackman-Tukey) correlation function is used as ground truth for computing modal contributions, instead ofprep_signals.corr_matrix. Defaults to all blocks (matching the default oftraining_blocksinbuild_toeplitz_cov()– pass disjoint sets for a held-out validation).
- Returns:
corr_matrix_synth ((n_l, n_r, m_lags, n_modes) numpy.ndarray) – Array holding the modally decomposed correlation functions for each channel n_l and reference channel n_r and all modes
modal_contributions ((order,) numpy.ndarray) – Array holding the contributions of each mode to the input correlation function.
- synthesize_spectrum(A, C, G)[source]#
L = N*dt (duration = number_of_samples*sampling_period) P = N*df (maximal frequency = number of samples * frequency inverval)
dt * df = 1/N L * P = N
- write_config(conf_file)[source]#
Write the analysis parameters used to compute this object to a text configuration file readable by
init_from_config().This is a stub that must be fully reimplemented by every derived class (mirrors
init_from_config()): write the same keys that class’s owninit_from_config()reads, viawrite().- Parameters:
conf_file (str) – Path to write the configuration file to.
- class pyOMA.core.SSICovRef.PogerSSICovRef[source]#
Bases:
BRSSICovRefPost-Global Estimation and Re-scaling (PoGER) multi-setup SSI-Cov/Ref.
Merges correlation functions from multiple measurement setups by stacking them into a joint subspace matrix, then identifies global modal parameters via SSI-Cov/Ref. Partial mode shapes are rescaled in a least-squares sense to the reference DOFs of the first setup.
The standard workflow is:
For each setup, create a
PreProcessSignalsobject with pre-computed correlation functions and calladd_setup().pair_channels()— match channels across setups.build_merged_subspace_matrix()— assemble the joint Toeplitz matrix.compute_modal_params()— run the multi-order modal identification.
Notes
There are two distinct roles for reference channels:
Joint identification — channels shared across all setups, used to stack correlation functions (auto-determined from channel-DOF assignments).
Mode-shape rescaling — always relative to the first setup added; ensure the first setup has the best-quality measurements at the reference DOFs.
Todo
Add modal contributions
Implement PreGER merging with variance computation in a new class
References
Döhler, M. et al. “Pre- and post-identification merging for multi-setup OMA with covariance-driven SSI.” IMAC-XXVIII, 2010, pp. 57-70.
- add_setup(prep_signals)[source]#
todo: check that ref_channels are equal in each setup (by number and by DOF)
- build_merged_subspace_matrix(num_block_columns, num_block_rows=None)[source]#
Build and SVD-decompose the merged block-Toeplitz subspace matrix.
Stacks the correlation functions from all added setups into a joint block-Toeplitz matrix and decomposes it via SVD.
<- num_block_columns * num_ref_channels -> _ [ R_1 R_2 ... R_i ]^ [ R_2 R_3 ... R_i+1 ]num_block_rows * (n_l * num_setups) [ ... ... ... ... ]v [ R_i ... ... R_2i-1 ]_ R_k = [ R_k^{setup_1} ] [ R_k^{setup_2} ] [ ... ]
- Parameters:
num_block_columns (int) – Number of block columns in the joint Toeplitz matrix.
num_block_rows (int, optional) – Number of block rows. Defaults to num_block_columns.
- compute_modal_params(max_model_order=None, max_modes=None, algo='svd')[source]#
Perform a multi-order computation of modal parameters. Successively calls
estimate_state(order, max_modes, algo)
modal_analysis(A,C)
synthesize_correlation(A,C, G), if modal_contrib == True
At ascending model orders, up to max_model_order. See the explanations in the the respective methods, for a detailed explanation of parameters.
- Parameters:
max_model_order (integer, optional) – Maximum model order, where to interrupt the algorithm. If not given, it is min(num_channels * (num_block_rows + 1), num_reference_channels * num_block_columns)
validation_blocks (list, optional) – Only meaningful if
build_toeplitz_cov()was called with num_blocks (cross-validation mode). Forwarded tosynthesize_correlation()at every order when modal_contrib is True.
- classmethod load_state(fname)[source]#
Restore a modal-analysis object from a previously saved archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Path to the
.npzarchive written bysave_state().prep_signals (PreProcessSignals) – Signal object for the same setup; used to validate the archive.
- Returns:
Restored subclass instance.
- Return type:
- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- modal_analysis(A, C)[source]#
Computes the modal parameters from a given state space model as described by Peeters 1999 and Döhler 2012. Mode shapes are scaled to unit modal displacements. Complex conjugate and real modes are removed prior to further processing. Typically, order // 2 modes are in the returned arrays.
- Parameters:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
- Returns:
modal_frequencies ((order,) numpy.ndarray) – Array holding the modal frequencies for each mode
modal_damping ((order,) numpy.ndarray) – Array holding the modal damping ratios (0,100) for each mode
mode_shapes ((n_l, order,) numpy.ndarray) – Complex array holding the mode shapes
eigenvalues ((order,) numpy.ndarray) – Complex array holding the eigenvalues for each mode
- pair_channels()[source]#
pairs channels from all given setups for the poger merging methods
ssi_reference channels are common to all setups rescale reference channels are common to at least two setups
finds common dofs from all setups and their respective channels generates new channel_dof_assignments with ascending channel numbers rescale reference channels are assumed to be equal to ssi_reference channels
- rescale_by_references(mode_shape)[source]#
This is PoGer Rescaling
extracts each setup’s reference and roving parts of the modeshape
compute rescaling factor from all setup’s reference channels using a least-squares approach
rescales each setup’s roving channels and assembles final modeshape vector
reference channel_pairs and final channel-dof-assignments have been determined by function pair_channels note: reference channels for SSI need not necessarily be reference channels for rescaling and vice versa
\(S_\phi \times \alpha = [n \times 1, 0 .. 0]\)
\(\phi^{ref}_i\) : Reference-sensor part of modeshape estimated from setup \(i = 0 .. n\) \(j_{max} = \operatorname{argmax}(\Pi_i |\phi^{ref}_i|)\) : maximal modal component in all setups → will be approximately scaled to 1, must belong to the same sensor in each setup
\[\begin{split}S_\phi = \begin{bmatrix} \phi^{ref}_{0,j_{max}}& \phi^{ref}_{1,j_{max}}& ..& ..& \phi^{ref}_{n,j_{max}} \\ \phi^{ref}_0& -\phi^{ref}_1& 0& ..& 0 \\ \phi^{ref}_0& 0& -\phi^{ref}_2& ..& 0 \\ . &. &. & . & . \\ . &. &. & . & . \\ \phi^{ref}_0& 0& 0& ..& -\phi^{ref}_n \\ 0& \phi^{ref}_1& -\phi^{ref}_2& ..& 0 \\ . &. & . & . & . \\ . &. & . & . & . \\ 0& \phi^{ref}_1& 0& ..& -\phi^{ref}_n \\ . &. & . & . & . \\ . &. & . & . & . \\ 0& 0& \phi^{ref}_2& ..& -\phi^{ref}_n \\ . &. & . & . & . \\ . &. & . & . & . \\ 0& 0& 0& \phi^{ref}_{n-1}& -\phi^{ref}_n \end{bmatrix}\end{split}\]if references are the same in all setups
dimensions \(= 1 + (n_{setups} ! )* n_{ref_{channels}} \times n_{setups}\)
not quite exact, since different setups may share different references
→ list based assembly of the \(S_\phi\) matrix
Data-driven SSI (SSIData, SSIDataMC) for operational modal analysis.
- class pyOMA.core.SSIData.SSIData(*args, **kwargs)[source]#
Bases:
SSIDataMCData-driven SSI without correlation synthesis (non-Monte-Carlo variant).
Identical workflow to
SSIDataMCbut skips the synthesis step (synth_sig=False), making it faster when variance estimation is not required.- compute_modal_params(max_model_order)[source]#
Perform a multi-order computation of modal parameters. Successively calls
estimate_state(order,)
modal_analysis(A,C)
at ascending model orders, up to max_model_order. See the explanations in the the respective methods, for a detailed explanation of parameters.
- Parameters:
max_model_order (integer, optional) – Maximum model order, where to interrupt the algorithm. If not given, it is determined from the previously computed subspace matrix.
- estimate_state(order, max_modes=None, algo='svd')[source]#
Compute the state matrix A and output matrix C from the singular values and vectors of the projection matrix, truncated at the requested order. Estimation of the state matrix can be performed by QR decomposition or Singular Value decomposition of the shifted observability matrix. If max_modes is specified, the singular value decomposition is truncated additionally, also known as Crystal Clear SSI.
- Parameters:
order (integer, required) – Model order, at which the state matrices should be estimated
max_modes (integer, optional) – Maximum number of modes, that are known to be present in the signal, to suppress noise modes
algo (str, optional) – Algorithm to use for estimation of A. Either ‘svd’ or ‘qr’.
- Returns:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
- class pyOMA.core.SSIData.SSIDataCV(*args, **kwargs)[source]#
Bases:
SSIDataMC- build_block_hankel(num_block_rows=None, num_blocks=1, training_blocks=None, reduced_projection=True)[source]#
Builds serveral Block-Hankel Matrices of the measured time series with varying time lags and estimates the subspace matrices from their LQ decompositions. Uniqueness of the subspace estimates is ensured by an intermediate LQ decomposition, where the diagonals of the L matrices are constrained to positive values. A subspace matrix estimate is computed by the mean over the training blocks leaving any remainig blocks for validation.
Note: Blocks are not completely i.i.d. as we borrow p+q timesteps from the previous block for the projection of a full block (assembly of Hankel matrix)
Todo
investigate correct scaling of the subspace matrices [sqrt(N_b), sqrt(N_b * num_blocks), sqrt(N_b*n_training_blocks)] ?
use sparse SVD (scipy.sparse.svds) to save memory and cpu time
- Parameters:
num_block_rows (integer, required) – The number of block rows of the Subspace matrix
num_blocks (integer, optional) – The number of blocks, used for cross-validation
training_blocks (list, optional) – The selected blocks to use for system identification (=training)
- synthesize_signals(A, C, Q, R, S, validation_blocks=None, N_offset=None, **kwargs)[source]#
Computes the modal response signals and the contribution of each mode. The algorithm follows Peeters 1999 and the Lyapunov equation is solved as a discrete-time algebraic Riccati equation (DARE). For long signals, the computation may become time-consuming, thus only time steps up to j may be used to synthesize the signal.
- Parameters:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
Q (numpy.ndarray) – state noise covariance matrix: Symmetric array of shape (order, order)
R (numpy.ndarray) – signal noise covariance matrix: Array of shape (num_analised_channels, num_analised_channels)
S (numpy.ndarray) – system noise - signal noise covariance matrix: Array of shape (order, num_analised_channels)
validation_blocks (list, optional) – The selected blocks to be synthethized and used for system validation.
N_offset (integer, optional) – The number of samples to be used from any previous block for Kalman-Filter startup.
- Returns:
sig_synth (numpy.ndarray, shape (num_analised_channels, j, order // 2)) – Array holding the modally decomposed input signals for each channel n_l and all modes
modal_contributions (numpy.ndarray, shape (order, )) – Array holding the contributions of each mode to the input signals.
- class pyOMA.core.SSIData.SSIDataMC(*args, **kwargs)[source]#
Bases:
ModalBaseReference-based Data-driven Stochastic Subspace Identification (SSI-Data/MC).
Identifies modal parameters from raw time-series data by constructing a block-Hankel matrix, computing its LQ decomposition, and extracting state- space models via SVD. The standard workflow is:
build_block_hankel()— build the projection matrix from raw data.compute_modal_params()— run the multi-order modal identification.Pass the result to
StabilCalcfor stabilisation-diagram analysis.
- Parameters:
prep_signals (PreProcessSignals) – Pre-processed signal object providing raw time-series and channel metadata.
TODO:: (..) –
define unit tests to check functionality after changes
add switch to keep synthesized time-histories
- build_block_hankel(num_block_rows=None, reduced_projection=True)[source]#
Builds a Block-Hankel Matrix of the measured time series with varying time lags and estimates the subspace matrix from its LQ decomposition.
<- num_time samples - num_block_rows-> _ [ y_0 y_1 ... y_(j-1) ]^ [ y_1 y_2 ... y_j ]num_block_rows (=i)*n_l [ ... ... ... ... ]v [ y_(2i-1) y_(2i) ... y_(2i+j-2) ]_
The notation mostly follows Peeters 1999.
- Parameters:
num_block_rows (integer, required) – The number of block rows of the Subspace matrix
- compute_modal_params(max_model_order=None, j=None, validation_blocks=None, synth_sig=True)[source]#
Perform a multi-order computation of modal parameters. Successively calls
estimate_state(order,)
modal_analysis(A,C)
synthesize_signals(A, C, Q, R, S, j)
at ascending model orders, up to max_model_order. See the explanations in the the respective methods, for a detailed explanation of parameters.
- Parameters:
max_model_order (integer, optional) – Maximum model order, where to interrupt the algorithm. If not given, it is determined from the previously computed subspace matrix.
- estimate_state(order)[source]#
Estimate the state matrices A, C and noise covariances Q, R and S from the subspace / projection matrix. Several methods exist, e.g.
Peeters 1999 Reference Based Stochastic Subspace Identification for OMA
DeCock 2007 Subspace Identification Methods
the algorithm used in BRSSICovRef.
Here, the first algorithm, a residual-based computation of Q, R and S, is implemented.
- Parameters:
order (integer, required) – The model order, at which to truncate the singular values of the projection Matrix P_i_ref
- Returns:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
Q (numpy.ndarray) – state noise covariance matrix: Symmetric array of shape (order, order)
R (numpy.ndarray) – signal noise covariance matrix: Array of shape (num_analised_channels, num_analised_channels)
S (numpy.ndarray) – system noise - signal noise covariance matrix: Array of shape (order, num_analised_channels)
- classmethod init_from_config(conf_file, prep_signals)[source]#
Initialise a modal analysis object from a text configuration file.
This is a stub that must be fully reimplemented by every derived class. Derived implementations typically read analysis parameters (e.g. model order, frequency range) from conf_file, call the relevant computation methods, and return the populated object.
- Parameters:
conf_file (str) – Path to a tab-separated key-value configuration file compatible with
ConfigFile.prep_signals (PreProcessSignals) – Pre-processed signal object for this setup.
- Returns:
Populated subclass instance.
- Return type:
- classmethod load_state(fname, prep_signals)[source]#
Restore a modal-analysis object from a previously saved archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Path to the
.npzarchive written bysave_state().prep_signals (PreProcessSignals) – Signal object for the same setup; used to validate the archive.
- Returns:
Restored subclass instance.
- Return type:
- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- modal_analysis(A, C, rescale_fun=None)[source]#
Computes the modal parameters from a given state space model as described by Peeters 1999 and Döhler 2012. Mode shapes are scaled to unit modal displacements. Complex conjugate and real modes are removed prior to further processing. Typically, order // 2 modes are in the returned arrays.
- Parameters:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
- Returns:
modal_frequencies (numpy.ndarray, shape (order,)) – Array holding the modal frequencies for each mode
modal_damping (numpy.ndarray, shape (order,)) – Array holding the modal damping ratios (0,100) for each mode
mode_shapes (numpy.ndarray, shape (n_l, order,)) – Complex array holding the mode shapes
eigenvalues (numpy.ndarray, shape (order,)) – Complex array holding the eigenvalues for each mode
- save_state(fname)[source]#
Save the current computation state to a compressed NumPy archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Destination file path (without
.npzextension).- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- synthesize_signals(A, C, Q, R, S, j=None, **kwargs)[source]#
Computes the modal response signals and the contribution of each mode. The algorithm follows Peeters 1999 and the Lyapunov equation is solved as a discrete-time algebraic Riccati equation (DARE). For long signals, the computation may become time-consuming, thus only time steps up to j may be used to synthesize the signal.
- Parameters:
A (numpy.ndarray) – State matrix: Array of shape (order, order)
C (numpy.ndarray) – Output matrix: Array of shape (num_analised_channels, order)
Q (numpy.ndarray) – state noise covariance matrix: Symmetric array of shape (order, order)
R (numpy.ndarray) – signal noise covariance matrix: Array of shape (num_analised_channels, num_analised_channels)
S (numpy.ndarray) – system noise - signal noise covariance matrix: Array of shape (order, num_analised_channels)
j (integer, optional) – length of signal to synthesize (number of timesteps)
- Returns:
sig_synth (numpy.ndarray, shape (num_analised_channels, j, order // 2)) – Array holding the modally decomposed input signals for each channel n_l and all modes
modal_contributions (numpy.ndarray, shape (order, )) – Array holding the contributions of each mode to the input signals.
- write_config(conf_file)[source]#
Write the analysis parameters used to compute this object to a text configuration file readable by
init_from_config().This is a stub that must be fully reimplemented by every derived class (mirrors
init_from_config()): write the same keys that class’s owninit_from_config()reads, viawrite().- Parameters:
conf_file (str) – Path to write the configuration file to.
Covariance-driven SSI with propagated parameter variances (VarSSIRef).
- class pyOMA.core.VarSSIRef.VarSSIRef(prep_signals)[source]#
Bases:
ModalBaseCovariance-driven SSI with first-order perturbation variance estimation.
Extends
BRSSICovRefwith analytical uncertainty propagation from measurement noise through the correlation functions, Toeplitz matrix, SVD, and eigendecomposition to the final modal parameters. Both covariance-based and projection-based subspace estimation are supported.The standard workflow is:
build_subspace_mat()— build the subspace matrix and its statistical properties.compute_state_matrices()— estimate state and output matrices.prepare_sensitivities()— pre-compute sensitivity matrices for variance propagation.compute_modal_params()— identify modal parameters with variances.
- Parameters:
prep_signals (PreProcessSignals) – Pre-processed signal object providing correlation functions and channel metadata.
TODO:: (..) –
define unit tests to check functionality after changes
optimize multi-order QR-based estimation routine
add mode-shape integration with variances
use Monte-Carlo sampling in the last step of variance propagation
- build_subspace_mat(num_block_columns, num_block_rows=None, num_blocks=None, subspace_method='covariance')[source]#
Builds a Block-Hankel Matrix of Covariances with varying time lags
R_1 R_2 … R_q |R_2 R_3 … R_q+1 |… … … … |R_p+1 … … R_p+q |
- compute_modal_params(max_model_order=None, debug=False, qr=True)[source]#
Compute modal parameters with variance estimation.
- compute_state_matrices(max_model_order=None, lsq_method='pinv')[source]#
computes the state and output matrix of the state-space-model by applying a singular value decomposition to the block-hankel-matrix of covariances the state space model matrices are obtained by appropriate truncation of the svd matrices at max_model_order the decision whether to take merged covariances is taken automatically
- classmethod init_from_config(conf_file, prep_signals)[source]#
Initialise a modal analysis object from a text configuration file.
This is a stub that must be fully reimplemented by every derived class. Derived implementations typically read analysis parameters (e.g. model order, frequency range) from conf_file, call the relevant computation methods, and return the populated object.
- Parameters:
conf_file (str) – Path to a tab-separated key-value configuration file compatible with
ConfigFile.prep_signals (PreProcessSignals) – Pre-processed signal object for this setup.
- Returns:
Populated subclass instance.
- Return type:
- classmethod load_state(fname, prep_signals)[source]#
Load a previously saved state from a compressed NumPy archive.
- prepare_sensitivities(variance_algo='fast', debug=False)[source]#
Prepare Jacobians and covariance matrices for variance propagation.
- write_config(conf_file)[source]#
Write the analysis parameters used to compute this object to a text configuration file readable by
init_from_config().This is a stub that must be fully reimplemented by every derived class (mirrors
init_from_config()): write the same keys that class’s owninit_from_config()reads, viawrite().- Parameters:
conf_file (str) – Path to write the configuration file to.
- pyOMA.core.VarSSIRef.vectorize(matrix)[source]#
- \[A=\begin{bmatrix} 1 & 2 & 3 \ 4 & 5 & 6 \ 7 & 8 & 9 \ \end{bmatrix}\]
returns vertically stacked columns of matrix A
..math:
\begin{bmatrix} 1 \ 4 \ 7 \ 2 \ 5 \ 8 \ 3 \ 6 \ 9 \ \end{bmatrix}
Eigensystem Realisation Algorithm (ERA) for operational modal analysis.
- class pyOMA.core.ERA.ERA(prep_signals)[source]#
Bases:
objectEigensystem Realisation Algorithm (ERA) for operational modal analysis.
Identifies state-space models and modal parameters from impulse-response or free-decay data by constructing a Hankel matrix and decomposing it via SVD. When forced-response data are available, call
CalculateFRF()first to convert them to impulse responses before callingbuild_hankel_matrix().- Parameters:
prep_signals (PreProcessSignals) – Pre-processed signal object providing
signals,sampling_rate, and channel metadata.
- CalculateFRF()[source]#
function by anil FRF(Frequency response function) is convertion of signal from time to frequency domain. The following function performs this conversion.
- build_hankel_matrix(num_block_columns)[source]#
Construct the shifted Hankel matrix from the impulse-response functions.
- Parameters:
num_block_columns (int) – Number of block columns in the Hankel matrix. The number of block rows is set to
num_block_columns + 1.
- compute_state_matrices(max_model_order=None)[source]#
Decompose the Hankel matrix and compute the observability matrix.
- Parameters:
max_model_order (int, optional) – Maximum model order to retain. When
None, the full rank of the Hankel matrix is used.
- classmethod load_state(fname, prep_signals)[source]#
Restore an
ERAobject from a previously saved archive.- Parameters:
fname (str) – Path to the
.npzarchive written bysave_state().prep_signals (PreProcessSignals) – Signal object for the same setup; used to validate the archive.
- Returns:
Restored object with all previously computed results.
- Return type:
Poly-reference Least-Squares Complex Frequency (pLSCF) identification method.
- class pyOMA.core.PLSCF.PLSCF(*args, **kwargs)[source]#
Bases:
ModalBasePoly-reference Least-Squares Complex Frequency (pLSCF) method.
Also known as PolyMAX. Identifies modal parameters from positive half-spectra derived from correlation functions. The standard workflow is:
build_half_spectra()— construct the positive half-spectra.compute_modal_params()— run the multi-order identification.Pass the result to
StabilCalcfor stabilisation-diagram analysis.
- Parameters:
prep_signals (PreProcessSignals) – Pre-processed signal object providing correlation functions and channel metadata.
TODO:: (..) –
Test functions should be added to the test package
- build_half_spectra(nperseg=None, begin_frequency=None, end_frequency=None, window_decay=0.001, num_blocks=None, training_blocks=None, **kwargs)[source]#
Extracts an array of positive half spectra between begin_frequency and end_frequency from a spectrum of nperseg frequency lines. If begin_frequency > 0.0 or end_frequency<nyquist freqeuncy, the resulting array has less than nperseg lines.
Positive power spectra are constructed from positive correlation functions, that are windowed by an exponential window and transformed to frequency domain by and (R)FFT. Correlation functions are computed in prep_signals by either Welch’s or Blackman-Tukey’s method, though, Welch’s method is not recommmended, because the artificial damping introduced by windowing can not be corrected.
See: Cauberghe-2004-Applied Frequency-Domain System … : Sections 3.4ff
Note: The previous implementation contained severe mistakes in the computation of positive power spectra, e.g. doubled squaring of spectral values, lazy handling of array dimensions and therefore effectively only a quarter of nperseg being used as well as numerical inefficiencies.
Todo
Move spectral estimation into prep_signals.pds_blackman_tukey and only keep bandwidth selection and argument checking here
Allow other windows than exponential
- Parameters:
nperseg (integer, optional) – Number of (positive) frequency lines to consider (rfft)
begin_frequency (float, optional) – Frequency range to restrict the identified system.
end_frequency (float, optional) – Frequency range to restrict the identified system.
window_decay (float, (0,1)) – Final value of the exponential window, that is applied to the correlation functions.
num_blocks (integer, optional) – The number of blocks to split the signal into for cross-validation. If given, correlation functions are (re-)estimated block-wise via
prep_signals.corr_blackman_tukey(nperseg, n_segments=num_blocks, refs_only=True)and only training_blocks are averaged into the half-spectrum; the remaining blocks are then available forsynthesize_spectrum()/compute_modal_params()via their validation_blocks argument. If not given (default), behaviour is unchanged: whatever correlation function is already cached inprep_signals(Welch or Blackman-Tukey, full signal) is used.training_blocks (list, optional) – The selected blocks to use for system identification (=training). Only meaningful together with num_blocks. Defaults to all blocks.
kwargs – Additional kwargs are passed to prep_signals.correlation
- compute_modal_params(max_model_order, complex_coefficients=False, algo='residuals', modal_contrib=None, validation_blocks=None)[source]#
Perform a multi-order computation of modal parameters. Successively calls
estimate_model(order, complex_coefficients)
modal_analysis_residuals(alpha, beta_l_i) or modal_analysis_state_space(alpha, beta_l_i)
synthesize_spectrum(alpha, beta_l_i), if modal_contrib == True
At ascending model orders, up to max_model_order. See the explanations in the the respective methods, for a detailed explanation of parameters.
- Parameters:
max_model_order (integer) – Maximum model order, where to interrupt the algorithm.
complex_coefficients (bool, optional) – Whether to estimate a real or complex RMFD model
algo (str, optional) – Algorithm to use for modal analysis. Either ‘state-space’ or ‘residuals’ Both algorithms are approximately equally fast. The state space based algorithm seems to yield less complex mode shapes.
modal_contrib (bool, optional) – Synthesize modal spectra and estimate modal contributions. Only to be used with residual-based modal analysis algorithm.
validation_blocks (list, optional) – Only meaningful if
build_half_spectra()was called with num_blocks (cross-validation mode). Forwarded tosynthesize_spectrum()at every order when modal_contrib is True.
- estimate_model(order, complex_coefficients=False)[source]#
Estimate a right matrix-fraction model from positive half-spectra, by constructing a set of reduced normal equations as shown in Peeters 2004. The polynomial is identified following Cauberghe 2004. Sec. 5.2.1
Verboven 2002: Sect. 5.3.3 has a discussion on the use of real or complex valued coefficients, favoring complex ones. Guillaume 2003, Peeters 2004 just assume real coefficients, while later references, e.g. Cauberghe 2004, Reynders 2012 use complex coefficients. However, with complex coefficients, stabilization diagrams seem to become corrupted.
Note: The previous implementation was wrong in the estimation of alpha coefficients and led to “bad” stabilization. Additionally there was a wrong sign in the assembly of the C_c matrix, which led to corrupted mode shapes.
Todo
implement weighting function; c.p. Peeters 2004 Sect. 2.2
improve assembly by exploiting the Toeplitz structure of S, R, T; c.p. Cauberghe 2004 Eq. 5.17ff
Investigate LS-TLS solution by using a SVD
estimate polynomial once at highest order and construct all lower order models from these coefficients; c.p. Peeters 2004 Sect. 2.4
Check, if alternative solution for lpha in Reynders 2012. Sec. 5.2.4 leads to clearer stabilization, or it it is actually equivalent to the current implementation
- Parameters:
order (integer, required) – Model order, at which the RMF model should be estimated
complex_coefficients (bool, optional) – Whether to assume real or complex coefficients
- Returns:
alpha (numpy.ndarray) – Denominator coefficients: Array of shape ((order + 1) * n_r, n_r)
beta_l_i (numpy.ndarray) – Numerator coefficients: Array of shape (order + 1, n_r, n_l)
- classmethod init_from_config(conf_file, prep_signals)[source]#
Initialise a modal analysis object from a text configuration file.
This is a stub that must be fully reimplemented by every derived class. Derived implementations typically read analysis parameters (e.g. model order, frequency range) from conf_file, call the relevant computation methods, and return the populated object.
- Parameters:
conf_file (str) – Path to a tab-separated key-value configuration file compatible with
ConfigFile.prep_signals (PreProcessSignals) – Pre-processed signal object for this setup.
- Returns:
Populated subclass instance.
- Return type:
- classmethod load_state(fname, prep_signals)[source]#
Restore a modal-analysis object from a previously saved archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Path to the
.npzarchive written bysave_state().prep_signals (PreProcessSignals) – Signal object for the same setup; used to validate the archive.
- Returns:
Restored subclass instance.
- Return type:
- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- modal_analysis_residuals(alpha, *args)[source]#
Perform a modal analysis of the identified polyomial with the least-squares residual-based method as outlined in Steffensen-2025-VarianceEstimation… Sect. 2.1 Mode shapes are scaled to unit modal displacements. Complex conjugate and real modes are removed prior to further processing. Damping values are corrected, if half-spectra were constructed with an exponential window.
Todo
numerical optimization to increase speed
- Parameters:
alpha (numpy.ndarray) – Denominator coefficients: Array of shape ((order + 1) * n_r, n_r)
- Returns:
modal_frequencies ((order * n_r,) numpy.ndarray) – Array holding the modal frequencies for each mode
modal_damping ((order * n_r,) numpy.ndarray) – Array holding the modal damping ratios (0,100) for each mode
mode_shapes ((n_l, order * n_r,) numpy.ndarray) – Complex array holding the mode shapes
eigenvalues ((order * n_r,) numpy.ndarray) – Complex array holding the _eigenvalues for each mode
- modal_analysis_state_space(alpha, beta_l_i)[source]#
Perform a modal analysis of the identified polyomial by converting it into a state-space model, as outlined in Reynders-2012: Lemma 2.2, followed by an eigendecomposition. Mode shapes are scaled to unit modal displacements. Complex conjugate and real modes are removed prior to further processing. Damping values are corrected, if half-spectra were constructed with an exponential window.
Todo
numerical optimization to increase speed
- Parameters:
alpha (numpy.ndarray) – Denominator coefficients: Array of shape ((order + 1) * n_r, n_r)
beta_l_i (numpy.ndarray) – Numerator coefficients: Array of shape (order + 1, n_r, n_l)
- Returns:
modal_frequencies ((order * n_r,) numpy.ndarray) – Array holding the modal frequencies for each mode
modal_damping ((order * n_r,) numpy.ndarray) – Array holding the modal damping ratios (0,100) for each mode
mode_shapes ((n_l, order * n_r,) numpy.ndarray) – Complex array holding the mode shapes
eigenvalues ((order * n_r,) numpy.ndarray) – Complex array holding the eigenvalues for each mode
- save_state(fname)[source]#
Save the current computation state to a compressed NumPy archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Destination file path (without
.npzextension).- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- synthesize_spectrum(alpha, beta_l_i, modal=True, validation_blocks=None)[source]#
Spectral synthetization in a modal decoupled form follows Steffensen-2025-VarianceEstimation… Sect. 2.1.2 The spectral synthetization without modal decomposition follows Peeters-2004-ThePolyMAX…
Todo
numerical optimization to increase speed
- Parameters:
alpha (numpy.ndarray) – Denominator coefficients: Array of shape ((order + 1) * n_r, n_r)
beta_l_i (numpy.ndarray) – Numerator coefficients: Array of shape (order + 1, n_r, n_l)
modal (bool, optional) – Synthesize a spectrum for each mode and its modal contribution to the full spectrum
validation_blocks (list, optional) – Only meaningful if
build_half_spectra()was called with num_blocks (cross-validation mode) and modal is True. The selected blocks whose (block-wise, Blackman-Tukey) half-spectrum is used as ground truth for computing modal contributions, instead ofself.pos_half_spectra. Defaults to all blocks (matching the default oftraining_blocksinbuild_half_spectra()– pass disjoint sets for a held-out validation).
- Returns:
half_spec_modal ((n_l, n_r, num_omega, n_modes) numpy.ndarray) – Array holding the (modally decomposed) synthesized positive half spectra for each channel n_l and reference channel n_r and all modes
modal_contributions ((order,) numpy.ndarray) – Array holding the contributions of each mode to the input spectrum
- write_config(conf_file)[source]#
Write the analysis parameters used to compute this object to a text configuration file readable by
init_from_config().This is a stub that must be fully reimplemented by every derived class (mirrors
init_from_config()): write the same keys that class’s owninit_from_config()reads, viawrite().- Parameters:
conf_file (str) – Path to write the configuration file to.
Poly-reference Complex Exponential (PRCE) identification method.
- class pyOMA.core.PRCE.PRCE(*args, **kwargs)[source]#
Bases:
ModalBasePoly-reference Complex Exponential (PRCE) identification method.
Identifies modal parameters from a 3-D tensor of cross-correlation functions using the Complex Exponential approach. The standard workflow is:
build_corr_tensor()— assemble the correlation tensor.compute_modal_params()— run the multi-order identification.Pass the result to
StabilCalcfor stabilisation-diagram analysis.
- Parameters:
prep_signals (PreProcessSignals) – Pre-processed signal object.
- build_corr_tensor(num_corr_samples)[source]#
Builds a 3D Tensor of cross correlation functions with the following directions: 1 - related to reference channels 2 - all channels 3 - time
- compute_modal_params(max_model_order)[source]#
Compute modal parameters for all model orders up to max_model_order.
- classmethod init_from_config(mod_ID_file, prep_signals)[source]#
Initialise a modal analysis object from a text configuration file.
This is a stub that must be fully reimplemented by every derived class. Derived implementations typically read analysis parameters (e.g. model order, frequency range) from conf_file, call the relevant computation methods, and return the populated object.
- Parameters:
conf_file (str) – Path to a tab-separated key-value configuration file compatible with
ConfigFile.prep_signals (PreProcessSignals) – Pre-processed signal object for this setup.
- Returns:
Populated subclass instance.
- Return type:
- classmethod load_state(fname, prep_signals)[source]#
Restore a modal-analysis object from a previously saved archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Path to the
.npzarchive written bysave_state().prep_signals (PreProcessSignals) – Signal object for the same setup; used to validate the archive.
- Returns:
Restored subclass instance.
- Return type:
- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- save_state(fname)[source]#
Save the current computation state to a compressed NumPy archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Destination file path (without
.npzextension).- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- write_config(conf_file)[source]#
Write the analysis parameters used to compute this object to a text configuration file readable by
init_from_config().This is a stub that must be fully reimplemented by every derived class (mirrors
init_from_config()): write the same keys that class’s owninit_from_config()reads, viawrite().- Parameters:
conf_file (str) – Path to write the configuration file to.
Base class shared by all pyOMA system-identification methods.
- class pyOMA.core.ModalBase.ModalBase(prep_signals=None)[source]#
Bases:
objectBase class from which all pyOMA system-identification classes inherit.
Provides shared functionality (conjugate removal, mode-shape integration, rescaling, persistence) so that derived classes only implement the method-specific identification steps. Post-processing tools (stabilization diagram, mode-shape plot) accept any
ModalBasesubclass instance.- prep_signals#
The signal object from which this analysis was created.
- Type:
PreProcessSignals or None
- setup_name#
Human-readable label for the measurement setup.
- Type:
str
- start_time#
Timestamp of the measurement.
- Type:
datetime.datetime or None
- num_analised_channels#
Total number of analysis channels.
- Type:
int or None
- num_ref_channels#
Number of reference channels.
- Type:
int or None
- max_model_order#
Maximum model order used in the identification.
- Type:
int or None
- modal_frequencies#
Identified natural frequencies (Hz), shape
(max_model_order, n_modes).- Type:
np.ndarray or None
- modal_damping#
Identified modal damping ratios (%), same shape as
modal_frequencies.- Type:
np.ndarray or None
- mode_shapes#
Identified mode shapes, shape
(n_channels, n_modes, max_model_order).- Type:
np.ndarray or None
- eigenvalues#
Identified (complex) eigenvalues.
- Type:
np.ndarray or None
- classmethod init_from_config(conf_file, prep_signals)[source]#
Initialise a modal analysis object from a text configuration file.
This is a stub that must be fully reimplemented by every derived class. Derived implementations typically read analysis parameters (e.g. model order, frequency range) from conf_file, call the relevant computation methods, and return the populated object.
- Parameters:
conf_file (str) – Path to a tab-separated key-value configuration file compatible with
ConfigFile.prep_signals (PreProcessSignals) – Pre-processed signal object for this setup.
- Returns:
Populated subclass instance.
- Return type:
- static integrate_quantities(vector, accel_channels, velo_channels, omega)[source]#
Rescales mode shapes from modal accelerations / velocities to modal displacements, by multiplication of the relevant modal coordinates (where accelerometers, or velocimeters were used, with $-1 omega^2$ or $i omega$, respectively,
- Parameters:
vector ((n_channels,) numpy.ndarray) – Complex modeshape for all n_channels
accel_channels (list) – A list containing the channel numbers of all acceleration channels
velo_channels (list) – A list containing the channel numbers of all velocity channels
omega (float) – The circular frequency of the corresponding mode ($omega = 2 pi f$)
- Returns:
vector – Rescaled complex modeshape for all n_channels
- Return type:
(n_channels,) numpy.ndarray
- classmethod load_state(fname, prep_signals)[source]#
Restore a modal-analysis object from a previously saved archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Path to the
.npzarchive written bysave_state().prep_signals (PreProcessSignals) – Signal object for the same setup; used to validate the archive.
- Returns:
Restored subclass instance.
- Return type:
- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- static remove_conjugates(eigval, eigvec_r=None, eigvec_l=None, inds_only=False)[source]#
This method finds complex conjugate modes, and removes unstable and overdamped poles.
A complex conjugate is defined as: \(\lambda_i = \overline{\lambda_j} \text{ for } i \neq j\)
Unstable poles, i.e. negatively damped poles, are defined by: \([\ln(|\lambda|)<0]: |\lambda_i|> 1\)
Overdamped poles, are purely real poles: \([\operatorname{atan}(\Im/\Re)=0]: \Im(\lambda_i)=0\)
The method keeps the second occurance of a conjugate pair (usually the one with the negative imaginary part) and either returns a truncated set of eigenvalues and eigenvectors or a list of (physical) poles that can be iterated.
- Parameters:
eigval ((order,) numpy.ndarray) – Complex array of all eigenvalues
eigvec_r ((order, n_channels) numpy.ndarray, optional) – Complex array(s) of all right (left) eigenvectors
eigvec_l ((order, n_channels) numpy.ndarray, optional) – Complex array(s) of all right (left) eigenvectors
inds_only (bool, optional) – Whether to return a list of pole indices, or a reduced set of eigenvalues and eigenvectors
- Returns:
conj_indices (list) – list of (physical) pole indices
eigval ((order,) numpy.ndarray) – Complex array of reduced (physical) eigenvalues
eigvec_l, eigvec_r ((order, n_channels) numpy.ndarray, optional) – Complex array(s) of reduced (physical) left (right) eigenvectors
- static rescale_mode_shape(modeshape, rotate_only=False)[source]#
Rescales and rotates modeshapes in the complex plane. Default behaviour is to scale the larges component to unit modal displacement. If argument rotate_only is provided, the method given in Appendix C2 of Doehler 2013 (doi:0.1016/j.ymssp.2012.11.011) is used to rotate but not rescale the mode shape. Note: The scale of identified mode shapes is arbitrary in most OMA methods.
- Parameters:
modeshape ((n_channels,) numpy.ndarray) – Complex modeshape for all n_channels
rotate_only (bool, optional) – Whether to rotate, but not rescale, the mode shape.
- Returns:
modeshape – Rescaled complex modeshape for all n_channels
- Return type:
(n_channels,) numpy.ndarray
- save_state(fname)[source]#
Save the current computation state to a compressed NumPy archive.
Must be fully reimplemented by every derived class.
- Parameters:
fname (str) – Destination file path (without
.npzextension).- Raises:
NotImplementedError – Always, unless overridden by a derived class.
- write_config(conf_file)[source]#
Write the analysis parameters used to compute this object to a text configuration file readable by
init_from_config().This is a stub that must be fully reimplemented by every derived class (mirrors
init_from_config()): write the same keys that class’s owninit_from_config()reads, viawrite().- Parameters:
conf_file (str) – Path to write the configuration file to.