Add typed field-flight prototype and preserve native qualification failures
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
// Candidate 100m field experiment only. BrakingReserve is an admission
|
||||
// hypothesis, not measured stopping performance or an emergency-landing promise.
|
||||
class ERR_AircraftFieldRules
|
||||
{
|
||||
static bool Length(float distance) { return distance >= 99.95 && distance <= 100.05; }
|
||||
static bool FiniteVector(vector value)
|
||||
{
|
||||
return Math.AbsFloat(value[0]) <= 1000000 && Math.AbsFloat(value[1]) <= 1000000 && Math.AbsFloat(value[2]) <= 1000000;
|
||||
}
|
||||
static float HorizontalSpeed(vector velocity)
|
||||
{
|
||||
velocity[1] = 0;
|
||||
return velocity.Length();
|
||||
}
|
||||
static bool SpeedAllowed(vector velocity) { return FiniteVector(velocity) && HorizontalSpeed(velocity) <= 2.5; }
|
||||
static bool ValidStep(float dt) { return dt > 0 && dt <= 0.5; }
|
||||
static float RampSpeed(float current, float target, float dt)
|
||||
{
|
||||
if (!(current >= 0 && current <= 2)) return 0;
|
||||
if (!(target >= 0 && target <= 2) || !ValidStep(dt)) return current;
|
||||
return current + Math.Clamp(target - current, -0.2 * dt, 0.2 * dt);
|
||||
}
|
||||
static vector CapHorizontal(vector value, float limit)
|
||||
{
|
||||
value[1] = 0;
|
||||
float magnitude = value.Length();
|
||||
if (magnitude > limit) value = value * (limit / magnitude);
|
||||
return value;
|
||||
}
|
||||
// Slew the complete horizontal vector: changing bearing cannot bypass the
|
||||
// acceleration velocityReference cap through an instantaneous sign/direction change.
|
||||
static vector RampReference(vector current, vector desired, float dt)
|
||||
{
|
||||
if (!FiniteVector(current)) return "0 0 0";
|
||||
current = CapHorizontal(current, 2);
|
||||
if (!FiniteVector(desired) || !ValidStep(dt)) return current;
|
||||
desired = CapHorizontal(desired, 2);
|
||||
return CapHorizontal(current + CapHorizontal(desired - current, 0.2 * dt), 2);
|
||||
}
|
||||
// Remaining target distance includes permitted takeoff/corridor drift; its
|
||||
// 120m arithmetic bound grants no authority beyond Contains/Length.
|
||||
// Invert the entire candidate stopping reserve (including1s latency and3m
|
||||
// margin), not just its deceleration term. Caller also freezes a0.9 entry-speed
|
||||
// cap to begin reducing the velocityReference immediately, then slews the vector.
|
||||
// The assumed0.15m/s² physical deceleration still requires native measurement.
|
||||
static float ApproachSpeed(float remaining, float current)
|
||||
{
|
||||
if (!(remaining >= 0 && remaining <= 120) || !(current >= 0 && current <= 2)) return 0;
|
||||
float reservedSpeed = (Math.Sqrt(0.09 + 1.2 * Math.Max(0, remaining - 3)) - 0.3) * 0.5;
|
||||
return Math.Min(current, Math.Max(0, reservedSpeed));
|
||||
}
|
||||
// Integral units are (m/s)*seconds; nextIntegral is caller-owned state.
|
||||
// Horizontal demand is world-space; the exact-owner controller converts it
|
||||
// to the native airframe basis. The caller resets state at phase transitions.
|
||||
static vector VelocityDemand(vector velocityReference, vector velocity, vector integral, float dt, out vector nextIntegral)
|
||||
{
|
||||
nextIntegral = "0 0 0";
|
||||
if (!FiniteVector(velocityReference) || !FiniteVector(velocity) || !FiniteVector(integral) || !ValidStep(dt)) return "0 0 0";
|
||||
velocityReference = CapHorizontal(velocityReference, 2);
|
||||
velocity[1] = 0;
|
||||
integral = CapHorizontal(integral, 4);
|
||||
vector error = velocityReference - velocity;
|
||||
vector candidate = CapHorizontal(integral + error * dt, 4);
|
||||
vector proposed = error * 0.10 + candidate * 0.02;
|
||||
// Freeze only integration which pushes an already saturated vector outward.
|
||||
// Opposing error can unwind stored demand while the output remains capped.
|
||||
nextIntegral = candidate;
|
||||
if (proposed.Length() > 0.08 && vector.Dot(proposed, error) > 0) nextIntegral = integral;
|
||||
return CapHorizontal(error * 0.10 + nextIntegral * 0.02, 0.08);
|
||||
}
|
||||
static float BrakingReserve(float speed)
|
||||
{
|
||||
if (!(speed >= 0 && speed <= 2.5)) return 1000000;
|
||||
return speed * speed / 0.30 + speed + 3;
|
||||
}
|
||||
static bool ShouldBrake(float remaining, float speed)
|
||||
{
|
||||
if (!(remaining >= 0 && remaining <= 120) || !(speed >= 0 && speed <= 2.5)) return true;
|
||||
return remaining <= Math.Max(25, BrakingReserve(speed));
|
||||
}
|
||||
// Admit only the full experimental lease, with <=1s dispatch allowance.
|
||||
// Never recompute a deadline from these checks or renew the original lease.
|
||||
static bool LeaseAdmitted(float now, float deadline)
|
||||
{
|
||||
return now >= 0 && deadline - now >= 239000 && deadline - now <= 240000;
|
||||
}
|
||||
static bool AbortDue(float now, float deadline)
|
||||
{
|
||||
if (!(now >= 0 && deadline > now && deadline - now <= 240000)) return true;
|
||||
return deadline - now <= 85000;
|
||||
}
|
||||
// 'since' is the caller's continuous low-speed observation start, in ms.
|
||||
// The caller clears it whenever actual horizontal speed is >=0.25m/s.
|
||||
static bool LowSpeedHeld(float speed, float since, float now)
|
||||
{
|
||||
return speed >= 0 && speed < 0.25 && since >= 0 && now >= since && now - since >= 2000;
|
||||
}
|
||||
static vector Nearest(vector start, vector end, vector point)
|
||||
{
|
||||
vector leg = end - start; leg[1] = 0;
|
||||
vector offset = point - start; offset[1] = 0;
|
||||
float squared = vector.Dot(leg, leg);
|
||||
if (!(squared > 0)) return start;
|
||||
return start + leg * Math.Clamp(vector.Dot(offset, leg) / squared, 0, 1);
|
||||
}
|
||||
static bool Contains(vector start, vector end, vector point, float upright)
|
||||
{
|
||||
if (!FiniteVector(start) || !FiniteVector(end) || !FiniteVector(point) || !Length(vector.DistanceXZ(start, end))) return false;
|
||||
float height = point[1] - start[1];
|
||||
return height >= -3 && height <= 18 && upright >= 0.85 && upright <= 1.01 && vector.DistanceXZ(point, Nearest(start, end, point)) < 8;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user