visualdynamics.core.modal_response¶
modal_response
¶
Modal responses: how each mode of a model answers the forces a record holds, computed in modal coordinates.
A model's modes are a compact description of how it moves: a large finite element model has many more physical DOFs than modes in a bandwidth, and the response anywhere follows from the modal responses by u = Φq. So the response to a test's forces is computed and kept as modal responses, one record per mode, in a time history of their own on the forces' time axis; the physical response at any DOF is a later expansion.
The forces are made modal first, pᵣ = Σₖ φₖᵣ fₖ, the projection
transform.to_modal makes of a force record (a record already holding
modal forces is used as it is). Each mode r then answers its own
equation,
q̈ᵣ + 2ζᵣωᵣ q̇ᵣ + ωᵣ² qᵣ = pᵣ(t) / mᵣ,
with ωᵣ, ζᵣ and mᵣ the set's frequency, damping and modal mass (one for a mass-normalized set). It is solved exactly for a force that varies linearly between samples: the mode's state equation discretized with a first-order hold, which is a second-order recursive filter run over the record. Nothing else is approximated, so the start of a record, a transient, and a rigid-body mode (ωᵣ = 0, whose displacement under a net force grows without bound, as it does) are all answered as they are. The record starts at rest.
A force CPSD is answered the same way, line by line in frequency:
each mode's frequency response H_r carries the modal force density to
the modal response density, every mode against every other
(modal_response_density).
The response is a displacement, a velocity or an acceleration of each
modal coordinate, M1 … Mn named as everywhere in the package (the
mode's 1-based index in its set). Through a mass-normalized set the
units carry a half power of mass, the modal_* dimensions, as
transform gives them; through any other set they are left undeclared
and hinted.
References
.. [1] G. F. Franklin, J. D. Powell and M. L. Workman, Digital Control of Dynamic Systems, 3rd ed., Addison-Wesley, 1998, sec. 6.3.2 (the triangle-hold equivalent). .. [2] R. R. Craig and A. J. Kurdila, Fundamentals of Structural Dynamics, 2nd ed., Wiley, 2006, ch. 10.
Functions:
| Name | Description |
|---|---|
modal_forces |
The modal forces the record's force channels put on every mode of |
modal_responses |
Each picked mode's response to the record's forces, one record per |
modal_force_density |
The modal force CPSD the density's forces put on the set, |
modal_response_density |
Each picked mode's response to a force CPSD, as the modal |
preview_responses |
|
Classes¶
Functions:¶
modal_forces
¶
modal_forces(history: TimeHistory, shapes: ShapeSet, records: Sequence[int] | None = None) -> TimeHistory
The modal forces the record's force channels put on every mode of
the set, one record per mode, M1 … Mn.
Force channels on DOFs the set covers are projected, pᵣ = Σ φₖᵣ fₖ; a record whose channels are already the set's modal forces is used as it is. Other channels (the responses) are passed over.
Raises:
| Type | Description |
|---|---|
ValueError
|
If no picked record is a force on a DOF the set covers, the set is complex or has no modes. |
Source code in src/visualdynamics/core/modal_response.py
modal_responses
¶
modal_responses(history: TimeHistory, shapes: ShapeSet, *, modes: Sequence[int] | None = None, quantity: str = 'acceleration', records: Sequence[int] | None = None, label: str = 'shapes') -> TimeHistory
Each picked mode's response to the record's forces, one record per
mode, at the modal coordinates M1 … Mn.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
history
|
TimeHistory
|
Evenly sampled, holding force channels on DOFs the set covers, or the set's modal forces. |
required |
shapes
|
ShapeSet
|
Real modes with frequency, damping and modal mass. |
required |
modes
|
sequence of int
|
Which modes, by index in the set from zero; every mode when omitted. |
None
|
quantity
|
str
|
'displacement', 'velocity' or 'acceleration' of each modal coordinate. |
'acceleration'
|
records
|
sequence of int
|
Which of the history's records are the forces; every force channel when omitted. |
None
|
label
|
str
|
The set's name, written into each record's comment, which is how the records find their shapes again when they are played on a geometry or merged in with the forces. |
'shapes'
|
Returns:
| Type | Description |
|---|---|
TimeHistory
|
One record per mode picked, on the history's own time axis. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the quantity is not one of |
Source code in src/visualdynamics/core/modal_response.py
modal_force_density
¶
The modal force CPSD the density's forces put on the set, S_pp = Φᵀ S_ff Φ, every mode against every mode.
It is transform.to_modal on the force records alone (the matrix
needs every cross term between the drives, and a density of
autospectra alone is refused there); a density whose records are
already the set's modal forces is used as it is, as a time history's
are in modal_forces.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the set is complex or has no modes, no picked record is a
force density, or as |
Source code in src/visualdynamics/core/modal_response.py
modal_response_density
¶
modal_response_density(density: Psd, shapes: ShapeSet, *, modes: Sequence[int] | None = None, quantity: str = 'acceleration', records: Sequence[int] | None = None, cross: bool = True) -> Psd
Each picked mode's response to a force CPSD, as the modal
response CPSD: every picked mode against every other, M1 … Mn.
The forces are made modal first, S_pp = Φᵀ S_ff Φ
(modal_force_density). Each mode answers its modal force through
its own frequency response H_r (ShapeSet.modal_frf), so with each
cross term stored as conj(Q_r)·Q_s, as DataArray.compute_cpsds
stores it,
S_qq,rs = conj(H_r) S_pp,rs H_s.
Expanding it through the shapes, Φ S_qq Φᵀ, gives conj(H) S_ff Hᵀ
with H the FRF matrix ShapeSet.synthesize_frf gives, so the
response density at the DOFs is the same as driving the synthesized
FRFs with the forces. A rigid mode's acceleration at 0 Hz is finite
(its (iω)² cancels its −ω² exactly); its displacement and velocity
there are nan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
density
|
Psd
|
A force CPSD with every cross term between the drives (zero terms, uncorrelated drives, are terms), or the set's modal force CPSD. |
required |
shapes
|
ShapeSet
|
Real modes with frequency, damping and modal mass. |
required |
modes
|
sequence of int
|
Which modes, by index in the set from zero; every mode when omitted. |
None
|
quantity
|
str
|
'displacement', 'velocity' or 'acceleration' of each modal coordinate. |
'acceleration'
|
records
|
sequence of int
|
Which of the density's records are the forces; every force record when omitted. |
None
|
cross
|
bool
|
Every pair of picked modes; with False, each mode's autospectrum alone, as a preview draws them. |
True
|
Returns:
| Type | Description |
|---|---|
Psd
|
One record per pair of picked modes (per mode without |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the quantity is not one of |
Source code in src/visualdynamics/core/modal_response.py
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | |
preview_responses
¶
preview_responses(history: TimeHistory, shapes: ShapeSet, *, modes: Sequence[int] | None = None, quantity: str = 'acceleration', records: Sequence[int] | None = None, label: str = 'shapes') -> TimeHistory
modal_responses over the first PREVIEW_SAMPLES of the record:
the same responses there, since each starts from rest at the
record's start.