galata · flight-condition report

NT-33A at flight condition 1

Trim, the five classical modes, and one closed bank-angle loop — every number on this page produced by the run that generated it.

Model NT-33A, flight condition 1 — sea level, M = 0.204, power approach (230 gal tip tanks, 25% internal fuel, full flaps, gear down, 1.4 Vs)
Condition 0 m, 69.494 m/s, M 0.2042 Built by galata 0.2.0 Emitter galata-report-data Documentation Source

Reference. R. K. Heffley and W. F. Jewell, "Aircraft Handling Qualities Data", NASA CR-2144, Systems Technology Inc., December 1972, Tables II-1 and II-2. NTRS 19730003312. Distribution: Unclassified - Unlimited.

This page is a run, not a write-up. A single command loads a nonlinear aircraft model built from non-dimensional derivatives, trims it, linearises it about that trim by central differences, classifies the modes by eigenvector participation, closes one loop around the result and measures it. Every table cell and every mark on every plot below is read from the JSON that run emitted; the routine that produced each is named beneath it.

How to get this page yourself.

cmake --preset dev
cmake --build --preset dev
./build/dev/tools/report/galata-report-data > docs/assets/nt33a-fc1-run.json
python3 scripts/gen-report-page.py

CI regenerates the JSON and compares it numerically against the committed copy, then regenerates this page and diffs it. A page that had drifted from the code would still look like evidence, which is worse than no page at all.

The trim point

Three unknowns — angle of attack, elevator and thrust — and three equations: the two body-axis translational accelerations and the pitching acceleration all vanish. Everything further down this page is taken about this point, so it is the first thing to disbelieve.

QuantityValueUnit
Altitude0.0m, geometric
True airspeed69.4944m/s
Mach0.2042
Dynamic pressure2958.1Pa
Angle of attack2.1481deg
Flight-path angle0.0000deg
Pitch attitude2.1481deg
Elevator0.0234deg
Thrust8685.5N
Trim lift coefficient0.80841

Evidence. Residual norm 0.000000000000 (m/s² and rad/s²); trim Jacobian condition number 350682.

A trim is only as good as its residual, so the residual is reported rather than asserted, and the solver throws rather than returning a best effort: a linearisation taken about a point that is not an equilibrium produces a state-space model that is plausible and wrong. The condition number is large here for a units reason and not a physical one — an angle of order 0.04 rad and a thrust of order 104 N sit in the same unknown vector, so the columns differ in scale by five orders before any aircraft is involved. It is worth worrying about only when it is large and the residual will not come down.

Computed by galata::trim::trim_level.

The modal table

The labels are not assigned by frequency order. Each one comes from eigenvector participation — how much of the mode lives in the states that define it — and the score is the share of participation that does. Below about 0.5 a label is a guess, and the column is there so that can be seen rather than assumed.

ModeAxisλ (1/s)ωn (rad/s)ζPeriod (s)T½ (s)T×2 (s)ScoreWhy it carries that label
phugoidlongitudinal-0.01626 ± 0.17063j0.171400.0948536.82442.6350.9590.959 of participation in u and theta
short periodlongitudinal-0.99200 ± 1.24902j1.595030.621935.0310.6990.9930.993 of participation in w and q
spirallateral-0.031900.0319021.7270.7170.717 of participation in phi
roll subsidencelateral-2.199232.199230.3150.8380.838 of participation in p
Dutch rolllateral-0.06805 ± 1.12728j1.129330.060265.57410.1850.7710.771 of participation in v and r

A dash is a quantity that is not defined for that mode, never a zero: a real root has no period, and a mode has either a time to half amplitude or a time to double, never both. Printing zero there would invite a plot to draw it.

Computed by galata::analyze::analyze_modes.

The pole map

0.5 1 1.5 2 2.5 ζ 0.1 ζ 0.2 ζ 0.4 ζ 0.6 ζ 0.8 EVERY MODE Re(λ) — 1/s Im(λ) — rad/s 0.1 0.2 0.3 ζ 0.1 ζ 0.2 ζ 0.4 ζ 0.6 ζ 0.8 MAGNIFIED · 7× Re(λ) — 1/s Im(λ) — rad/s phugoid short period spiral roll subsidence Dutch roll ✕ a pole. An oscillatory mode is a conjugate pair and is drawn twice. Shaded: the right half-plane, where a pole is a divergence.
Every mode of both axes on one s-plane, in units of 1/s horizontally and rad/s vertically, with constant-ωn circles and constant-ζ rays about the origin. Modes of the longitudinal axis and the lateral axis carry different colours. The axes are equally scaled, which is not a stylistic choice: under unequal scaling the constant-ωn circles become ellipses and the constant-ζ rays stop reading as constant damping. The labels are the classifier’s own output.

Participation factors — the evidence for the labels

Normalised to sum to one across the states of each axis. This is the measure the classification rests on, so a label whose evidence looks thin here is a label to distrust.

Longitudinal — states u, w, q, theta

Modeuwqtheta
phugoid0.4770.0100.0310.483
short period0.0010.4990.4930.006

Eigenvector matrix condition number 68.61.

Lateral — states v, p, r, phi

Modevprphi
spiral0.0050.0090.2690.717
roll subsidence0.0700.8380.0340.058
Dutch roll0.4430.1110.3270.119

Eigenvector matrix condition number 81.19.

Against the published values

The input to everything above is a set of non-dimensional derivatives and some geometry. There is no matrix anywhere in it. These are the modal characteristics the same report printed, read from the committed reference file by the same loader the validation tier uses.

ModeQuantityPublishedIts own printinggalataDeviationWithin the published printing?
phugoidzeta0.09480±5e-050.0948520.05%outside
phugoidomega_n0.17200±0.00050.1714010.35%outside
short periodzeta0.62200±0.00050.6219340.01%inside
short periodomega_n1.59000±0.0051.5950300.32%outside
Dutch rollzeta0.06090±5e-050.0602591.05%outside
Dutch rollomega_n1.13000±0.0051.1293300.06%inside
roll subsidence1/T2.20000±0.0052.1992300.04%inside
spiral1/T0.03180±5e-050.0319020.32%outside

“Its own printing” is not the gate. The source prints three significant figures, so each published value carries half a unit in its last digit — that is the column above. The full error budget also has to carry the rounding of the ten printed inputs the value was computed from, and it is derived per quantity in the validation tests and published in the V&V report. This page reports the measurement; it does not carry a second copy of the gate, because two gates are two answers to one question.

The largest deviation in this table is the Dutch roll zeta, at 1.05%. It is reported rather than absorbed by a wider tolerance, which is the whole discipline: a deviation over budget gets localised and published, never widened away. One quantity in this reference case does not reproduce at all — the phugoid damping ratio of a state matrix assembled by hand from the report’s dimensional derivatives, where the chain above reproduces it to the deviation shown in the first row. That gap is localised to a single matrix entry and written up at the phugoid-damping note; its size is published in the V&V report, which measures it rather than quoting it. It is still open, and it is still listed.

One closed loop

The loop is not the aircraft. Margins are a property of a loop, and an aircraft on its own is not one. What is measured below is the smallest control law that makes the question meaningful: measure bank angle, multiply by a gain, drive the aileron. The A and B matrices are the lateral linearisation from the run above — not a matrix read from a file — and the C row is the control law.

PropertyValue
Loopaileron to bank_feedback
Feedback gain0.50 rad aileron per rad of bank error
Where the gain comes fromchosen for this example, not from a document
Where the loop is brokenplant input, between the gain and the aileron
Band searched0.01000 to 100.0 rad/s, 413 points
Worst pivot ratio over the sweep0.00379

That gain is a choice, not a published value. It is 0.50, and it is chosen because at that gain the magnitude crosses unity 3 times, so the loop has that many phase margins — which is the point worth showing. Breaking the loop at the plant output instead would give a different transfer function and different margins for the same closed-loop system. galata will not make that decision for you.

-75 -50 -25 0 25 -150 -100 -50 0 |L| = 1 −180° 0.593 0.918 PM 48.5° 1.61 0.01 0.1 1 10 100 ω — rad/s OPEN-LOOP MAGNITUDE · dB OPEN-LOOP PHASE · deg, unwrapped Vertical marks: every |L(jω)| = 1 crossing. The bold one governs; the numbers above the upper panel are their frequencies in rad/s.
Open-loop frequency response. Magnitude in dB and unwrapped phase in degrees, against frequency in rad/s. Vertical marks are every |L(jω)| = 1 crossing; the bold one governs. Evaluated by Hessenberg solves — the inverse is never formed — on a grid refined around the loop’s own lightly damped modes. Computed by galata::analyze::single_loop_response.

The governing margins

MarginValueAt (rad/s)
Gain margininfinite
Phase margin48.497 deg1.60954
Delay margin0.52588 s1.60954

Every crossover, not just the governing one

A loop whose magnitude crosses unity three times has three phase margins. An implementation that returned the first crossing it found would report this loop as comfortable at the largest of them.

Kindω (rad/s)MarginDelay
|L| = 10.59337101.068 deg2.97279 s
|L| = 10.91806165.221 deg3.14103 s
|L| = 11.6095448.497 deg0.52588 s

Computed by galata::analyze::stability_margins.

Crossovers are found by searching a frequency grid. A crossover pair narrower than the grid spacing is not found, which is why the band and the point count travel with the result. Nothing here proves closed-loop stability either: margins are distances from the critical point, not a Nyquist encirclement count.

Gain and phase together

The gain margin is the tolerable gain change with no phase change; the phase margin is the tolerable phase change with no gain change. No real actuator varies one alone. The disk margin asks how much of both together, and the picture below is the whole of the argument: the perturbed loop is f·L for every f in a disk, so the closed loop is stable for all of them exactly when L(jω) misses the shaded region.

-2 -1 0 1 Im L(jω) Re L(jω) L(jω), ω > 0 — dimensionless L(−jω), the conjugate branch |L| = 1 the critical point, −1 + 0j the disk L must avoid tangency, at ω = 1.757 rad/s
Nyquist, against the disk the loop must avoid. Axes are the real and imaginary parts of L(jω), dimensionless. The shaded disk meets the real axis at −1/γmin and −1/γmax, the two gain limits the margin guarantees, and the marked point is where the curve touches it — the boundary perturbation f = 0.8550 − 0.8894j places a closed-loop pole exactly at s = j1.7574. The low-frequency arm runs off the panel. Computed by galata::analyze::disk_margin.
QuantityValueWhere
Disk margin α0.87606
Peak of |S + (σ−1)/2|1.14147
Critical frequency1.75745rad/s
Guaranteed gain range0.3908 to 2.5589 (-8.16 to 8.16 dB)
Guaranteed phase range±47.310 deg
Sensitivity peak MS1.44941at 2.0441 rad/s
Complementary peak MT1.25447at 1.4844 rad/s

What those peaks guarantee

Skogestad & Postlethwaite, 2nd ed., equations (2.47) and (2.48). Lower bounds: the loop’s actual margins are at least this good. The two gain-margin bounds have different functional forms — MS/(MS−1) against 1 + 1/MT — which is easy to blur from memory.

FromGain margin at leastPhase margin at least
MS3.225140.360 deg
MT1.797246.978 deg

Every peak on this page is a grid maximum. The disk margin, MS and MT are all found by searching a refined frequency grid and not by the exact Hamiltonian-eigenvalue method, so each peak is a lower bound on the true H-infinity norm and each derived margin is an upper bound on the true one. The error is in the optimistic direction. Treat a marginal result as marginal.

The state matrices these came from

Central differences about the trim, with a Richardson truncation estimate per entry. The neglected coupling is the largest entry of the full 12×12 Jacobian that ties a retained state to a discarded one, relative to the largest retained entry: it is measured rather than assumed, because “the longitudinal and lateral axes decouple” is true at a wings-level symmetric trim and false in a turn, and the difference does not show in the reduced matrix.

Longitudinal

Rows and columns in the order u, w, q, theta. Velocities m/s, angles rad, rates rad/s. Worst relative truncation 4.26e-12; neglected coupling 1.35e-05; Euler-chart conditioning |cos θ| = 0.999297.

A =
                   u           w           q       theta
      u    -0.039146    0.079936   -2.604860   -9.799760
      w    -0.247105   -0.936394   69.445600   -0.367583
      q     0.002244   -0.022467   -1.040980   -0.000000
  theta     0.000000    0.000000    1.000000    0.000000

B =
            elevator     aileron      rudder      thrust
      u     0.153638    0.000000    0.000000    0.000187
      w    -4.095990    0.000000    0.000000    0.000000
      q    -4.170710    0.000000    0.000000    0.000000
  theta     0.000000    0.000000    0.000000    0.000000

Lateral

Rows and columns in the order v, p, r, phi. Velocities m/s, angles rad, rates rad/s. Worst relative truncation 5.87e-15; neglected coupling 0; Euler-chart conditioning |cos θ| = 0.999297.

A =
                   v           p           r         phi
      v    -0.124902    2.604860  -69.445600    9.799760
      p    -0.079099   -2.035300    0.641840    0.000000
      r     0.009609   -0.115922   -0.207034    0.000000
    phi     0.000000    1.000000    0.037509    0.000000

B =
            elevator     aileron      rudder      thrust
      v     0.000000    0.000000    2.049440    0.000000
      p     0.000000    6.014430   -0.012507    0.000000
      r     0.000000    0.028629   -1.242800    0.000000
    phi     0.000000    0.000000    0.000000    0.000000

Computed by galata::linearize::linearize_finite_difference.

What this page is not

Not certified, and not a handling-qualities assessment. Nothing in galata is DO-178C qualified and none of it may be used as evidence in a certification package. Nothing here says whether a mode or a margin is acceptable: Level 1/2/3 boundaries are a judgement against a specification, and that is a separate capability with its own citations, which galata does not have.

The aircraft model is a first-order expansion about one flight condition. It has no stall, no Mach effects and no engine, and it will return a confident answer at any angle of attack it is asked for. The linearisation is only as good as the trim, and the trim is reported above with its residual so that can be checked. The classification cannot tell you that a label is meaningless — only that its evidence was weak, which is what the score column is for.