pyyeti.ode.get_freq_damping¶
- pyyeti.ode.get_freq_damping(lam, suppress_warning=False)[source]¶
Get frequency and damping from complex eigenvalues
- Parameters:
lam (1d ndarray; shape = (2n,)) – Vector of potentially complex eigenvalues. Pairs are assumed to be adjacent. Furthermore, each pair of values in lam is assumed to be: \(-\omega_n (\zeta \pm \sqrt {\zeta^2 - 1})\). This is the case when lam are the eigenvalues of \(A\), where \(A\) is setup as shown in
eigss()(which has a \(-K\) in it as opposed to a \(+K\)).suppress_warning (bool; optional) – If True, do not print a warning if this routine finds that there are complex eigenvalues without an adjacent conjugate. Suppressing the warning can be useful for cases where the state-space matrix is complex. In that case, this routine may not be that useful, but there’s no use in printing a warning. See also the notes below.
- Returns:
wn (1d ndarray; shape = (n,)) – Vector of natural frequencies (rad/sec) in the same order as lam. wn is always greater than or equal to zero.
zeta (1d ndarray; shape = (n,)) – Vector of critical damping ratios:
|zeta|
description of eigenvalue pairs
< 1.0
underdamped; eigenvalues are complex conjugate pairs
= 1.0
critically damped; eigenvalues are real duplicates
> 1.0
overdamped; eigenvalues are real and unequal
Note
If zeta comes out negative, it could mean that the sign on lam is the opposite of that expected. Or, you have negative damping. If zeta should be positive for your problem, just change the sign on lam (and see description of the lam input).
Notes
The implicit assumption behind this routine is that the equations of motion are real (that the state-space matrix as documented in
SolveUncis real). If that is not true, this routine may or may not be helpful, probably depending on how close to real the system is. Note that this routine will issue a warning if it finds that there are complex eigenvalues without an adjacent conjugate (unless suppress_warning is True). The rest of the documentation assumes the system is real.The complex eigenvalue pairs for all cases (underdamped, critically damped, and overdamped) are:
\[\begin{split}\begin{aligned} \lambda_1 &= -\omega_n (\zeta + \sqrt {\zeta^2 - 1}) \\ \lambda_2 &= -\omega_n (\zeta - \sqrt {\zeta^2 - 1}) \end{aligned}\end{split}\]The eigenvalue pairs will be real if \(|\zeta| >= 1.0\) and complex conjugates otherwise.
The natural frequency \(\omega_n\) is computed by taking the square-root of the product of the eigenvalue pairs. This works for underdamped, critically damped, and overdamped cases:
\[\omega_n = \sqrt{\lambda_1 \lambda_2}\]Because:
\[\begin{split}\begin{aligned} \lambda_1 \lambda_2 &= \omega_n (\zeta + \sqrt {\zeta^2 - 1}) \omega_n (\zeta - \sqrt {\zeta^2 - 1}) \\ &= \omega_n^2 (\zeta^2 - (\zeta^2 - 1) \\ &= \omega_n^2 \end{aligned}\end{split}\]Once \(\omega_n\) is known, \(\zeta\) can be computed by dividing the sum of the eigenvalue pairs by \(-2 \omega_n\):
\[\begin{split}\begin{aligned} \zeta &= -\frac{\lambda_1 + \lambda_2}{2 \omega_n} \\ &= \frac{\omega_n (\zeta + \sqrt {\zeta^2 - 1}) + \omega_n (\zeta - \sqrt {\zeta^2 - 1})} {2 \omega_n} \\ &= \frac{2 \omega_n \zeta}{2 \omega_n} \\ &= \zeta \end{aligned}\end{split}\]Note
This routine will give incorrect results without warning if any real eigenvalue is not adjacent to its pair. (A complex eigenvalue that is not adjacent to its pair will trigger a warning.)
- Raises:
ValueError – When length of lam is not even (eigenvalues must be in pairs)
Examples
Set up a diagonal system of equations with known natural frequencies and damping. Then, to demo the routine, put the equations into state-space form (as shown in
SolveUnc), compute eigenvalues, call this routine, and check results:>>> import numpy as np >>> import scipy.linalg as la >>> from pyyeti import ode >>> >>> m = np.array([10.0, 11.0, 12.0, 13.0]) # mass >>> k = np.array([6.0e5, 7.0e5, 8.0e5, 9.0e5]) # stiffness >>> zeta = np.array([0.2, 0.05, 1.0, 2.0]) # percent damping >>> >>> wn = np.sqrt(k / m) >>> >>> b = 2.0 * zeta * np.sqrt(k / m) * m # damping >>> >>> # solve eigenvalue problem on state-space equations: >>> A = ode.make_A(m, b, k) >>> lam, phi = la.eig(A) >>> wn_extracted, zeta_extracted = ode.get_freq_damping(lam) >>> >>> # check results: >>> i = np.argsort(wn_extracted) >>> np.allclose(wn_extracted[i], wn) True >>> np.allclose(zeta_extracted[i], zeta) True
Check sign convention. The first input follows the sign convention described above, so should result in a positive 60% damping. The second is the opposite, so should give -60% damping:
>>> ode.get_freq_damping([-3+4j, -3-4j]) (array([ 5.]), array([ 0.6])) >>> ode.get_freq_damping([3+4j, 3-4j]) (array([ 5.]), array([-0.6]))