re(flight): the rate probe measures a MOVING speed -- pitching bleeds it hard

Measured pitch with the rows properly pinned, against this craft's own disc caps
(AV_PitchPlus_Min 150, AV_PitchPlus_Max 70):

    min speed (LT)  1391.0 deg / 8.00 s, clock x1.326 -> 131.1 deg/game-s  vs 150
    max speed (RT)   989.0 deg / 8.05 s, clock x1.318 ->  93.2 deg/game-s  vs 70

A rate 33% ABOVE a cap is not a finding, it is a broken instrument. The HUD speed
is in the same bracketing screenshots that give the clock, so read it:

    slow phase   102 ->  18
    fast phase  1193 -> 589

The speed is NOT constant during the dwell -- pitching halves it in 8 seconds.
The cap is speed-dependent, so as the craft slowed its cap rose, and an 8-second
average necessarily lands between the max-speed cap and a mid-speed one. The 133%
is entirely the instrument.

This also weakens the roll result committed earlier: same method, so 120.9 vs
AV_Roll_Max 125 is CONSISTENT but is not a tight test -- the true cap could be
lower and still produce that average. Said plainly in the doc rather than left
standing as a clean confirmation. Min-speed figures are less affected; there is
little speed left to lose.

Proper fix, not yet done: dwell ~1-2 s so speed barely moves, or sample HUD speed
continuously and fit rate against INSTANTANEOUS speed -- which yields the whole
rate-vs-speed curve instead of two points.

Separately this is a flight-model finding: TURNING COSTS SPEED, steeply, with the
throttle still at maximum. A reimplementation treating the throttle as a speed the
craft simply holds will be wrong during manoeuvres.
This commit is contained in:
2026-08-13 22:48:29 +00:00
parent dc46339b63
commit 6c7025851e
3 changed files with 450 additions and 0 deletions

View File

@@ -0,0 +1,315 @@
phase,t,dpitch_deg
slow,0.051,0.0953
slow,0.101,1.6885
slow,0.152,0.8717
slow,0.202,1.6238
slow,0.252,-0.0
slow,0.302,-0.0
slow,0.352,8.8412
slow,0.403,5.679
slow,0.453,5.3839
slow,0.503,12.9544
slow,0.553,7.5713
slow,0.603,4.0593
slow,0.653,0.0
slow,0.703,0.0
slow,0.753,23.7081
slow,0.804,14.501
slow,0.854,9.6502
slow,0.905,9.64
slow,0.955,2.4036
slow,1.006,-0.0
slow,1.056,-0.0
slow,1.106,24.1631
slow,1.156,9.7201
slow,1.206,14.5817
slow,1.26,7.2861
slow,1.31,-0.0
slow,1.36,-0.0
slow,1.41,21.8962
slow,1.461,12.1865
slow,1.511,14.6395
slow,1.561,4.8866
slow,1.611,4.8766
slow,1.661,0.0
slow,1.712,0.0
slow,1.762,24.4862
slow,1.812,12.272
slow,1.863,14.7764
slow,1.913,14.8237
slow,1.964,9.9081
slow,2.014,-0.0
slow,2.064,-0.0
slow,2.116,22.3434
slow,2.166,4.9684
slow,2.217,14.8905
slow,2.267,9.9066
slow,2.317,2.4656
slow,2.367,-0.0
slow,2.417,19.7888
slow,2.467,7.374
slow,2.517,9.8264
slow,2.569,14.7106
slow,2.619,12.2195
slow,2.671,0.0
slow,2.721,0.0
slow,2.771,0.0
slow,2.821,24.4044
slow,2.871,12.1781
slow,2.951,14.5889
slow,3.001,14.5786
slow,3.052,0.0
slow,3.102,0.0
slow,3.153,19.432
slow,3.203,14.5741
slow,3.253,4.8605
slow,3.303,19.4596
slow,3.355,2.4281
slow,3.405,0.0
slow,3.455,0.0
slow,3.506,31.6949
slow,3.556,9.7829
slow,3.606,14.7094
slow,3.656,9.8314
slow,3.706,7.3808
slow,3.756,-0.0
slow,3.807,-0.0
slow,3.857,19.7355
slow,3.907,14.8675
slow,3.958,4.9655
slow,4.008,17.3918
slow,4.06,2.4777
slow,4.11,-0.0
slow,4.16,-0.0
slow,4.211,32.264
slow,4.261,9.866
slow,4.311,19.6734
slow,4.361,7.3673
slow,4.412,7.3404
slow,4.462,0.0
slow,4.513,0.0
slow,4.563,19.5894
slow,4.613,12.1841
slow,4.663,4.8719
slow,4.713,17.0264
slow,4.765,2.4241
slow,4.815,0.0
slow,4.866,0.0
slow,4.918,26.7496
slow,4.968,17.0367
slow,5.019,14.6052
slow,5.069,7.3143
slow,5.119,2.4296
slow,5.17,0.0
slow,5.222,17.0719
slow,5.272,12.2148
slow,5.351,14.6765
slow,5.401,14.7096
slow,5.454,2.4482
slow,5.504,0.0
slow,5.555,0.0
slow,5.605,27.0453
slow,5.655,12.3214
slow,5.705,14.8308
slow,5.756,4.9518
slow,5.806,19.8347
slow,5.856,2.4736
slow,5.906,-0.0
slow,5.957,-0.0
slow,6.008,24.7941
slow,6.058,9.8906
slow,6.108,14.805
slow,6.159,4.9105
slow,6.209,-0.0
slow,6.26,-0.0
slow,6.31,24.6254
slow,6.36,7.3425
slow,6.41,14.6791
slow,6.461,9.7716
slow,6.511,7.3144
slow,6.561,0.0
slow,6.612,0.0
slow,6.662,21.9754
slow,6.713,12.1647
slow,6.763,9.7355
slow,6.813,19.4718
slow,6.864,2.4274
slow,6.914,0.0
slow,6.964,0.0
slow,7.014,29.2378
slow,7.064,9.7533
slow,7.114,14.6513
slow,7.165,4.8902
slow,7.215,2.4395
slow,7.266,0.0
slow,7.316,0.0
slow,7.368,26.9512
slow,7.418,14.7524
slow,7.468,9.8579
slow,7.518,12.3414
slow,7.569,2.4662
slow,7.621,-0.0
slow,7.671,-0.0
slow,7.722,19.8018
slow,7.772,9.92
slow,7.851,14.8814
slow,7.901,12.3787
slow,7.951,2.4669
slow,8.001,0.0
fast,0.05,0.0
fast,0.104,0.0
fast,0.154,0.0
fast,0.204,0.2374
fast,0.254,0.206
fast,0.306,1.8902
fast,0.356,1.5885
fast,0.406,1.4595
fast,0.456,0.0
fast,0.506,0.0
fast,0.556,5.7624
fast,0.606,2.347
fast,0.657,3.5323
fast,0.707,6.1276
fast,0.757,1.1012
fast,0.807,-0.0
fast,0.857,-0.0
fast,0.909,12.418
fast,0.959,5.1346
fast,1.009,7.8218
fast,1.059,6.5806
fast,1.109,1.3424
fast,1.16,0.0
fast,1.21,10.761
fast,1.263,4.2102
fast,1.313,8.2445
fast,1.363,6.8621
fast,1.413,6.9892
fast,1.463,-0.0
fast,1.542,-0.0
fast,1.592,11.0635
fast,1.642,5.9249
fast,1.692,8.7078
fast,1.742,2.8665
fast,1.793,10.1297
fast,1.843,0.0
fast,1.893,0.0
fast,1.943,0.0
fast,1.993,20.6893
fast,2.043,3.2503
fast,2.094,11.2506
fast,2.144,6.3385
fast,2.194,7.8452
fast,2.244,1.556
fast,2.295,-0.0
fast,2.345,-0.0
fast,2.395,18.7454
fast,2.445,10.3395
fast,2.495,10.608
fast,2.545,7.0808
fast,2.596,7.0815
fast,2.646,0.0
fast,2.696,0.0
fast,2.746,0.0
fast,2.796,17.7627
fast,2.847,10.6635
fast,2.897,7.1571
fast,2.947,7.1983
fast,3.002,5.4229
fast,3.052,0.0
fast,3.102,0.0
fast,3.152,0.0
fast,3.202,25.5105
fast,3.253,7.3926
fast,3.303,11.2085
fast,3.353,3.7679
fast,3.404,3.7764
fast,3.455,-0.0
fast,3.505,-0.0
fast,3.556,19.0406
fast,3.642,11.5779
fast,3.692,11.712
fast,3.742,3.9222
fast,3.792,0.0
fast,3.842,0.0
fast,3.892,17.7661
fast,3.942,1.9679
fast,3.993,17.8611
fast,4.043,3.9876
fast,4.093,15.9815
fast,4.146,0.0
fast,4.196,0.0
fast,4.246,0.0
fast,4.296,21.9362
fast,4.346,7.908
fast,4.396,11.8184
fast,4.447,7.8388
fast,4.497,1.9466
fast,4.547,0.0
fast,4.597,0.0
fast,4.647,0.0
fast,4.697,29.0258
fast,4.747,11.3566
fast,4.797,11.275
fast,4.847,3.7393
fast,4.898,7.4494
fast,4.948,-0.0
fast,4.998,-0.0
fast,5.048,-0.0
fast,5.098,24.0113
fast,5.148,10.888
fast,5.202,10.8585
fast,5.252,7.225
fast,5.302,5.4068
fast,5.352,0.0
fast,5.403,0.0
fast,5.453,0.0
fast,5.504,26.97
fast,5.554,10.7617
fast,5.604,10.8137
fast,5.654,3.6172
fast,5.709,5.4336
fast,5.759,-0.0
fast,5.809,-0.0
fast,5.862,20.0109
fast,5.942,10.985
fast,5.992,11.0845
fast,6.042,5.5755
fast,6.092,0.0
fast,6.142,0.0
fast,6.192,18.6832
fast,6.245,1.866
fast,6.295,15.0963
fast,6.345,3.8107
fast,6.395,9.5834
fast,6.446,1.9237
fast,6.496,0.0
fast,6.546,0.0
fast,6.598,21.2979
fast,6.651,7.8108
fast,6.701,13.7645
fast,6.751,3.9499
fast,6.802,5.9406
fast,6.852,0.0
fast,6.902,15.8604
fast,6.952,5.9146
fast,7.002,11.8545
fast,7.053,7.9034
fast,7.103,9.8434
fast,7.153,1.9608
fast,7.203,-0.0
fast,7.253,-0.0
fast,7.303,19.6693
fast,7.357,13.4968
fast,7.407,11.5239
fast,7.457,7.6491
fast,7.507,11.4147
fast,7.559,1.8882
fast,7.642,-0.0
fast,7.692,15.147
fast,7.742,5.584
fast,7.792,11.1374
fast,7.842,3.6992
fast,7.892,9.2126
fast,7.946,1.8328
fast,7.996,-0.0
fast,8.046,-0.0
1 phase t dpitch_deg
2 slow 0.051 0.0953
3 slow 0.101 1.6885
4 slow 0.152 0.8717
5 slow 0.202 1.6238
6 slow 0.252 -0.0
7 slow 0.302 -0.0
8 slow 0.352 8.8412
9 slow 0.403 5.679
10 slow 0.453 5.3839
11 slow 0.503 12.9544
12 slow 0.553 7.5713
13 slow 0.603 4.0593
14 slow 0.653 0.0
15 slow 0.703 0.0
16 slow 0.753 23.7081
17 slow 0.804 14.501
18 slow 0.854 9.6502
19 slow 0.905 9.64
20 slow 0.955 2.4036
21 slow 1.006 -0.0
22 slow 1.056 -0.0
23 slow 1.106 24.1631
24 slow 1.156 9.7201
25 slow 1.206 14.5817
26 slow 1.26 7.2861
27 slow 1.31 -0.0
28 slow 1.36 -0.0
29 slow 1.41 21.8962
30 slow 1.461 12.1865
31 slow 1.511 14.6395
32 slow 1.561 4.8866
33 slow 1.611 4.8766
34 slow 1.661 0.0
35 slow 1.712 0.0
36 slow 1.762 24.4862
37 slow 1.812 12.272
38 slow 1.863 14.7764
39 slow 1.913 14.8237
40 slow 1.964 9.9081
41 slow 2.014 -0.0
42 slow 2.064 -0.0
43 slow 2.116 22.3434
44 slow 2.166 4.9684
45 slow 2.217 14.8905
46 slow 2.267 9.9066
47 slow 2.317 2.4656
48 slow 2.367 -0.0
49 slow 2.417 19.7888
50 slow 2.467 7.374
51 slow 2.517 9.8264
52 slow 2.569 14.7106
53 slow 2.619 12.2195
54 slow 2.671 0.0
55 slow 2.721 0.0
56 slow 2.771 0.0
57 slow 2.821 24.4044
58 slow 2.871 12.1781
59 slow 2.951 14.5889
60 slow 3.001 14.5786
61 slow 3.052 0.0
62 slow 3.102 0.0
63 slow 3.153 19.432
64 slow 3.203 14.5741
65 slow 3.253 4.8605
66 slow 3.303 19.4596
67 slow 3.355 2.4281
68 slow 3.405 0.0
69 slow 3.455 0.0
70 slow 3.506 31.6949
71 slow 3.556 9.7829
72 slow 3.606 14.7094
73 slow 3.656 9.8314
74 slow 3.706 7.3808
75 slow 3.756 -0.0
76 slow 3.807 -0.0
77 slow 3.857 19.7355
78 slow 3.907 14.8675
79 slow 3.958 4.9655
80 slow 4.008 17.3918
81 slow 4.06 2.4777
82 slow 4.11 -0.0
83 slow 4.16 -0.0
84 slow 4.211 32.264
85 slow 4.261 9.866
86 slow 4.311 19.6734
87 slow 4.361 7.3673
88 slow 4.412 7.3404
89 slow 4.462 0.0
90 slow 4.513 0.0
91 slow 4.563 19.5894
92 slow 4.613 12.1841
93 slow 4.663 4.8719
94 slow 4.713 17.0264
95 slow 4.765 2.4241
96 slow 4.815 0.0
97 slow 4.866 0.0
98 slow 4.918 26.7496
99 slow 4.968 17.0367
100 slow 5.019 14.6052
101 slow 5.069 7.3143
102 slow 5.119 2.4296
103 slow 5.17 0.0
104 slow 5.222 17.0719
105 slow 5.272 12.2148
106 slow 5.351 14.6765
107 slow 5.401 14.7096
108 slow 5.454 2.4482
109 slow 5.504 0.0
110 slow 5.555 0.0
111 slow 5.605 27.0453
112 slow 5.655 12.3214
113 slow 5.705 14.8308
114 slow 5.756 4.9518
115 slow 5.806 19.8347
116 slow 5.856 2.4736
117 slow 5.906 -0.0
118 slow 5.957 -0.0
119 slow 6.008 24.7941
120 slow 6.058 9.8906
121 slow 6.108 14.805
122 slow 6.159 4.9105
123 slow 6.209 -0.0
124 slow 6.26 -0.0
125 slow 6.31 24.6254
126 slow 6.36 7.3425
127 slow 6.41 14.6791
128 slow 6.461 9.7716
129 slow 6.511 7.3144
130 slow 6.561 0.0
131 slow 6.612 0.0
132 slow 6.662 21.9754
133 slow 6.713 12.1647
134 slow 6.763 9.7355
135 slow 6.813 19.4718
136 slow 6.864 2.4274
137 slow 6.914 0.0
138 slow 6.964 0.0
139 slow 7.014 29.2378
140 slow 7.064 9.7533
141 slow 7.114 14.6513
142 slow 7.165 4.8902
143 slow 7.215 2.4395
144 slow 7.266 0.0
145 slow 7.316 0.0
146 slow 7.368 26.9512
147 slow 7.418 14.7524
148 slow 7.468 9.8579
149 slow 7.518 12.3414
150 slow 7.569 2.4662
151 slow 7.621 -0.0
152 slow 7.671 -0.0
153 slow 7.722 19.8018
154 slow 7.772 9.92
155 slow 7.851 14.8814
156 slow 7.901 12.3787
157 slow 7.951 2.4669
158 slow 8.001 0.0
159 fast 0.05 0.0
160 fast 0.104 0.0
161 fast 0.154 0.0
162 fast 0.204 0.2374
163 fast 0.254 0.206
164 fast 0.306 1.8902
165 fast 0.356 1.5885
166 fast 0.406 1.4595
167 fast 0.456 0.0
168 fast 0.506 0.0
169 fast 0.556 5.7624
170 fast 0.606 2.347
171 fast 0.657 3.5323
172 fast 0.707 6.1276
173 fast 0.757 1.1012
174 fast 0.807 -0.0
175 fast 0.857 -0.0
176 fast 0.909 12.418
177 fast 0.959 5.1346
178 fast 1.009 7.8218
179 fast 1.059 6.5806
180 fast 1.109 1.3424
181 fast 1.16 0.0
182 fast 1.21 10.761
183 fast 1.263 4.2102
184 fast 1.313 8.2445
185 fast 1.363 6.8621
186 fast 1.413 6.9892
187 fast 1.463 -0.0
188 fast 1.542 -0.0
189 fast 1.592 11.0635
190 fast 1.642 5.9249
191 fast 1.692 8.7078
192 fast 1.742 2.8665
193 fast 1.793 10.1297
194 fast 1.843 0.0
195 fast 1.893 0.0
196 fast 1.943 0.0
197 fast 1.993 20.6893
198 fast 2.043 3.2503
199 fast 2.094 11.2506
200 fast 2.144 6.3385
201 fast 2.194 7.8452
202 fast 2.244 1.556
203 fast 2.295 -0.0
204 fast 2.345 -0.0
205 fast 2.395 18.7454
206 fast 2.445 10.3395
207 fast 2.495 10.608
208 fast 2.545 7.0808
209 fast 2.596 7.0815
210 fast 2.646 0.0
211 fast 2.696 0.0
212 fast 2.746 0.0
213 fast 2.796 17.7627
214 fast 2.847 10.6635
215 fast 2.897 7.1571
216 fast 2.947 7.1983
217 fast 3.002 5.4229
218 fast 3.052 0.0
219 fast 3.102 0.0
220 fast 3.152 0.0
221 fast 3.202 25.5105
222 fast 3.253 7.3926
223 fast 3.303 11.2085
224 fast 3.353 3.7679
225 fast 3.404 3.7764
226 fast 3.455 -0.0
227 fast 3.505 -0.0
228 fast 3.556 19.0406
229 fast 3.642 11.5779
230 fast 3.692 11.712
231 fast 3.742 3.9222
232 fast 3.792 0.0
233 fast 3.842 0.0
234 fast 3.892 17.7661
235 fast 3.942 1.9679
236 fast 3.993 17.8611
237 fast 4.043 3.9876
238 fast 4.093 15.9815
239 fast 4.146 0.0
240 fast 4.196 0.0
241 fast 4.246 0.0
242 fast 4.296 21.9362
243 fast 4.346 7.908
244 fast 4.396 11.8184
245 fast 4.447 7.8388
246 fast 4.497 1.9466
247 fast 4.547 0.0
248 fast 4.597 0.0
249 fast 4.647 0.0
250 fast 4.697 29.0258
251 fast 4.747 11.3566
252 fast 4.797 11.275
253 fast 4.847 3.7393
254 fast 4.898 7.4494
255 fast 4.948 -0.0
256 fast 4.998 -0.0
257 fast 5.048 -0.0
258 fast 5.098 24.0113
259 fast 5.148 10.888
260 fast 5.202 10.8585
261 fast 5.252 7.225
262 fast 5.302 5.4068
263 fast 5.352 0.0
264 fast 5.403 0.0
265 fast 5.453 0.0
266 fast 5.504 26.97
267 fast 5.554 10.7617
268 fast 5.604 10.8137
269 fast 5.654 3.6172
270 fast 5.709 5.4336
271 fast 5.759 -0.0
272 fast 5.809 -0.0
273 fast 5.862 20.0109
274 fast 5.942 10.985
275 fast 5.992 11.0845
276 fast 6.042 5.5755
277 fast 6.092 0.0
278 fast 6.142 0.0
279 fast 6.192 18.6832
280 fast 6.245 1.866
281 fast 6.295 15.0963
282 fast 6.345 3.8107
283 fast 6.395 9.5834
284 fast 6.446 1.9237
285 fast 6.496 0.0
286 fast 6.546 0.0
287 fast 6.598 21.2979
288 fast 6.651 7.8108
289 fast 6.701 13.7645
290 fast 6.751 3.9499
291 fast 6.802 5.9406
292 fast 6.852 0.0
293 fast 6.902 15.8604
294 fast 6.952 5.9146
295 fast 7.002 11.8545
296 fast 7.053 7.9034
297 fast 7.103 9.8434
298 fast 7.153 1.9608
299 fast 7.203 -0.0
300 fast 7.253 -0.0
301 fast 7.303 19.6693
302 fast 7.357 13.4968
303 fast 7.407 11.5239
304 fast 7.457 7.6491
305 fast 7.507 11.4147
306 fast 7.559 1.8882
307 fast 7.642 -0.0
308 fast 7.692 15.147
309 fast 7.742 5.584
310 fast 7.792 11.1374
311 fast 7.842 3.6992
312 fast 7.892 9.2126
313 fast 7.946 1.8328
314 fast 7.996 -0.0
315 fast 8.046 -0.0

View File

@@ -504,3 +504,44 @@ should model as such.
🟡 Not covered: the **d-pad** (the tactical map) and the **face buttons** (fire / 🟡 Not covered: the **d-pad** (the tactical map) and the **face buttons** (fire /
weapon select). Neither is a plausible flight axis, but neither was measured here. weapon select). Neither is a plausible flight axis, but neither was measured here.
Data: [`captures/axis-probe-rows-pinned.csv`](captures/axis-probe-rows-pinned.csv). Data: [`captures/axis-probe-rows-pinned.csv`](captures/axis-probe-rows-pinned.csv).
## ⚠️ Angular-rate probes measure a MOVING speed — the dwell bleeds it
Measuring pitch with the rows properly pinned gave, for
`UN_f001_TCAF_DeltaSaber_T_Player` (whose own disc values are
`AV_PitchPlus_Min` **150°**, `AV_PitchPlus_Max` **70°**):
| phase | swept | clock | per game-s | cap |
|---|---|---|---|---|
| min speed (`LT`) | 1 391.0° / 8.00 s | ×1.326 | **131.1** | 150 |
| max speed (`RT`) | 989.0° / 8.05 s | ×1.318 | **93.2** | 70 — **133 % of cap** |
A rate 33 % *above* a cap is not a finding, it is a broken instrument, so read the
HUD speed off the same bracketing screenshots that gave the clock:
```
slow phase 102 -> 18
fast phase 1193 -> 589
```
**The speed is not constant during the dwell — pitching bleeds it hard**, halving it
in 8 seconds. The rate cap is itself speed-dependent, so as the craft slowed its cap
*rose*, and the 8-second average necessarily lands between the max-speed cap and a
mid-speed one. The 133 % is fully explained by the instrument.
**This weakens the roll numbers above as well.** They were taken the same way, so
`120.9` vs `AV_Roll_Max` `125` is *consistent* but is **not a tight test** — the true
max-speed roll cap could be lower and still produce that average. The min-speed
figures are less affected (there is little speed left to lose).
**How to measure it properly** (not yet done): keep the dwell to ~12 s so the speed
barely moves, or sample the HUD speed continuously and fit rate against
*instantaneous* speed rather than assuming the endpoint. The second is strictly
better and gives the whole rate-vs-speed curve rather than two points.
**And a flight-model finding in its own right:** *turning costs speed*, steeply —
1 193 → 589 under 8 s of full pitch, with the throttle still held at maximum. A
reimplementation that treats the throttle as setting a speed the craft simply holds
will be wrong during manoeuvres. Data:
[`captures/pitch-rate-speed-bleed.csv`](captures/pitch-rate-speed-bleed.csv).

94
tools/re-capture/rate_probe.py Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python3
"""Angular rate cap for one axis, at minimum and maximum speed.
Generalises `roll_axis.py`. Two things it does that the probes before it did not:
* **Pins the matrix rows.** `entities2` measures row 2 = forward against velocity,
but up-vs-right was previously taken from the D3D convention — and measuring
world-Y in flight showed the convention is *backwards* here (up = row 1, right =
row 0). Roll is immune to that (rotation of either non-forward row within their
shared plane is roll either way), but **pitch is not**, so a pitch number taken
without this pinning is naming an axis by assumption.
* **Brackets each phase with the HUD clock.** Rates are per GAME second and the
clock ratio is a property of the moment — 1.260, 1.311, 1.383 and 1.247/1.218
across five flights — so it cannot be assumed and must be read per phase.
roll driven by lx, measured as rotation of UP about forward
pitch driven by ly, measured as rotation of FORWARD toward up
Usage: rate_probe.py <roll|pitch> <out.csv> [dwell_s]
Then read HUD TIME off the `rate_<axis>_<phase>_[ab]` screenshots for the ratio.
"""
import json
import math
import os
import struct
import subprocess
import sys
import time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import speed_law # noqa: E402
from axis_probe import alive, pad_state, pin_rows, rows_at, dot # noqa: E402
DRIVER = {"roll": {"lx": 32767}, "pitch": {"ly": 32767}}
def shot(n):
subprocess.run(["screenshot", f"/sylph-home/re/shots/{n}.png"], capture_output=True)
def main():
axis = sys.argv[1]
out_csv = sys.argv[2]
dwell = float(sys.argv[3]) if len(sys.argv) > 3 else 8.0
if axis not in DRIVER:
sys.exit(f"axis must be one of {list(DRIVER)}")
cfg = json.load(open("/tmp/nav-live.json"))
w, off, nm = speed_law.find_player()
if not w:
sys.exit("player entity not found")
print(f"# locked on {nm}, measuring {axis}")
f_i = cfg["fwd_row"]
if not alive(w, off, cfg):
sys.exit("craft is not moving — not in flight, or already dead")
u_i, w_i = pin_rows(w, off, cfg)
rows = []
for label, trig in (("slow", "lt"), ("fast", "rt")):
pad_state(**{trig: 255})
time.sleep(5.0) # settle: 2 s was shown wrong twice
shot(f"rate_{axis}_{label}_a")
prev = rows_at(w.fd, off, cfg)
pad_state(**{trig: 255}, **DRIVER[axis])
t0, swept, seq = time.time(), 0.0, []
while time.time() - t0 < dwell:
time.sleep(0.05)
cur = rows_at(w.fd, off, cfg)
if axis == "roll":
d = math.atan2(dot(cur[u_i], prev[w_i]), dot(cur[u_i], prev[u_i]))
else:
d = math.atan2(dot(cur[f_i], prev[u_i]), dot(cur[f_i], prev[f_i]))
d = math.degrees(d)
swept += abs(d)
seq.append((round(time.time() - t0, 3), round(d, 4)))
prev = cur
pad_state(**{trig: 255})
wall = seq[-1][0]
shot(f"rate_{axis}_{label}_b")
rows += [(label, *s) for s in seq]
print(f"# {label:<5} wall {wall:5.2f}s {axis} swept {swept:7.1f}deg "
f"rate {swept / wall:6.1f} deg/wall-s")
if not alive(w, off, cfg):
print("# CRAFT STOPPED MOVING — aborting rather than reporting zeros")
break
pad_state()
with open(out_csv, "w") as f:
f.write(f"phase,t,d{axis}_deg\n")
for r in rows:
f.write(",".join(str(x) for x in r) + "\n")
print(f"# wrote {out_csv} — read HUD TIME off rate_{axis}_*_[ab] for the clock")
if __name__ == "__main__":
raise SystemExit(main())