#119: heatLoad filter restored to the POD's 28 Hz sample cadence
The clipping coolant-leak voice ("warning... war... warning coo...")
measured to a ReportLeak relaxation oscillation at a drained tank:
draw = zoneDamage x heatLoad hunts across the authored 0.0025/0.003
hysteresis band (constants byte-verified) as the dry sink's conduction
collapses and the tank trickle refills it. State machine, constants,
refill dynamics and the sequencer's chase-and-cut stop (T0 AUDSEQ.cpp)
are all the binary's own -- the ONE divergence was the 15-sample
heatLoad filter: per-Perform in the binary = a 0.536 s window at the
pod's 28 Hz, but only 0.25 s at the port's ~59 fps -- heatLoad twice as
twitchy, the flap at double the pod cadence (the myomer-kinetic dt-less
class, third instance).
UpdateHeatLoad now accrues real time and samples at 28 Hz on any
machine (catch-up capped at the 15-sample window). Per-instance clock
in a static map -- the heat-family layouts are factory-size-locked
(sizeof(Myomers) == 0x358 exact), no new members. Ctor/reset prime
calls sample unconditionally.
A/B (260 s leak-to-empty bench): trigger fires 12 -> 8, transitions
11 -> 7. The residual slow restart at a bone-dry tank is authentic 1995
behavior (same engine sequencer chase-cut); a minimum-retrigger
interval would be an opt-in deviation for the operator to decide.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
1efe8efc68
commit
1df2c571ee
@@ -777,7 +777,7 @@ void
|
||||
{
|
||||
heatEnergy += pendingHeat;
|
||||
currentTemperature = heatEnergy / thermalMass;
|
||||
UpdateHeatLoad();
|
||||
UpdateHeatLoad(time_slice); // 28 Hz filter cadence (#119)
|
||||
|
||||
// DIAG census (BT_HEAT_LOG, viewpoint mech): PER-INSTANCE 5-s timers --
|
||||
// the old shared static timer aliased to whichever instance crossed the
|
||||
@@ -850,8 +850,22 @@ void
|
||||
// @004ad7f0 -- recompute the radiated/instantaneous heat and feed it through
|
||||
// the running-average filter to produce the smoothed heatLoad reading.
|
||||
//
|
||||
// POD-CADENCE SAMPLING (#119, 2026-08-02). The binary adds ONE sample per
|
||||
// Perform -- a dt-less per-frame term (the myomer-kinetic class, FUN_0041c018
|
||||
// proves Performs ride the frame rate). 15 samples at the pod's 28 Hz = a
|
||||
// 0.536 s smoothing window; sampled at the port's ~59 fps the window halves
|
||||
// and heatLoad turns 2x as twitchy -- which doubles the cadence of the
|
||||
// ReportLeak relaxation oscillation at a drained tank (draw = damage x
|
||||
// heatLoad hunting across the authored 0.0025/0.003 hysteresis band), and
|
||||
// THAT is the rapidly-clipping "warning coo-- war--" leak voice Oracle
|
||||
// reproduced twice in 716. Sim calls pass their slice and samples accrue at
|
||||
// 28 Hz on any machine; ctor/reset prime calls (negative dt) sample
|
||||
// unconditionally. Per-instance clock lives in a static map (the census
|
||||
// precedent above) because the heat-family layouts are factory-size-locked
|
||||
// (sizeof(Myomers) == 0x358 exact) -- no new members.
|
||||
//
|
||||
void
|
||||
HeatSink::UpdateHeatLoad()
|
||||
HeatSink::UpdateHeatLoad(Scalar time_slice)
|
||||
{
|
||||
radiatedHeat = currentTemperature * coolantLevel;
|
||||
|
||||
@@ -865,7 +879,31 @@ void
|
||||
sample = HeatLoadMaximum;
|
||||
}
|
||||
|
||||
heatFilter.AddSample(sample); // FUN_0043ade4
|
||||
if (time_slice >= 0.0f)
|
||||
{
|
||||
static std::map<const void *, Scalar> s_filterClock;
|
||||
Scalar &clock = s_filterClock[this];
|
||||
clock += time_slice;
|
||||
const Scalar kPodTick = 1.0f / 28.0f; // [T1] pod Perform cadence
|
||||
if (clock < kPodTick)
|
||||
{
|
||||
return; // heatLoad holds the last average
|
||||
}
|
||||
int catchUp = 0;
|
||||
while (clock >= kPodTick && ++catchUp <= 15) // >15 samples saturate the window
|
||||
{
|
||||
clock -= kPodTick;
|
||||
heatFilter.AddSample(sample); // FUN_0043ade4
|
||||
}
|
||||
if (catchUp > 15)
|
||||
{
|
||||
clock = 0.0f; // hitch: window already saturated
|
||||
}
|
||||
heatLoad = heatFilter.Average(); // FUN_0043ae0b
|
||||
return;
|
||||
}
|
||||
|
||||
heatFilter.AddSample(sample); // FUN_0043ade4 (prime call)
|
||||
heatLoad = heatFilter.Average(); // FUN_0043ae0b
|
||||
}
|
||||
|
||||
|
||||
@@ -512,8 +512,11 @@ inline int
|
||||
// Internal model helpers
|
||||
//
|
||||
public:
|
||||
// time_slice >= 0: sample the filter at the POD's 28 Hz cadence (#119
|
||||
// -- the per-Perform filter is frame-rate-dependent, the myomer-kinetic
|
||||
// class); negative (the ctor/reset prime calls) samples unconditionally.
|
||||
void
|
||||
UpdateHeatLoad(); // @004ad7f0
|
||||
UpdateHeatLoad(Scalar time_slice = -1.0f); // @004ad7f0
|
||||
void
|
||||
ClearHeatFilter(); // @004ad884
|
||||
void
|
||||
|
||||
@@ -1233,7 +1233,7 @@ void
|
||||
}
|
||||
heatEnergy += pendingHeat; // [0x56] += [0x72]
|
||||
currentTemperature = heatEnergy / thermalMass; // [0x45] = [0x56]/[0x55]
|
||||
UpdateHeatLoad(); // FUN_004ad7f0
|
||||
UpdateHeatLoad(time_slice); // FUN_004ad7f0 (28 Hz cadence, #119)
|
||||
pendingHeat = 0.0f;
|
||||
|
||||
Scalar target = 300.0f
|
||||
|
||||
Reference in New Issue
Block a user