bcam.indar.ema.Amplitudes

class bcam.indar.ema.Amplitudes(*, mech_poles: array - like | None = None, res_poles: tuple[array - like, array - like] | None = None, fs: float = 1.0, response: str = 'a', cond: float | None = None, solver: str = 'gelsd')

Fit amplitudes to MIMO exponential sums with fixed frequencies.

If \(h\) is an exponential sum representing a noisy Impulse Response Function (IRF), then

\[\begin{split}\begin{split} h_{k, ij} &= \im\Big(\sum_{l=1}^{n} A^l_{ij}\lambda_l^\nu s_l^k\Big) + \sum_{m}C^m_{ij}s_{b, m}^k \\ &= \text{estimated IRF} + \text{background}, \end{split}\end{split}\]

where \(n\) are the number of Degrees of Freedom (DoF), \(\lambda_l\) are the frequencies representing the modes of the mechanical system, \(s_l = e^{\lambda_l dt}\) are the corresponding poles, \(s_{b, m}\) are the poles representing the background (includes the noise), and \(A^l_{ij}\) and \(C^m_{ij}\) are the corresponding amplitudes. The exponent \(\nu\) depends on the type of response (displacement (0), velocity (1), or acceleration (2)).

The mechanical amplitudes \(A^l_{ij}\) satisfy Maxwell’s reciprocity theorem, that is, \(A^l_{ij} = A^l_{ji}\), and also the necessary condition \(\sum_l \im(A^l_{ij}) = 0\) for all \(i, j\).

By convention, mechanical frequencies have positive imaginary part. Since the IRF is real, the poles and amplitudes of the background should be either real or come in complex conjugate pairs.

Parameters:
mech_polesarray-like of complex, shape (n_dof,), optional

Poles representing the mechanical modes. If None, no mechanical modes are fitted.

res_polestuple of array-like, optional

Poles representing the background (residual). The first element is an array of real poles, and the second element is an array of complex poles. If None, no background is fitted.

fsfloat, default=1.

Sampling frequency (\(1/dt\)).

response{‘a’, ‘v’, ‘d’}, default=’a’

Type of response: ‘a’ for acceleration, ‘v’ for velocity, ‘d’ for displacement.

condfloat or None, optional

Condition number for least-squares solver. If None, machine precision is used.

solver{‘normal’, ‘gelsd’, ‘gelss’, ‘gelsy’}, default=’gelsd’

Solver to use for least-squares problems. ‘normal’ uses the normal equations, while the others use different LAPACK drivers for more stable solutions.

Attributes:
tensor_modes_array, shape (n_outputs, n_inputs, n_dof)

Amplitudes of the mechanical modes.

amps_HCoeffs

Amplitudes of the background (residual) poles, with attributes ‘real’ and ‘cx’ for real and complex poles, respectively.

Methods

fit(y)

Fit amplitudes.

get_metadata_routing()

Get metadata routing of this object.

get_params([deep])

Get parameters for this estimator.

irf_pred(X)

Predict IRF.

predict(X)

Predict the noisy IRF.

residual(X)

Predict background or residual.

score(X, y)

Return the coefficient of determination R^2 of the prediction.

set_params(**params)

Set the parameters of this estimator.

Notes

If \(h\) are the data, and \(\hat{h}\) is the estimated noisy IRF, then the least squares problem is solved using the Hilbert–Schmidt norm, that is, the objective function is proportional to

\[\norm{h - \hat{h}}^2_{\mathrm{HS}} = \sum_{i, j}\sum_{k=0}^{N-1} (N-k)(h_{k, ij} - \hat{h}_{k, ij})^2.\]

This norm gives more weight to the earlier part of the IRF, which appear more often when computing the output given an input.

When the IRF is accelerance, then the IRF contains a mass-term which introduces a Dirac delta at time zero, so the background will also contain this term, but the Dirac delta is approximated by frequencies with very high damping.

fit(y: array - like) Amplitudes

Fit amplitudes.

Parameters:
yarray-like, shape (n_outputs, n_inputs, n_samples)

Data to fit representing the IRF.

Returns:
selfAmplitudes

Fitted estimator.

get_metadata_routing()

Get metadata routing of this object.

Please check User Guide on how the routing mechanism works.

Returns:
routingMetadataRequest

A MetadataRequest encapsulating routing information.

get_params(deep=True)

Get parameters for this estimator.

Parameters:
deepbool, default=True

If True, will return the parameters for this estimator and contained subobjects that are estimators.

Returns:
paramsdict

Parameter names mapped to their values.

irf_pred(X: array - like) ndarray

Predict IRF.

Parameters:
Xarray-like, shape (n_samples,)

Time samples.

Returns:
Knp.ndarray, shape (n_outputs, n_inputs, n_samples)

Predicted IRF. In case of accelerance, returns IRF without the mass-term.

predict(X: array - like) ndarray

Predict the noisy IRF.

Parameters:
Xarray-like, shape (n_samples,)

Time samples.

Returns:
Knp.ndarray, shape (n_outputs, n_inputs, n_samples)

Predicted noisy IRF.

residual(X: array - like) ndarray

Predict background or residual.

Parameters:
Xarray-like, shape (n_samples,)

Time samples.

Returns:
Knp.ndarray, shape (n_outputs, n_inputs, n_samples)

Predicted background.

score(X: array - like, y: array - like) float

Return the coefficient of determination R^2 of the prediction.

Parameters:
Xarray-like, shape (n_samples,)

Time samples.

yarray-like, shape (n_outputs, n_inputs, n_samples)

True values.

Returns:
scorefloat

Coefficient of determination.

set_params(**params)

Set the parameters of this estimator.

The method works on simple estimators as well as on nested objects (such as Pipeline). The latter have parameters of the form <component>__<parameter> so that it’s possible to update each component of a nested object.

Parameters:
**paramsdict

Estimator parameters.

Returns:
selfestimator instance

Estimator instance.