Campbell diagram, resonance, and uncertainty

With the modes identified and tracked, VANE assembles the Campbell diagram, locates the excitation resonances on it, and attaches a confidence to every mode. The confidence is built from the numerical conditioning, the azimuth sensitivity and the tracking quality of the mode. It can set the initial covariance of an estimator; see Realization, reduction, and observability and LPV export, load maps, and estimation.

The sweep axis

Tracking links modes between adjacent operating points, so the sweep must be ordered along a strictly monotonic operating parameter. Rotor speed increases below rated but is constant above it, where the trimmed values differ only by round-off. Sorting by those values would order the points arbitrarily and link points that are not neighbours. vane.pipeline.ModalPipeline.run() therefore rejects an axis on which two points lie within parameter_rtol (default \(10^{-4}\)) times the largest-magnitude value on the axis, far above round-off and far below a physical sweep step, and recommends the wind-speed axis, which stays monotonic across rated. vane.campbell.build_campbell() requires a finite, strictly increasing axis.

Excitation lines and resonance

A rotor turning at \(\Omega\) excites the structure at integer multiples of the rotational frequency, the \(nP\) lines at \(f = n\,\mathrm{rpm}/60\). vane.campbell.find_resonances() tests 1P, 3P, 6P and 9P by default. A potential resonance occurs where a mode line crosses an \(nP\) line. Each crossing is located by a sign change of \(f_{\text{mode}} - n\,\mathrm{rpm}/60\) between adjacent operating points, and the rotor speed, frequency and damping ratio at the crossing are interpolated linearly. Each crossing carries a damping-based severity: high below a damping ratio of 0.01, medium below 0.05, and low otherwise, since a lightly damped mode at a crossing can build a large response. An optional operating_range keeps only the crossings inside a rotor-speed window. Resonance detection needs a diagram whose axis is the rotor speed in rev/min; the pipeline skips it on a wind-speed axis.

Azimuth-spread uncertainty

The averaged model (4) discards the azimuth dependence; the azimuth spread (vane.modal.azimuth_spread()) measures how much. It uses the per-azimuth matrices kept with retain_per_azimuth=True and measures how each frozen-time matrix \(\mathbf{A}_{\mathrm{NR}}(\psi)\) perturbs the averaged model. For an isotropic rotor every \(\mathbf{A}_{\mathrm{NR}}(\psi)=\bar{\mathbf{A}}\) and the spread is zero. Anisotropy makes the per-azimuth matrices differ from the average by an amount the spread captures. Applying (1) with \(\delta\mathbf{A} = \mathbf{A}_{\mathrm{NR}}(\psi)-\bar{\mathbf{A}}\) gives

\[\lambda_i(\psi) \approx \lambda_i + \frac{\mathbf{y}_i^{\mathsf H}\big(\mathbf{A}_{\mathrm{NR}}(\psi)-\bar{\mathbf{A}}\big) \mathbf{x}_i}{\mathbf{y}_i^{\mathsf H}\mathbf{x}_i},\]

and the standard deviations over the azimuth samples of the natural frequency \(|\lambda_i(\psi)|/2\pi\) and of the damping ratio \(-\operatorname{Re}\lambda_i(\psi)/|\lambda_i(\psi)|\) form the spread. The modes are those of vane.modal.modes_from_mbc() for the same result, in the same order. This first-order spread is the inexpensive companion to the exact Floquet analysis of the periodic system treatment: it flags azimuth sensitivity from the averaged eigenpairs already computed, while the Floquet error (6) measures the averaging error exactly.

The sources are combined into one unified confidence in \([0,1]\) (vane.modal.unified_mode_confidence()) as a product of independent factors,

(1)\[c_i = \underbrace{\kappa_i^{-1}}_{\text{conditioning}}\ \cdot\ \underbrace{d_i}_{\text{degeneracy}}\ \cdot\ \underbrace{\exp\!\big(-\sigma_{f,i}/(f_i\,s)\big)}_{\text{azimuth stability}}\ \cdot\ \underbrace{t_i}_{\text{tracking}},\]

where \(\kappa_i\) is the eigenvalue condition number, \(d_i\) is 0.5 for a degenerate mode and 1 otherwise, \(\sigma_{f,i}\) is the frequency spread, \(s\) is the relative-spread scale (spread_scale, default 0.05), and \(t_i\) is the optional tracking confidence. The spread and tracking factors are omitted when they are not supplied. A low \(c_i\) can be mapped to a larger initial covariance for the estimator (vane.sysid.covariances_from_confidence()).

Confidence calibration

The unified confidence \(c_i\) is useful only if it is calibrated: among the modes assigned confidence \(c\), a fraction of about \(c\) should be correct. vane.modal.calibrate_confidence() measures this against a correctness label \(y_i\in\{0,1\}\) supplied by the user (for instance, whether a predicted physical label matches a known one) with a reliability diagram, confidence binned into equal bins (n_bins, default 10) against the observed accuracy. It is summarized by the expected and maximum calibration errors

\[\mathrm{ECE} = \sum_b \frac{n_b}{N}\,\big|\,\mathrm{acc}_b - \mathrm{conf}_b\,\big|, \qquad \mathrm{MCE} = \max_b \big|\,\mathrm{acc}_b - \mathrm{conf}_b\,\big|,\]

over the non-empty bins \(b\) (\(n_b\) samples each, \(N\) in total), together with the Brier score \(\tfrac1N\sum_i (c_i-y_i)^2\) [Brier1950]. A monotone recalibration map \(g:[0,1]\to[0,1]\) is fitted by isotonic regression (pool-adjacent-violators [Barlow1972]): the non-decreasing function minimizing \(\sum_i (g(c_i)-y_i)^2\). The value \(g(c)\) then reads as a probability of being correct (vane.modal.recalibrate()), and vane.modal.confidence_threshold() inverts it to find the smallest confidence that meets a target accuracy.

Two properties follow from the construction. If the labels are drawn as \(y_i\sim\mathrm{Bernoulli}\big(h(c_i)\big)\) for a known function \(h\), a large sample recovers \(g\approx h\). For \(h(c)=c\) with \(c\) uniform on \([0,1]\) the ECE is close to zero and the Brier score approaches \(\mathbb{E}[c-c^2]=\tfrac16\), while an over-confident \(h(c)=c^2\) shows a positive calibration gap that the map removes. Because the isotonic fit minimizes the squared error over all non-decreasing maps, which include the identity, recalibration never increases the Brier score on the data it was fitted to.