The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
evaluateSr09 · src/physics/reference/waves.ts · this site’s source, as built · sha256:ef623131c3e8ea8ac949e8079db833adab903b09b5bb016549d9ecbd18d959b4
This function computes the listed outputs when it runs.
In words
Paper 3's § 7 in one evaluation. It takes the boost, the angle the wave travels at in the resting system and its frequency, and returns the transformed angle, the transformed frequency, the Doppler factor, the amplitude factor, the line-of-sight factors for a source receding and approaching, and the aberration in arcseconds for the Earth's orbital speed. It also returns the second-order shift at a stated small speed, which is the part that distinguishes this prediction from the classical one.
Implementation
export function evaluateSr09(input: Sr09Input): Sr09EvaluationResult {
const beta = input.beta;
const thetaDeg = input.propagationAngleDeg;
const thetaRad = (thetaDeg * Math.PI) / 180;
const nuK = input.frequencyHz;
const omegaK = 2 * Math.PI * nuK;
const secondOrderSpeed = input.secondOrderSpeed ?? 0.005;
if (!Number.isFinite(beta) || Math.abs(beta) >= 1) {
return Object.freeze({
beta,
gamma: Number.NaN,
propagationAngleStationaryDeg: thetaDeg,
propagationAngleStationaryRad: thetaRad,
propagationAngleMovingDeg: Number.NaN,
propagationAngleMovingRad: Number.NaN,
cosThetaStationary: Number.NaN,
sinThetaStationary: Number.NaN,
cosThetaMoving: Number.NaN,
sinThetaMoving: Number.NaN,
waveFrequencyStationaryHz: nuK,
waveFrequencyMovingHz: Number.NaN,
waveAngularFrequencyStationary: omegaK,
waveAngularFrequencyMoving: Number.NaN,
dopplerFactor: Number.NaN,
amplitudeFactor: Number.NaN,
lineOfSightRecedingFactor: Number.NaN,
lineOfSightApproachingFactor: Number.NaN,
detectorCrossings: Number.NaN,
detectorProperRateHz: Number.NaN,
earthOrbitAberrationArcsec: Number.NaN,
earthOrbitAberrationFormatted: "outside-domain",
secondOrderShift: Number.NaN,
secondOrderComparisonSpeed: secondOrderSpeed,
events: [],
results: [
sr09Outside("frameSpeed", "c", "speed"),
sr09Outside("propagationAngleStationary", "deg", "angle"),
sr09Outside("propagationAngleMoving", "deg", "angle"),
sr09Outside("waveFrequencyStationary", "Hz", "frequency"),
sr09Outside("waveFrequencyMoving", "Hz", "frequency"),
sr09Outside("dopplerFactor", "1", "ratio"),
sr09Outside("wavePhase", "rad", "angle"),
sr09Outside("lorentzFactor", "1", "lorentz-factor"),
sr09Outside("classicalObserverDopplerFactor", "1", "ratio"),
sr09Outside("classicalSourceDopplerFactor", "1", "ratio"),
sr09Outside("recedingDopplerFactor", "1", "ratio"),
sr09Outside("approachingDopplerFactor", "1", "ratio"),
],
status: "outside-domain",
});
}
const gResult = gamma(beta);
const g = gResult.status === "value" ? gResult.value : Number.NaN;
const cosThetaK = Math.cos(thetaRad);
const sinThetaK = Math.sin(thetaRad);
const kMag = omegaK / C_SI;
const boosted = transformWaveVector(
omegaK,
{ x: kMag * cosThetaK, y: kMag * sinThetaK, z: 0 },
beta,
C_SI,
);
const omega_k = boosted.omegaPrime;
const nu_k = omega_k / (2 * Math.PI);
const doppler = omega_k / omegaK;
const ab = aberration(beta, thetaRad);
let theta_k_deg = (ab.thetaPrimeRad * 180) / Math.PI;
if (theta_k_deg < 0) theta_k_deg += 360;
const classicalObserver = classicalObserverDopplerFactor(beta, thetaRad);
const classicalSource = classicalSourceDopplerFactor(beta, thetaRad);
const recedingFactor = Math.sqrt((1 - beta) / (1 + beta));
const approachingFactor = Math.sqrt((1 + beta) / (1 - beta));
const detectorSpeed = input.detectorSpeed ?? beta;
const detectorWindow = input.countingWindow ?? 10 / nuK;
const detectorCrossings = detectorCrossingCount({
omega: omegaK,
k: { x: (omegaK / C_SI) * cosThetaK, y: (omegaK / C_SI) * sinThetaK, z: 0 },
detectorVelocity: { x: detectorSpeed * C_SI, y: 0, z: 0 },
window: detectorWindow,
});
const detectorProperRateHz = detectorCrossings / detectorWindow;
const modernAberration = modernEarthOrbitAberration();
const earthOrbitAberrationArcsec = modernAberration.arcsec;
const earthOrbitAberrationFormatted = `${earthOrbitAberrationArcsec.toFixed(4)}" (${modernAberration.label})`;
const secondOrderShiftVal = secondOrderShift(secondOrderSpeed);
// Discrete named events for Phase Invariance verification
const kxK = (omegaK / C_SI) * cosThetaK;
const kyK = (omegaK / C_SI) * sinThetaK;
const kzK = 0;
const wave1_K = { omega: omegaK, kx: kxK, ky: kyK, kz: kzK };
const transW = transformWaveVector(omegaK, { x: kxK, y: kyK, z: kzK }, beta, C_SI);
const wave1_k = {
omega: transW.omegaPrime,
kx: transW.kPrime.x,
ky: transW.kPrime.y,
kz: transW.kPrime.z,
};
// Event 1: tick at t = 1e-15 s, x = 0, y = 0, z = 0
const event1_K = { t: 1e-15, x: 0, y: 0, z: 0 };
const event1_k = {
t: g * (event1_K.t - (beta * event1_K.x) / C_SI),
x: g * (event1_K.x - beta * C_SI * event1_K.t),
y: 0,
z: 0,
};
const p1_K = phaseAtEvent(event1_K, wave1_K);
const p1_k = phaseAtEvent(event1_k, wave1_k);
const val1_K = p1_K.status === "value" && typeof p1_K.value === "number" ? p1_K.value : 0;
const val1_k = p1_k.status === "value" && typeof p1_k.value === "number" ? p1_k.value : 0;
// Adversarial Phase: uses Galilean wave transformation where kx does not mix with omega
const adv_kx_k = g * (kxK + (beta * omegaK) / C_SI);
const adv_wave1_k = { omega: omega_k, kx: adv_kx_k, ky: kyK, kz: kzK };
const adv_p1_k = phaseAtEvent(event1_k, adv_wave1_k);
const adv_val1_k =
adv_p1_k.status === "value" && typeof adv_p1_k.value === "number" ? adv_p1_k.value : 0;
// Event 2: offset event (t = 2e-15 s, x = 3e-7 m, y = 0, z = 0)
const event2_K = { t: 2e-15, x: 3e-7, y: 0, z: 0 };
const event2_k = {
t: g * (event2_K.t - (beta * event2_K.x) / C_SI),
x: g * (event2_K.x - beta * C_SI * event2_K.t),
y: 0,
z: 0,
};
const p2_K = phaseAtEvent(event2_K, wave1_K);
const p2_k = phaseAtEvent(event2_k, wave1_k);
const val2_K = p2_K.status === "value" && typeof p2_K.value === "number" ? p2_K.value : 0;
const val2_k = p2_k.status === "value" && typeof p2_k.value === "number" ? p2_k.value : 0;
const adv_p2_k = phaseAtEvent(event2_k, adv_wave1_k);
const adv_val2_k =
adv_p2_k.status === "value" && typeof adv_p2_k.value === "number" ? adv_p2_k.value : 0;
const events: readonly Sr09NamedEventRecord[] = [
Object.freeze({
id: "sr-09-event-origin-tick",
label: "Origin cycle tick (t = 1 fs, x = 0)",
eventK: event1_K,
event_k: event1_k,
waveK: wave1_K,
wave_k: wave1_k,
phaseK: val1_K,
phase_k: val1_k,
phasesAgree:
classifyWithTolerance(val1_K - val1_k, { absolute: 1e-12 }).sign === "indeterminate" ||
val1_K === val1_k,
adversarialPhase_k: adv_val1_k,
}),
Object.freeze({
id: "sr-09-event-offset",
label: "Offset downstream event (t = 2 fs, x = 300 nm)",
eventK: event2_K,
event_k: event2_k,
waveK: wave1_K,
wave_k: wave1_k,
phaseK: val2_K,
phase_k: val2_k,
phasesAgree:
classifyWithTolerance(val2_K - val2_k, { absolute: 1e-12 }).sign === "indeterminate" ||
val2_K === val2_k,
adversarialPhase_k: adv_val2_k,
}),
];
const results: readonly ScientificResult[] = [
Object.freeze({
quantityId: "frameSpeed",
unit: "c",
semanticKind: "speed",
ownerId: OWNER_ID,
status: "value",
value: beta,
}),
Object.freeze({
quantityId: "propagationAngleStationary",
unit: "deg",
semanticKind: "angle",
ownerId: OWNER_ID,
status: "value",
value: thetaDeg,
}),
Object.freeze({
quantityId: "propagationAngleMoving",
unit: "deg",
semanticKind: "angle",
ownerId: OWNER_ID,
status: "value",
value: theta_k_deg,
}),
Object.freeze({
quantityId: "waveFrequencyStationary",
unit: "Hz",
semanticKind: "frequency",
ownerId: OWNER_ID,
status: "value",
value: nuK,
}),
Object.freeze({
quantityId: "waveFrequencyMoving",
unit: "Hz",
semanticKind: "frequency",
ownerId: OWNER_ID,
status: "value",
value: nu_k,
}),
Object.freeze({
quantityId: "dopplerFactor",
unit: "1",
semanticKind: "ratio",
ownerId: OWNER_ID,
status: "value",
value: doppler,
}),
Object.freeze({
quantityId: "wavePhase",
unit: "rad",
semanticKind: "angle",
ownerId: OWNER_ID,
status: "value",
value: val1_K,
}),
Object.freeze({
quantityId: "lorentzFactor",
unit: "1",
semanticKind: "lorentz-factor",
ownerId: OWNER_ID,
status: "value",
value: g,
}),
Object.freeze({
quantityId: "classicalObserverDopplerFactor",
unit: "1",
semanticKind: "ratio",
ownerId: OWNER_ID,
status: "value",
value: classicalObserver,
}),
Object.freeze({
quantityId: "classicalSourceDopplerFactor",
unit: "1",
semanticKind: "ratio",
ownerId: OWNER_ID,
status: "value",
value: classicalSource,
}),
Object.freeze({
quantityId: "recedingDopplerFactor",
unit: "1",
semanticKind: "ratio",
ownerId: OWNER_ID,
status: "value",
value: recedingFactor,
}),
Object.freeze({
quantityId: "approachingDopplerFactor",
unit: "1",
semanticKind: "ratio",
ownerId: OWNER_ID,
status: "value",
value: approachingFactor,
}),
];
return Object.freeze({
beta,
gamma: g,
propagationAngleStationaryDeg: thetaDeg,
propagationAngleStationaryRad: thetaRad,
propagationAngleMovingDeg: theta_k_deg,
propagationAngleMovingRad: ab.thetaPrimeRad,
cosThetaStationary: cosThetaK,
sinThetaStationary: sinThetaK,
cosThetaMoving: ab.cosThetaPrime,
sinThetaMoving: ab.sinThetaPrime,
waveFrequencyStationaryHz: nuK,
waveFrequencyMovingHz: nu_k,
waveAngularFrequencyStationary: omegaK,
waveAngularFrequencyMoving: omega_k,
dopplerFactor: doppler,
amplitudeFactor: doppler,
lineOfSightRecedingFactor: recedingFactor,
lineOfSightApproachingFactor: approachingFactor,
detectorCrossings,
detectorProperRateHz,
earthOrbitAberrationArcsec,
earthOrbitAberrationFormatted,
secondOrderShift: secondOrderShiftVal,
secondOrderComparisonSpeed: secondOrderSpeed,
events,
results,
status: "value",
});
}