"""Assembly of Campbell-diagram data from tracked modes.
A Campbell diagram plots modal natural frequency (and damping) against an operating
parameter — rotor speed or wind speed — with one curve per tracked mode. This
module pairs the mode tracks from :func:`vane.modal.identify_modes` with the
operating-parameter value of each operating point, producing a structure ready for
plotting or resonance analysis.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
import numpy as np
from vane.modal.identifier import identify_modes
if TYPE_CHECKING:
from collections.abc import Sequence
import numpy.typing as npt
from vane.modal.eigensolver import ModalSolution
from vane.modal.identifier import IdentificationResult, ModeTrack
__all__ = ["CampbellDiagram", "build_campbell", "campbell_from_solutions"]
[docs]
@dataclass
class CampbellDiagram:
"""Campbell-diagram data: tracked modes against an operating parameter.
Parameters
----------
parameter_values : npt.NDArray[np.float64]
Operating-parameter value (e.g. rotor speed in rev/min) at each operating
point, indexed by operating-point number, shape ``(n_operating_points,)``.
parameter_name : str
Name of the operating parameter (e.g. ``"rotor_speed_rpm"``).
tracks : list[ModeTrack]
The tracked modes, ordered by first natural frequency.
n_operating_points : int
Number of operating points.
"""
parameter_values: npt.NDArray[np.float64]
parameter_name: str
tracks: list[ModeTrack]
n_operating_points: int
[docs]
def track_curve(
self, track: ModeTrack
) -> tuple[
npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64]
]:
"""Return the operating-parameter, frequency, and damping arrays of a track.
Parameters
----------
track : ModeTrack
A track belonging to this diagram.
Returns
-------
tuple of npt.NDArray[np.float64]
``(parameter_values, natural_frequencies_hz, damping_ratios)`` along the
track, each of length equal to the track's span.
"""
x = self.parameter_values[track.operating_points]
return (
x,
np.asarray(track.natural_frequencies_hz, dtype=np.float64),
np.asarray(track.damping_ratios, dtype=np.float64),
)
[docs]
def build_campbell(
result: IdentificationResult,
parameter_values: Sequence[float],
*,
parameter_name: str = "rotor_speed_rpm",
) -> CampbellDiagram:
"""Build a Campbell diagram from identified mode tracks.
Parameters
----------
result : IdentificationResult
The cross-operating-point mode tracks.
parameter_values : Sequence[float]
Operating-parameter value at each operating point, in operating-point
order; its length must equal ``result.n_operating_points``.
parameter_name : str, optional
Name of the operating parameter (default ``"rotor_speed_rpm"``).
Returns
-------
CampbellDiagram
The assembled diagram.
Raises
------
ValueError
If ``parameter_values`` length does not match the number of operating
points.
"""
if len(parameter_values) != result.n_operating_points:
msg = (
f"parameter_values has {len(parameter_values)} entries but there are "
f"{result.n_operating_points} operating points"
)
raise ValueError(msg)
return CampbellDiagram(
parameter_values=np.asarray(parameter_values, dtype=np.float64),
parameter_name=parameter_name,
tracks=result.tracks,
n_operating_points=result.n_operating_points,
)
[docs]
def campbell_from_solutions(
solutions: Sequence[ModalSolution],
parameter_values: Sequence[float],
*,
parameter_name: str = "rotor_speed_rpm",
frequency_weight: float = 0.5,
mac_threshold: float = 0.5,
) -> CampbellDiagram:
"""Identify mode tracks from solutions and build a Campbell diagram.
Parameters
----------
solutions : Sequence[ModalSolution]
Modal solutions, one per operating point, in operating-point order.
parameter_values : Sequence[float]
Operating-parameter value at each operating point.
parameter_name : str, optional
Name of the operating parameter.
frequency_weight, mac_threshold : float, optional
Passed through to :func:`vane.modal.identify_modes`.
Returns
-------
CampbellDiagram
The assembled diagram.
"""
result = identify_modes(
solutions, frequency_weight=frequency_weight, mac_threshold=mac_threshold
)
return build_campbell(result, parameter_values, parameter_name=parameter_name)