@photivra/engine 2.18.0 → 2.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +179 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +7 -5
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +14 -10
- package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
- package/dist/capture/dng-lens-correction-opcodes.js +119 -0
- package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
- package/dist/capture/focus-control.js +2 -75
- package/dist/capture/focus-control.js.map +1 -1
- package/dist/capture/native-environment-lean.d.ts +1 -0
- package/dist/capture/native-environment-lean.js +2 -6
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-optical-stage.d.ts +1 -0
- package/dist/capture/native-environment-optical-stage.js +2 -5
- package/dist/capture/native-environment-optical-stage.js.map +1 -1
- package/dist/capture/native-environment-raw.js +1 -5
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/capture/native-raw-dng.d.ts +6 -0
- package/dist/capture/native-raw-dng.js +16 -2
- package/dist/capture/native-raw-dng.js.map +1 -1
- package/dist/capture/release-sequence.js +2 -47
- package/dist/capture/release-sequence.js.map +1 -1
- package/dist/capture/sensor-raw-producer.js +3 -5
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/color/white-balance.d.ts +2 -0
- package/dist/color/white-balance.js +3 -56
- package/dist/color/white-balance.js.map +1 -1
- package/dist/composition/image-formation-plan.d.ts +1 -0
- package/dist/composition/image-formation-plan.js +3 -49
- package/dist/composition/image-formation-plan.js.map +1 -1
- package/dist/core/evidence-provenance.js +1 -16
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/record-validation.d.ts +54 -0
- package/dist/core/record-validation.js +176 -0
- package/dist/core/record-validation.js.map +1 -1
- package/dist/core/scientific-assurance.js +1 -18
- package/dist/core/scientific-assurance.js.map +1 -1
- package/dist/core/shared-helpers.d.ts +35 -0
- package/dist/core/shared-helpers.js +38 -0
- package/dist/core/shared-helpers.js.map +1 -0
- package/dist/core/spectral-composition.js +1 -36
- package/dist/core/spectral-composition.js.map +1 -1
- package/dist/core/spectral.js +1 -19
- package/dist/core/spectral.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/exposure-capabilities.d.ts +1 -0
- package/dist/equipment/exposure-capabilities.js +2 -36
- package/dist/equipment/exposure-capabilities.js.map +1 -1
- package/dist/equipment/generic-lens-catalogue.d.ts +8 -2
- package/dist/equipment/generic-lens-catalogue.js +31 -2
- package/dist/equipment/generic-lens-catalogue.js.map +1 -1
- package/dist/equipment/generic-tier-assets.js +2 -3
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.js +2 -3
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/equipment/iso-capabilities.js +2 -49
- package/dist/equipment/iso-capabilities.js.map +1 -1
- package/dist/equipment/metering-capabilities.js +1 -26
- package/dist/equipment/metering-capabilities.js.map +1 -1
- package/dist/equipment/release-capabilities.js +1 -53
- package/dist/equipment/release-capabilities.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
- package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
- package/dist/exposure/exposure-duration-control.js +1 -16
- package/dist/exposure/exposure-duration-control.js.map +1 -1
- package/dist/exposure/exposure-mode-resolver.js +1 -17
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/exposure/filtered-exposure-time.d.ts +93 -0
- package/dist/exposure/filtered-exposure-time.js +129 -0
- package/dist/exposure/filtered-exposure-time.js.map +1 -0
- package/dist/exposure/flash-ttl.d.ts +1 -0
- package/dist/exposure/flash-ttl.js +1 -1
- package/dist/exposure/flash-ttl.js.map +1 -1
- package/dist/exposure/flash.js +1 -49
- package/dist/exposure/flash.js.map +1 -1
- package/dist/exposure/metering-scene-radiance.js +1 -25
- package/dist/exposure/metering-scene-radiance.js.map +1 -1
- package/dist/exposure/metering-target.js +1 -30
- package/dist/exposure/metering-target.js.map +1 -1
- package/dist/exposure/metering-temporal.js +1 -8
- package/dist/exposure/metering-temporal.js.map +1 -1
- package/dist/exposure/metering.js +1 -72
- package/dist/exposure/metering.js.map +1 -1
- package/dist/exposure/program-line.js +1 -45
- package/dist/exposure/program-line.js.map +1 -1
- package/dist/facade/develop-joined-parts.d.ts +29 -0
- package/dist/facade/develop-joined-parts.js +33 -0
- package/dist/facade/develop-joined-parts.js.map +1 -0
- package/dist/facade/display-view-gpu.d.ts +7 -4
- package/dist/facade/display-view-gpu.js +4 -4
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.d.ts +1 -1
- package/dist/facade/display-view-lens-signal.js +5 -3
- package/dist/facade/display-view-lens-signal.js.map +1 -1
- package/dist/facade/display-view.d.ts +3 -1
- package/dist/facade/display-view.js +1 -1
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/fast-methods.d.ts +50 -0
- package/dist/facade/fast-methods.js +50 -0
- package/dist/facade/fast-methods.js.map +1 -0
- package/dist/facade/fast-resolution.d.ts +12 -0
- package/dist/facade/fast-resolution.js +18 -0
- package/dist/facade/fast-resolution.js.map +1 -0
- package/dist/facade/generic-lens-capture.d.ts +6 -3
- package/dist/facade/generic-lens-capture.js +6 -3
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +88 -16
- package/dist/facade/simulate-capture.js +279 -153
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +3 -2
- package/dist/facade/simulate-display-view.js +22 -12
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.js +1 -3
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +1 -5
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
- package/dist/gpu/display-view-quality-gpu.js +4 -8
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.js +3 -25
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/sensor-stage-gpu.js +1 -5
- package/dist/gpu/sensor-stage-gpu.js.map +1 -1
- package/dist/gpu/webgpu-runtime.d.ts +2 -0
- package/dist/gpu/webgpu-runtime.js +3 -0
- package/dist/gpu/webgpu-runtime.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.js +1 -6
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
- package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
- package/dist/motion/capture-rotation-trajectory.js +2 -17
- package/dist/motion/capture-rotation-trajectory.js.map +1 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
- package/dist/motion/extended-object-projection.js +5 -40
- package/dist/motion/extended-object-projection.js.map +1 -1
- package/dist/optics/aperture-diameter.d.ts +47 -0
- package/dist/optics/aperture-diameter.js +50 -0
- package/dist/optics/aperture-diameter.js.map +1 -0
- package/dist/optics/atmospheric-haze.js +1 -7
- package/dist/optics/atmospheric-haze.js.map +1 -1
- package/dist/optics/brown-conrady-distortion.js +1 -7
- package/dist/optics/brown-conrady-distortion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +1 -0
- package/dist/optics/complex-pupil-psf.js +2 -84
- package/dist/optics/complex-pupil-psf.js.map +1 -1
- package/dist/optics/detail-limit.d.ts +182 -0
- package/dist/optics/detail-limit.js +336 -0
- package/dist/optics/detail-limit.js.map +1 -0
- package/dist/optics/focus-state.js +1 -11
- package/dist/optics/focus-state.js.map +1 -1
- package/dist/optics/front-of-lens-filter.d.ts +5 -0
- package/dist/optics/front-of-lens-filter.js +3 -65
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/generic-lens-psf.d.ts +18 -2
- package/dist/optics/generic-lens-psf.js +25 -2
- package/dist/optics/generic-lens-psf.js.map +1 -1
- package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
- package/dist/optics/generic-nd-filter-presets.js +48 -0
- package/dist/optics/generic-nd-filter-presets.js.map +1 -0
- package/dist/optics/illumination-vignetting.js +1 -6
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +4 -1
- package/dist/optics/lens-psf-profile.js +12 -111
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
- package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
- package/dist/optics/pupil-vignetting.js +1 -7
- package/dist/optics/pupil-vignetting.js.map +1 -1
- package/dist/optics/radial-distortion.js +1 -6
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
- package/dist/optics/scene-to-sensor-irradiance.js +11 -96
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/optics/stray-light.d.ts +1 -0
- package/dist/optics/stray-light.js +1 -1
- package/dist/optics/stray-light.js.map +1 -1
- package/dist/optics/zernike-wavefront.js +1 -7
- package/dist/optics/zernike-wavefront.js.map +1 -1
- package/dist/output/capture-geometry.js +1 -8
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/crop-to-match-focal-length.d.ts +62 -0
- package/dist/output/crop-to-match-focal-length.js +63 -0
- package/dist/output/crop-to-match-focal-length.js.map +1 -0
- package/dist/output/developed-lens-corrections.d.ts +62 -0
- package/dist/output/developed-lens-corrections.js +135 -0
- package/dist/output/developed-lens-corrections.js.map +1 -0
- package/dist/output/generic-lens-corrections.d.ts +5 -7
- package/dist/output/generic-lens-corrections.js +11 -10
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/geometric-transforms.js +1 -4
- package/dist/output/geometric-transforms.js.map +1 -1
- package/dist/output/lens-corrections.d.ts +12 -2
- package/dist/output/lens-corrections.js +22 -7
- package/dist/output/lens-corrections.js.map +1 -1
- package/dist/output/native-capture-sdr.d.ts +2 -2
- package/dist/output/native-capture-sdr.js +3 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/print-contrast-reference.js +1 -1
- package/dist/output/print-contrast-reference.js.map +1 -1
- package/dist/output/print-size-blur-noise.d.ts +110 -0
- package/dist/output/print-size-blur-noise.js +138 -0
- package/dist/output/print-size-blur-noise.js.map +1 -0
- package/dist/processing/development-detail.d.ts +29 -0
- package/dist/processing/development-detail.js +128 -107
- package/dist/processing/development-detail.js.map +1 -1
- package/dist/schema/illumination-temporal.js +3 -72
- package/dist/schema/illumination-temporal.js.map +1 -1
- package/dist/schema/illumination.d.ts +1 -0
- package/dist/schema/illumination.js +2 -65
- package/dist/schema/illumination.js.map +1 -1
- package/dist/schema/scene-radiance-temporal.js +2 -14
- package/dist/schema/scene-radiance-temporal.js.map +1 -1
- package/dist/schema/scene-radiance.js +2 -60
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/schema/validation.d.ts +2 -0
- package/dist/schema/validation.js +2 -17
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.js +2 -59
- package/dist/sensor/accumulated-charge.js.map +1 -1
- package/dist/sensor/architecture.js +1 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
- package/dist/sensor/camera-saturation-capacity.js +3 -55
- package/dist/sensor/camera-saturation-capacity.js.map +1 -1
- package/dist/sensor/capture-color-sampling-binding.js +1 -26
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
- package/dist/sensor/capture-mode-timing.js +1 -39
- package/dist/sensor/capture-mode-timing.js.map +1 -1
- package/dist/sensor/capture-mode.js +1 -23
- package/dist/sensor/capture-mode.js.map +1 -1
- package/dist/sensor/color-sampling.js +1 -26
- package/dist/sensor/color-sampling.js.map +1 -1
- package/dist/sensor/constant-rate-temporal-integration.js +2 -46
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
- package/dist/sensor/dark-current.js +2 -45
- package/dist/sensor/dark-current.js.map +1 -1
- package/dist/sensor/eqe-electron-rate.js +2 -41
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +7 -0
- package/dist/sensor/exposure-window.js +9 -24
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/iso-gain.js +1 -7
- package/dist/sensor/iso-gain.js.map +1 -1
- package/dist/sensor/iso-signal-chain.js +1 -43
- package/dist/sensor/iso-signal-chain.js.map +1 -1
- package/dist/sensor/optical-stack.js +1 -25
- package/dist/sensor/optical-stack.js.map +1 -1
- package/dist/sensor/photon-energy.js +1 -26
- package/dist/sensor/photon-energy.js.map +1 -1
- package/dist/sensor/physical-charge-capacity.js +3 -77
- package/dist/sensor/physical-charge-capacity.js.map +1 -1
- package/dist/sensor/radiometry-readiness.js +2 -23
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +3 -0
- package/dist/sensor/raw-readout.js +4 -66
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/raw-reconstruction.js +2 -64
- package/dist/sensor/raw-reconstruction.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.js +1 -9
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/dist/sensor/readout-timing.js +4 -79
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.d.ts +2 -0
- package/dist/sensor/response-application-compatibility.js +4 -35
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/response-operating-range.d.ts +1 -0
- package/dist/sensor/response-operating-range.js +3 -79
- package/dist/sensor/response-operating-range.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.js +4 -114
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sampling-aperture.js +1 -25
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/dist/sensor/sensor-characteristics.d.ts +137 -0
- package/dist/sensor/sensor-characteristics.js +115 -0
- package/dist/sensor/sensor-characteristics.js.map +1 -0
- package/dist/sensor/spatial-sample-reduction.js +3 -24
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.js +1 -3
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
- package/dist/sensor/spatio-spectral-reduction.js +1 -18
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
- package/dist/sensor/spectral-coverage.d.ts +10 -1
- package/dist/sensor/spectral-coverage.js +1 -1
- package/dist/sensor/spectral-coverage.js.map +1 -1
- package/dist/sensor/spectral-quadrature.js +3 -41
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/spectral-response.js +1 -47
- package/dist/sensor/spectral-response.js.map +1 -1
- package/dist/sensor/temporal-photo-signal.d.ts +3 -0
- package/dist/sensor/temporal-photo-signal.js +5 -2
- package/dist/sensor/temporal-photo-signal.js.map +1 -1
- package/dist/stabilization/camera-shake.js +1 -6
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.d.ts +9 -0
- package/dist/stabilization/system.js +7 -86
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +5 -0
- package/docs/API_REFERENCE.md +116 -3
- package/docs/QUICK_START.md +178 -14
- package/docs/USAGE.md +111 -3
- package/docs/api/capture-native-raw-dng.md +6 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +7 -2
- package/docs/api/exports.json +203 -3
- package/docs/api/exposure-filtered-exposure-time.md +105 -0
- package/docs/api/facade-develop-joined-parts.md +32 -0
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-fast-methods.md +91 -0
- package/docs/api/facade-simulate-capture.md +72 -16
- package/docs/api/facade-simulate-display-view.md +3 -2
- package/docs/api/optics-aperture-diameter.md +51 -0
- package/docs/api/optics-detail-limit.md +203 -0
- package/docs/api/optics-generic-nd-filter-presets.md +34 -0
- package/docs/api/optics-lens-psf-profile.md +3 -1
- package/docs/api/output-crop-to-match-focal-length.md +67 -0
- package/docs/api/output-developed-lens-corrections.md +12 -0
- package/docs/api/output-generic-lens-corrections.md +3 -10
- package/docs/api/output-lens-corrections.md +11 -1
- package/docs/api/output-print-size-blur-noise.md +115 -0
- package/docs/api/sensor-sensor-characteristics.md +105 -0
- package/llms.txt +5 -0
- package/package.json +1 -1
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
* @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support
|
|
12
12
|
* limits.
|
|
13
13
|
*/
|
|
14
|
-
import { rejectUnknownFields } from "../core/record-validation.js";
|
|
15
14
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
16
15
|
import { parseEvidenceList } from "../core/evidence-provenance.js";
|
|
17
16
|
import { InvalidScientificInputError } from "../core/validation.js";
|
|
17
|
+
import { requireConfigRecord as requireRecord, requireConfigString as requireNonEmptyString, requireConfigFiniteNumber as requireFiniteNumber } from "../core/record-validation.js";
|
|
18
18
|
const COMPONENT_ROLES = new Set([
|
|
19
19
|
"cover-glass",
|
|
20
20
|
"infrared-cut",
|
|
@@ -24,23 +24,6 @@ const COMPONENT_ROLES = new Set([
|
|
|
24
24
|
"wave-plate",
|
|
25
25
|
"other-optical-filter"
|
|
26
26
|
]);
|
|
27
|
-
function requireRecord(value, path, allowedKeys) {
|
|
28
|
-
if (typeof value !== "object" ||
|
|
29
|
-
value === null ||
|
|
30
|
-
Array.isArray(value)) {
|
|
31
|
-
throw new InvalidConfigurationError(path + " must be an object.");
|
|
32
|
-
}
|
|
33
|
-
if (allowedKeys !== null)
|
|
34
|
-
rejectUnknownFields(value, allowedKeys, path);
|
|
35
|
-
return value;
|
|
36
|
-
}
|
|
37
|
-
function requireNonEmptyString(value, path) {
|
|
38
|
-
if (typeof value !== "string" ||
|
|
39
|
-
value.trim().length === 0) {
|
|
40
|
-
throw new InvalidConfigurationError(path + " must be a non-empty string.");
|
|
41
|
-
}
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
27
|
function parseComponentRoles(value, path) {
|
|
45
28
|
if (!Array.isArray(value) || value.length === 0) {
|
|
46
29
|
throw new InvalidConfigurationError(path + " must be a non-empty array.");
|
|
@@ -75,13 +58,6 @@ function parseOrderedComponents(value, path) {
|
|
|
75
58
|
}
|
|
76
59
|
return components;
|
|
77
60
|
}
|
|
78
|
-
function requireFiniteNumber(value, path) {
|
|
79
|
-
if (typeof value !== "number" ||
|
|
80
|
-
!Number.isFinite(value)) {
|
|
81
|
-
throw new InvalidConfigurationError(path + " must be a finite number.");
|
|
82
|
-
}
|
|
83
|
-
return value;
|
|
84
|
-
}
|
|
85
61
|
function parsePointSplitComponents(value, path) {
|
|
86
62
|
if (!Array.isArray(value) || value.length === 0) {
|
|
87
63
|
throw new InvalidConfigurationError(path + " must be a non-empty array.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optical-stack.js","sourceRoot":"","sources":["../../src/sensor/optical-stack.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Sensor optical stack: the layers in front of the photodiodes (such as cover glass, infrared- and\n * ultraviolet-cut filters, a birefringent low-pass filter and microlenses), described as metadata,\n * plus an optional declared anti-aliasing (AA) blur kernel.\n *\n * Whether a component is physically present is recorded separately from its net AA effect. That lets\n * the schema describe designs that cancel the AA effect without claiming the hardware is missing.\n * Component presence alone creates no optical effect. Thickness, refractive index, spectral\n * transmission, angle of acceptance, focus shift and microlens collection need separate models.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { rejectUnknownFields } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport type SensorOpticalStackComponentRole =\n | \"cover-glass\"\n | \"infrared-cut\"\n | \"ultraviolet-cut\"\n | \"anti-reflection\"\n | \"birefringent-low-pass\"\n | \"wave-plate\"\n | \"other-optical-filter\";\n\nexport interface SensorOpticalStackComponent {\n componentId: string;\n /**\n * A component can have several roles, because one physical element can do\n * more than one optical or filtering job.\n */\n roles: readonly SensorOpticalStackComponentRole[];\n evidence: readonly EvidenceProvenance[];\n}\n\nexport interface SensorMicrolensDeclaration {\n presence: \"present\" | \"absent\";\n evidence: readonly EvidenceProvenance[];\n /**\n * Being present does not establish any model of angle, spectrum, fill factor\n * or collection efficiency.\n */\n opticalEffectModel: \"unresolved\";\n}\n\nexport interface AntiAliasingPointSplitComponent {\n /**\n * Physical offset on the native sensor from where the light would otherwise\n * land. +X right, +Y down. Units: micrometres.\n */\n offsetMicrometers: {\n x: number;\n y: number;\n };\n /**\n * Normalized weight (dimensionless). A point-splitting kernel only describes\n * where the light goes; the stack's total throughput is not part of it.\n */\n normalizedWeight: number;\n}\n\nexport type SensorEffectiveAntiAliasingSpatialResponse =\n | {\n /**\n * Documented absence (or cancellation) of deliberate AA splitting. It does\n * not mean the rest of the sensor stack has no optical effect.\n */\n kind: \"absent\";\n evidence: readonly EvidenceProvenance[];\n }\n | {\n /**\n * An AA effect is known to exist, but its spatial response is not\n * specified well enough to use.\n */\n kind: \"present-unresolved\";\n evidence: readonly EvidenceProvenance[];\n }\n | {\n /**\n * Generic approximation: each point is split into weighted copies at\n * offsets in native sensor physical coordinates.\n */\n kind: \"normalized-point-splitting-kernel\";\n evidence: readonly EvidenceProvenance[];\n coordinateSystem: \"native-sensor-physical\";\n scope:\n \"field-wavelength-polarization-invariant-approximation\";\n components: readonly AntiAliasingPointSplitComponent[];\n };\n\nexport interface SensorOpticalStackProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n evidence: readonly EvidenceProvenance[];\n /**\n * In order from the side light enters towards the sensor.\n *\n * These components are descriptive metadata only. Their presence does not\n * create transmission, focus-shift, aberration or spectral effects.\n */\n orderedComponents?: readonly SensorOpticalStackComponent[];\n /**\n * Omitted means \"unknown, not stated\".\n *\n * This is separate from which components are present, so a stack can\n * contain low-pass hardware while its net AA effect is absent or cancelled.\n */\n effectiveAntiAliasingSpatialResponse?: SensorEffectiveAntiAliasingSpatialResponse;\n /**\n * Omitted means \"unknown, not stated\".\n */\n microlens?: SensorMicrolensDeclaration;\n}\n\nexport interface ResolvedAntiAliasingSpatialKernel {\n profileId: string;\n effectiveResponse:\n | \"absent\"\n | \"normalized-point-splitting-kernel\";\n coordinateSystem: \"native-sensor-physical\";\n components: readonly AntiAliasingPointSplitComponent[];\n normalizedWeightSum: number;\n throughputIncluded: false;\n spectralTransmissionIncluded: false;\n fieldDependenceIncluded: false;\n wavelengthDependenceIncluded: false;\n polarizationDependenceIncluded: false;\n microlensResponseIncluded: false;\n coverFilterStackEffectsIncluded: false;\n wholeSensorOpticalStackResponse: false;\n provenance: {\n profile: readonly EvidenceProvenance[];\n antiAliasingResponse: readonly EvidenceProvenance[];\n };\n}\n\nconst COMPONENT_ROLES = new Set<SensorOpticalStackComponentRole>([\n \"cover-glass\",\n \"infrared-cut\",\n \"ultraviolet-cut\",\n \"anti-reflection\",\n \"birefringent-low-pass\",\n \"wave-plate\",\n \"other-optical-filter\"\n]);\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireNonEmptyString(\n value: unknown,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty string.\"\n );\n }\n return value;\n}\n\nfunction parseComponentRoles(\n value: unknown,\n path: string\n): readonly SensorOpticalStackComponentRole[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty array.\"\n );\n }\n\n const roles = value.map((entry, index) => {\n if (\n typeof entry !== \"string\" ||\n !COMPONENT_ROLES.has(\n entry as SensorOpticalStackComponentRole\n )\n ) {\n throw new InvalidConfigurationError(\n path + \"[\" + index + \"] is invalid.\"\n );\n }\n return entry as SensorOpticalStackComponentRole;\n });\n\n if (new Set(roles).size !== roles.length) {\n throw new InvalidConfigurationError(\n path + \" must not contain duplicate roles.\"\n );\n }\n\n return roles;\n}\n\nfunction parseOrderedComponents(\n value: unknown,\n path: string\n): readonly SensorOpticalStackComponent[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty array.\"\n );\n }\n\n const components = value.map((entry, index) => {\n const record = requireRecord(\n entry,\n path + \"[\" + index + \"]\", [\"componentId\", \"roles\", \"evidence\"]\n );\n\n return {\n componentId: requireNonEmptyString(\n record.componentId,\n path + \"[\" + index + \"].componentId\"\n ),\n roles: parseComponentRoles(\n record.roles,\n path + \"[\" + index + \"].roles\"\n ),\n evidence: parseEvidenceList(\n record.evidence,\n path + \"[\" + index + \"].evidence\"\n )\n };\n });\n\n const ids = components.map(\n (component) => component.componentId\n );\n if (new Set(ids).size !== ids.length) {\n throw new InvalidConfigurationError(\n path + \" must not contain duplicate componentId values.\"\n );\n }\n\n return components;\n}\n\nfunction requireFiniteNumber(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be a finite number.\"\n );\n }\n return value;\n}\n\nfunction parsePointSplitComponents(\n value: unknown,\n path: string\n): readonly AntiAliasingPointSplitComponent[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty array.\"\n );\n }\n\n const components = value.map((entry, index) => {\n const record = requireRecord(\n entry,\n path + \"[\" + index + \"]\", [\"offsetMicrometers\", \"normalizedWeight\"]\n );\n const offset = requireRecord(\n record.offsetMicrometers,\n path + \"[\" + index + \"].offsetMicrometers\", [\"x\", \"y\"]\n );\n const normalizedWeight = requireFiniteNumber(\n record.normalizedWeight,\n path + \"[\" + index + \"].normalizedWeight\"\n );\n\n if (normalizedWeight <= 0) {\n throw new InvalidConfigurationError(\n path +\n \"[\" +\n index +\n \"].normalizedWeight must be greater than zero.\"\n );\n }\n\n return {\n offsetMicrometers: {\n x: requireFiniteNumber(\n offset.x,\n path +\n \"[\" +\n index +\n \"].offsetMicrometers.x\"\n ),\n y: requireFiniteNumber(\n offset.y,\n path +\n \"[\" +\n index +\n \"].offsetMicrometers.y\"\n )\n },\n normalizedWeight\n };\n });\n\n const weightSum = components.reduce(\n (sum, component) =>\n sum + component.normalizedWeight,\n 0\n );\n\n if (\n !Number.isFinite(weightSum) ||\n Math.abs(weightSum - 1) > 1e-12\n ) {\n throw new InvalidConfigurationError(\n path +\n \" normalizedWeight values must sum to 1 within 1e-12.\"\n );\n }\n\n return components;\n}\n\nfunction parseAntiAliasingResponse(\n value: unknown,\n path: string\n): SensorEffectiveAntiAliasingSpatialResponse {\n const record = requireRecord(value, path, [\"kind\", \"coordinateSystem\", \"scope\", \"components\", \"evidence\"]);\n\n if (\n record.kind === \"absent\" ||\n record.kind === \"present-unresolved\"\n ) {\n if (\n record.coordinateSystem !== undefined ||\n record.scope !== undefined ||\n record.components !== undefined\n ) {\n throw new InvalidConfigurationError(\n path +\n \" absent/present-unresolved responses must omit kernel fields.\"\n );\n }\n return {\n kind: record.kind,\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n }\n\n if (\n record.kind ===\n \"normalized-point-splitting-kernel\"\n ) {\n if (\n record.coordinateSystem !==\n \"native-sensor-physical\"\n ) {\n throw new InvalidConfigurationError(\n path +\n '.coordinateSystem must be \"native-sensor-physical\".'\n );\n }\n if (\n record.scope !==\n \"field-wavelength-polarization-invariant-approximation\"\n ) {\n throw new InvalidConfigurationError(\n path + \".scope is invalid.\"\n );\n }\n\n return {\n kind:\n \"normalized-point-splitting-kernel\",\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n coordinateSystem:\n \"native-sensor-physical\",\n scope:\n \"field-wavelength-polarization-invariant-approximation\",\n components: parsePointSplitComponents(\n record.components,\n path + \".components\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseMicrolens(\n value: unknown,\n path: string\n): SensorMicrolensDeclaration {\n const record = requireRecord(value, path, [\"presence\", \"opticalEffectModel\", \"evidence\"]);\n\n if (\n record.presence !== \"present\" &&\n record.presence !== \"absent\"\n ) {\n throw new InvalidConfigurationError(\n path + \".presence is invalid.\"\n );\n }\n\n if (record.opticalEffectModel !== \"unresolved\") {\n throw new InvalidConfigurationError(\n path +\n '.opticalEffectModel must be \"unresolved\" in schema 0.1.0.'\n );\n }\n\n return {\n presence: record.presence,\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n opticalEffectModel: \"unresolved\"\n };\n}\n\n/**\n * Parses descriptive sensor optical-stack metadata, plus an optional explicitly\n * declared anti-aliasing (AA) spatial response.\n *\n * Leave out unknown facts rather than guessing them. Physical presence of a\n * component is separate from the net AA response, so the schema can describe\n * designs that cancel the AA effect without claiming the hardware is missing.\n *\n * In schema 0.1.0, cover glass, filters and microlenses create no optical\n * effect. Thickness, refractive index, spectral transmission, angle of\n * acceptance, focus shift and microlens collection need later explicit models\n * or calibration.\n */\nexport function parseSensorOpticalStackProfile(\n value: unknown\n): SensorOpticalStackProfile {\n const profile = requireRecord(\n value,\n \"sensorOpticalStack\", [\"schemaVersion\", \"orderedComponents\", \"effectiveAntiAliasingSpatialResponse\", \"microlens\", \"profileId\", \"evidence\"]\n );\n\n if (profile.schemaVersion !== \"0.1.0\") {\n throw new InvalidConfigurationError(\n 'sensorOpticalStack.schemaVersion must be \"0.1.0\".'\n );\n }\n\n const orderedComponents =\n profile.orderedComponents === undefined\n ? undefined\n : parseOrderedComponents(\n profile.orderedComponents,\n \"sensorOpticalStack.orderedComponents\"\n );\n\n const effectiveAntiAliasingSpatialResponse =\n profile.effectiveAntiAliasingSpatialResponse ===\n undefined\n ? undefined\n : parseAntiAliasingResponse(\n profile.effectiveAntiAliasingSpatialResponse,\n \"sensorOpticalStack.effectiveAntiAliasingSpatialResponse\"\n );\n\n const microlens =\n profile.microlens === undefined\n ? undefined\n : parseMicrolens(\n profile.microlens,\n \"sensorOpticalStack.microlens\"\n );\n\n if (\n orderedComponents === undefined &&\n effectiveAntiAliasingSpatialResponse ===\n undefined &&\n microlens === undefined\n ) {\n throw new InvalidConfigurationError(\n \"sensorOpticalStack must assert at least one optical-stack fact.\"\n );\n }\n\n return {\n schemaVersion: \"0.1.0\",\n profileId: requireNonEmptyString(\n profile.profileId,\n \"sensorOpticalStack.profileId\"\n ),\n evidence: parseEvidenceList(\n profile.evidence,\n \"sensorOpticalStack.evidence\"\n ),\n ...(orderedComponents === undefined\n ? {}\n : { orderedComponents }),\n ...(effectiveAntiAliasingSpatialResponse ===\n undefined\n ? {}\n : {\n effectiveAntiAliasingSpatialResponse\n }),\n ...(microlens === undefined\n ? {}\n : { microlens })\n };\n}\n\n/**\n * Resolves only the anti-aliasing (AA) spatial kernel.\n *\n * This is not the PSF (point-spread function) of the whole optical stack. Cover\n * glass and filter transmission, refraction, microlens behaviour, dependence on\n * field position, wavelength or polarization, and total throughput are excluded.\n *\n * A documented absent AA response gives a single component with weight 1 at zero\n * offset (no blur). An unknown response (field omitted) or one that is present\n * but unspecified is rejected.\n */\nexport function resolveAntiAliasingSpatialKernel(\n profileInput: SensorOpticalStackProfile\n): ResolvedAntiAliasingSpatialKernel {\n const profile =\n parseSensorOpticalStackProfile(\n profileInput\n );\n const response =\n profile.effectiveAntiAliasingSpatialResponse;\n\n if (response === undefined) {\n throw new InvalidScientificInputError(\n \"Effective anti-aliasing spatial response is unknown/unasserted for this optical-stack profile.\"\n );\n }\n\n if (response.kind === \"present-unresolved\") {\n throw new InvalidScientificInputError(\n \"Effective anti-aliasing spatial response is present but unresolved; a spatial kernel cannot be produced.\"\n );\n }\n\n if (response.kind === \"absent\") {\n return {\n profileId: profile.profileId,\n effectiveResponse: \"absent\",\n coordinateSystem:\n \"native-sensor-physical\",\n components: [\n {\n offsetMicrometers: {\n x: 0,\n y: 0\n },\n normalizedWeight: 1\n }\n ],\n normalizedWeightSum: 1,\n throughputIncluded: false,\n spectralTransmissionIncluded: false,\n fieldDependenceIncluded: false,\n wavelengthDependenceIncluded: false,\n polarizationDependenceIncluded: false,\n microlensResponseIncluded: false,\n coverFilterStackEffectsIncluded: false,\n wholeSensorOpticalStackResponse: false,\n provenance: {\n profile: profile.evidence,\n antiAliasingResponse:\n response.evidence\n }\n };\n }\n\n const normalizedWeightSum =\n response.components.reduce(\n (sum, component) =>\n sum + component.normalizedWeight,\n 0\n );\n\n return {\n profileId: profile.profileId,\n effectiveResponse:\n \"normalized-point-splitting-kernel\",\n coordinateSystem:\n \"native-sensor-physical\",\n components: response.components.map(\n (component) => ({\n offsetMicrometers: {\n ...component.offsetMicrometers\n },\n normalizedWeight:\n component.normalizedWeight\n })\n ),\n normalizedWeightSum,\n throughputIncluded: false,\n spectralTransmissionIncluded: false,\n fieldDependenceIncluded: false,\n wavelengthDependenceIncluded: false,\n polarizationDependenceIncluded: false,\n microlensResponseIncluded: false,\n coverFilterStackEffectsIncluded: false,\n wholeSensorOpticalStackResponse: false,\n provenance: {\n profile: profile.evidence,\n antiAliasingResponse:\n response.evidence\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"optical-stack.js","sourceRoot":"","sources":["../../src/sensor/optical-stack.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Sensor optical stack: the layers in front of the photodiodes (such as cover glass, infrared- and\n * ultraviolet-cut filters, a birefringent low-pass filter and microlenses), described as metadata,\n * plus an optional declared anti-aliasing (AA) blur kernel.\n *\n * Whether a component is physically present is recorded separately from its net AA effect. That lets\n * the schema describe designs that cancel the AA effect without claiming the hardware is missing.\n * Component presence alone creates no optical effect. Thickness, refractive index, spectral\n * transmission, angle of acceptance, focus shift and microlens collection need separate models.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport { requireConfigRecord as requireRecord, requireConfigString as requireNonEmptyString, requireConfigFiniteNumber as requireFiniteNumber } from \"../core/record-validation.js\";\n\n\nexport type SensorOpticalStackComponentRole =\n | \"cover-glass\"\n | \"infrared-cut\"\n | \"ultraviolet-cut\"\n | \"anti-reflection\"\n | \"birefringent-low-pass\"\n | \"wave-plate\"\n | \"other-optical-filter\";\n\nexport interface SensorOpticalStackComponent {\n componentId: string;\n /**\n * A component can have several roles, because one physical element can do\n * more than one optical or filtering job.\n */\n roles: readonly SensorOpticalStackComponentRole[];\n evidence: readonly EvidenceProvenance[];\n}\n\nexport interface SensorMicrolensDeclaration {\n presence: \"present\" | \"absent\";\n evidence: readonly EvidenceProvenance[];\n /**\n * Being present does not establish any model of angle, spectrum, fill factor\n * or collection efficiency.\n */\n opticalEffectModel: \"unresolved\";\n}\n\nexport interface AntiAliasingPointSplitComponent {\n /**\n * Physical offset on the native sensor from where the light would otherwise\n * land. +X right, +Y down. Units: micrometres.\n */\n offsetMicrometers: {\n x: number;\n y: number;\n };\n /**\n * Normalized weight (dimensionless). A point-splitting kernel only describes\n * where the light goes; the stack's total throughput is not part of it.\n */\n normalizedWeight: number;\n}\n\nexport type SensorEffectiveAntiAliasingSpatialResponse =\n | {\n /**\n * Documented absence (or cancellation) of deliberate AA splitting. It does\n * not mean the rest of the sensor stack has no optical effect.\n */\n kind: \"absent\";\n evidence: readonly EvidenceProvenance[];\n }\n | {\n /**\n * An AA effect is known to exist, but its spatial response is not\n * specified well enough to use.\n */\n kind: \"present-unresolved\";\n evidence: readonly EvidenceProvenance[];\n }\n | {\n /**\n * Generic approximation: each point is split into weighted copies at\n * offsets in native sensor physical coordinates.\n */\n kind: \"normalized-point-splitting-kernel\";\n evidence: readonly EvidenceProvenance[];\n coordinateSystem: \"native-sensor-physical\";\n scope:\n \"field-wavelength-polarization-invariant-approximation\";\n components: readonly AntiAliasingPointSplitComponent[];\n };\n\nexport interface SensorOpticalStackProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n evidence: readonly EvidenceProvenance[];\n /**\n * In order from the side light enters towards the sensor.\n *\n * These components are descriptive metadata only. Their presence does not\n * create transmission, focus-shift, aberration or spectral effects.\n */\n orderedComponents?: readonly SensorOpticalStackComponent[];\n /**\n * Omitted means \"unknown, not stated\".\n *\n * This is separate from which components are present, so a stack can\n * contain low-pass hardware while its net AA effect is absent or cancelled.\n */\n effectiveAntiAliasingSpatialResponse?: SensorEffectiveAntiAliasingSpatialResponse;\n /**\n * Omitted means \"unknown, not stated\".\n */\n microlens?: SensorMicrolensDeclaration;\n}\n\nexport interface ResolvedAntiAliasingSpatialKernel {\n profileId: string;\n effectiveResponse:\n | \"absent\"\n | \"normalized-point-splitting-kernel\";\n coordinateSystem: \"native-sensor-physical\";\n components: readonly AntiAliasingPointSplitComponent[];\n normalizedWeightSum: number;\n throughputIncluded: false;\n spectralTransmissionIncluded: false;\n fieldDependenceIncluded: false;\n wavelengthDependenceIncluded: false;\n polarizationDependenceIncluded: false;\n microlensResponseIncluded: false;\n coverFilterStackEffectsIncluded: false;\n wholeSensorOpticalStackResponse: false;\n provenance: {\n profile: readonly EvidenceProvenance[];\n antiAliasingResponse: readonly EvidenceProvenance[];\n };\n}\n\nconst COMPONENT_ROLES = new Set<SensorOpticalStackComponentRole>([\n \"cover-glass\",\n \"infrared-cut\",\n \"ultraviolet-cut\",\n \"anti-reflection\",\n \"birefringent-low-pass\",\n \"wave-plate\",\n \"other-optical-filter\"\n]);\n\nfunction parseComponentRoles(\n value: unknown,\n path: string\n): readonly SensorOpticalStackComponentRole[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty array.\"\n );\n }\n\n const roles = value.map((entry, index) => {\n if (\n typeof entry !== \"string\" ||\n !COMPONENT_ROLES.has(\n entry as SensorOpticalStackComponentRole\n )\n ) {\n throw new InvalidConfigurationError(\n path + \"[\" + index + \"] is invalid.\"\n );\n }\n return entry as SensorOpticalStackComponentRole;\n });\n\n if (new Set(roles).size !== roles.length) {\n throw new InvalidConfigurationError(\n path + \" must not contain duplicate roles.\"\n );\n }\n\n return roles;\n}\n\nfunction parseOrderedComponents(\n value: unknown,\n path: string\n): readonly SensorOpticalStackComponent[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty array.\"\n );\n }\n\n const components = value.map((entry, index) => {\n const record = requireRecord(\n entry,\n path + \"[\" + index + \"]\", [\"componentId\", \"roles\", \"evidence\"]\n );\n\n return {\n componentId: requireNonEmptyString(\n record.componentId,\n path + \"[\" + index + \"].componentId\"\n ),\n roles: parseComponentRoles(\n record.roles,\n path + \"[\" + index + \"].roles\"\n ),\n evidence: parseEvidenceList(\n record.evidence,\n path + \"[\" + index + \"].evidence\"\n )\n };\n });\n\n const ids = components.map(\n (component) => component.componentId\n );\n if (new Set(ids).size !== ids.length) {\n throw new InvalidConfigurationError(\n path + \" must not contain duplicate componentId values.\"\n );\n }\n\n return components;\n}\n\nfunction parsePointSplitComponents(\n value: unknown,\n path: string\n): readonly AntiAliasingPointSplitComponent[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty array.\"\n );\n }\n\n const components = value.map((entry, index) => {\n const record = requireRecord(\n entry,\n path + \"[\" + index + \"]\", [\"offsetMicrometers\", \"normalizedWeight\"]\n );\n const offset = requireRecord(\n record.offsetMicrometers,\n path + \"[\" + index + \"].offsetMicrometers\", [\"x\", \"y\"]\n );\n const normalizedWeight = requireFiniteNumber(\n record.normalizedWeight,\n path + \"[\" + index + \"].normalizedWeight\"\n );\n\n if (normalizedWeight <= 0) {\n throw new InvalidConfigurationError(\n path +\n \"[\" +\n index +\n \"].normalizedWeight must be greater than zero.\"\n );\n }\n\n return {\n offsetMicrometers: {\n x: requireFiniteNumber(\n offset.x,\n path +\n \"[\" +\n index +\n \"].offsetMicrometers.x\"\n ),\n y: requireFiniteNumber(\n offset.y,\n path +\n \"[\" +\n index +\n \"].offsetMicrometers.y\"\n )\n },\n normalizedWeight\n };\n });\n\n const weightSum = components.reduce(\n (sum, component) =>\n sum + component.normalizedWeight,\n 0\n );\n\n if (\n !Number.isFinite(weightSum) ||\n Math.abs(weightSum - 1) > 1e-12\n ) {\n throw new InvalidConfigurationError(\n path +\n \" normalizedWeight values must sum to 1 within 1e-12.\"\n );\n }\n\n return components;\n}\n\nfunction parseAntiAliasingResponse(\n value: unknown,\n path: string\n): SensorEffectiveAntiAliasingSpatialResponse {\n const record = requireRecord(value, path, [\"kind\", \"coordinateSystem\", \"scope\", \"components\", \"evidence\"]);\n\n if (\n record.kind === \"absent\" ||\n record.kind === \"present-unresolved\"\n ) {\n if (\n record.coordinateSystem !== undefined ||\n record.scope !== undefined ||\n record.components !== undefined\n ) {\n throw new InvalidConfigurationError(\n path +\n \" absent/present-unresolved responses must omit kernel fields.\"\n );\n }\n return {\n kind: record.kind,\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n }\n\n if (\n record.kind ===\n \"normalized-point-splitting-kernel\"\n ) {\n if (\n record.coordinateSystem !==\n \"native-sensor-physical\"\n ) {\n throw new InvalidConfigurationError(\n path +\n '.coordinateSystem must be \"native-sensor-physical\".'\n );\n }\n if (\n record.scope !==\n \"field-wavelength-polarization-invariant-approximation\"\n ) {\n throw new InvalidConfigurationError(\n path + \".scope is invalid.\"\n );\n }\n\n return {\n kind:\n \"normalized-point-splitting-kernel\",\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n coordinateSystem:\n \"native-sensor-physical\",\n scope:\n \"field-wavelength-polarization-invariant-approximation\",\n components: parsePointSplitComponents(\n record.components,\n path + \".components\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseMicrolens(\n value: unknown,\n path: string\n): SensorMicrolensDeclaration {\n const record = requireRecord(value, path, [\"presence\", \"opticalEffectModel\", \"evidence\"]);\n\n if (\n record.presence !== \"present\" &&\n record.presence !== \"absent\"\n ) {\n throw new InvalidConfigurationError(\n path + \".presence is invalid.\"\n );\n }\n\n if (record.opticalEffectModel !== \"unresolved\") {\n throw new InvalidConfigurationError(\n path +\n '.opticalEffectModel must be \"unresolved\" in schema 0.1.0.'\n );\n }\n\n return {\n presence: record.presence,\n evidence: parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n opticalEffectModel: \"unresolved\"\n };\n}\n\n/**\n * Parses descriptive sensor optical-stack metadata, plus an optional explicitly\n * declared anti-aliasing (AA) spatial response.\n *\n * Leave out unknown facts rather than guessing them. Physical presence of a\n * component is separate from the net AA response, so the schema can describe\n * designs that cancel the AA effect without claiming the hardware is missing.\n *\n * In schema 0.1.0, cover glass, filters and microlenses create no optical\n * effect. Thickness, refractive index, spectral transmission, angle of\n * acceptance, focus shift and microlens collection need later explicit models\n * or calibration.\n */\nexport function parseSensorOpticalStackProfile(\n value: unknown\n): SensorOpticalStackProfile {\n const profile = requireRecord(\n value,\n \"sensorOpticalStack\", [\"schemaVersion\", \"orderedComponents\", \"effectiveAntiAliasingSpatialResponse\", \"microlens\", \"profileId\", \"evidence\"]\n );\n\n if (profile.schemaVersion !== \"0.1.0\") {\n throw new InvalidConfigurationError(\n 'sensorOpticalStack.schemaVersion must be \"0.1.0\".'\n );\n }\n\n const orderedComponents =\n profile.orderedComponents === undefined\n ? undefined\n : parseOrderedComponents(\n profile.orderedComponents,\n \"sensorOpticalStack.orderedComponents\"\n );\n\n const effectiveAntiAliasingSpatialResponse =\n profile.effectiveAntiAliasingSpatialResponse ===\n undefined\n ? undefined\n : parseAntiAliasingResponse(\n profile.effectiveAntiAliasingSpatialResponse,\n \"sensorOpticalStack.effectiveAntiAliasingSpatialResponse\"\n );\n\n const microlens =\n profile.microlens === undefined\n ? undefined\n : parseMicrolens(\n profile.microlens,\n \"sensorOpticalStack.microlens\"\n );\n\n if (\n orderedComponents === undefined &&\n effectiveAntiAliasingSpatialResponse ===\n undefined &&\n microlens === undefined\n ) {\n throw new InvalidConfigurationError(\n \"sensorOpticalStack must assert at least one optical-stack fact.\"\n );\n }\n\n return {\n schemaVersion: \"0.1.0\",\n profileId: requireNonEmptyString(\n profile.profileId,\n \"sensorOpticalStack.profileId\"\n ),\n evidence: parseEvidenceList(\n profile.evidence,\n \"sensorOpticalStack.evidence\"\n ),\n ...(orderedComponents === undefined\n ? {}\n : { orderedComponents }),\n ...(effectiveAntiAliasingSpatialResponse ===\n undefined\n ? {}\n : {\n effectiveAntiAliasingSpatialResponse\n }),\n ...(microlens === undefined\n ? {}\n : { microlens })\n };\n}\n\n/**\n * Resolves only the anti-aliasing (AA) spatial kernel.\n *\n * This is not the PSF (point-spread function) of the whole optical stack. Cover\n * glass and filter transmission, refraction, microlens behaviour, dependence on\n * field position, wavelength or polarization, and total throughput are excluded.\n *\n * A documented absent AA response gives a single component with weight 1 at zero\n * offset (no blur). An unknown response (field omitted) or one that is present\n * but unspecified is rejected.\n */\nexport function resolveAntiAliasingSpatialKernel(\n profileInput: SensorOpticalStackProfile\n): ResolvedAntiAliasingSpatialKernel {\n const profile =\n parseSensorOpticalStackProfile(\n profileInput\n );\n const response =\n profile.effectiveAntiAliasingSpatialResponse;\n\n if (response === undefined) {\n throw new InvalidScientificInputError(\n \"Effective anti-aliasing spatial response is unknown/unasserted for this optical-stack profile.\"\n );\n }\n\n if (response.kind === \"present-unresolved\") {\n throw new InvalidScientificInputError(\n \"Effective anti-aliasing spatial response is present but unresolved; a spatial kernel cannot be produced.\"\n );\n }\n\n if (response.kind === \"absent\") {\n return {\n profileId: profile.profileId,\n effectiveResponse: \"absent\",\n coordinateSystem:\n \"native-sensor-physical\",\n components: [\n {\n offsetMicrometers: {\n x: 0,\n y: 0\n },\n normalizedWeight: 1\n }\n ],\n normalizedWeightSum: 1,\n throughputIncluded: false,\n spectralTransmissionIncluded: false,\n fieldDependenceIncluded: false,\n wavelengthDependenceIncluded: false,\n polarizationDependenceIncluded: false,\n microlensResponseIncluded: false,\n coverFilterStackEffectsIncluded: false,\n wholeSensorOpticalStackResponse: false,\n provenance: {\n profile: profile.evidence,\n antiAliasingResponse:\n response.evidence\n }\n };\n }\n\n const normalizedWeightSum =\n response.components.reduce(\n (sum, component) =>\n sum + component.normalizedWeight,\n 0\n );\n\n return {\n profileId: profile.profileId,\n effectiveResponse:\n \"normalized-point-splitting-kernel\",\n coordinateSystem:\n \"native-sensor-physical\",\n components: response.components.map(\n (component) => ({\n offsetMicrometers: {\n ...component.offsetMicrometers\n },\n normalizedWeight:\n component.normalizedWeight\n })\n ),\n normalizedWeightSum,\n throughputIncluded: false,\n spectralTransmissionIncluded: false,\n fieldDependenceIncluded: false,\n wavelengthDependenceIncluded: false,\n polarizationDependenceIncluded: false,\n microlensResponseIncluded: false,\n coverFilterStackEffectsIncluded: false,\n wholeSensorOpticalStackResponse: false,\n provenance: {\n profile: profile.evidence,\n antiAliasingResponse:\n response.evidence\n }\n };\n}\n"]}
|
|
@@ -14,35 +14,10 @@ import { calculatedResult } from "../core/calculation-result.js";
|
|
|
14
14
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
15
15
|
import { parseEvidenceList } from "../core/evidence-provenance.js";
|
|
16
16
|
import { InvalidScientificInputError } from "../core/validation.js";
|
|
17
|
-
import { requireInputKeys,
|
|
17
|
+
import { requireInputKeys, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireConfigFinite as requireFinite, requireConfigFiniteAboveZero as requirePositiveFinite } from "../core/record-validation.js";
|
|
18
18
|
const PLANCK_CONSTANT_JOULE_SECONDS = 6.62607015e-34;
|
|
19
19
|
const SPEED_OF_LIGHT_METERS_PER_SECOND = 299_792_458;
|
|
20
20
|
const NANOMETERS_TO_METERS = 1e-9;
|
|
21
|
-
function requireRecord(value, path, allowedKeys) {
|
|
22
|
-
if (typeof value !== "object" ||
|
|
23
|
-
value === null ||
|
|
24
|
-
Array.isArray(value)) {
|
|
25
|
-
throw new InvalidConfigurationError(path + " must be an object.");
|
|
26
|
-
}
|
|
27
|
-
if (allowedKeys !== null)
|
|
28
|
-
rejectUnknownFields(value, allowedKeys, path);
|
|
29
|
-
return value;
|
|
30
|
-
}
|
|
31
|
-
function requireFinite(value, path) {
|
|
32
|
-
if (typeof value !== "number" ||
|
|
33
|
-
!Number.isFinite(value)) {
|
|
34
|
-
throw new InvalidConfigurationError(path + " must be finite.");
|
|
35
|
-
}
|
|
36
|
-
return value;
|
|
37
|
-
}
|
|
38
|
-
function requirePositiveFinite(value, path) {
|
|
39
|
-
const parsed = requireFinite(value, path);
|
|
40
|
-
if (parsed <= 0) {
|
|
41
|
-
throw new InvalidConfigurationError(path +
|
|
42
|
-
" must be greater than zero.");
|
|
43
|
-
}
|
|
44
|
-
return parsed;
|
|
45
|
-
}
|
|
46
21
|
function requireFraction(value, path) {
|
|
47
22
|
const parsed = requireFinite(value, path);
|
|
48
23
|
if (parsed < 0 || parsed > 1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"photon-energy.js","sourceRoot":"","sources":["../../src/sensor/photon-energy.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Photon energy and optical frequency from wavelength, using the exact SI values of the Planck\n * constant h and the speed of light c (E = h·c / λ_vacuum).\n *\n * The formula needs the vacuum wavelength. An air wavelength is converted with\n * λ_vacuum = n·λ_air, which requires a sourced phase refractive index n of air at that exact\n * wavelength, for matching atmospheric conditions. The refractive index's uncertainty is kept, but\n * it is not automatically carried through to the photon energy.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n calculatedResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport type {\n SensorSpectralResponseScientificStatus,\n SensorSpectralResponseUncertainty,\n SpectralWavelengthBasis\n} from \"./spectral-response.js\";\nimport { requireInputKeys, rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nconst PLANCK_CONSTANT_JOULE_SECONDS =\n 6.62607015e-34;\nconst SPEED_OF_LIGHT_METERS_PER_SECOND =\n 299_792_458;\nconst NANOMETERS_TO_METERS = 1e-9;\n\nexport interface AirRefractiveIndexReferenceConditions {\n temperatureC: number;\n pressurePascal: number;\n relativeHumidityFraction?: number;\n carbonDioxideMoleFraction?: number;\n}\n\nexport interface SourcedAirPhaseRefractiveIndex {\n wavelengthNanometers: number;\n wavelengthBasis: \"air\";\n definition:\n \"vacuum-wavelength-divided-by-air-wavelength\";\n phaseRefractiveIndex: number;\n scientificStatus:\n SensorSpectralResponseScientificStatus;\n uncertainty:\n SensorSpectralResponseUncertainty;\n evidence: readonly EvidenceProvenance[];\n referenceConditions?:\n AirRefractiveIndexReferenceConditions;\n}\n\nexport type AirRefractiveIndexConditionPolicy =\n | {\n kind: \"exact-match-required\";\n }\n | {\n kind: \"assume-compatible\";\n limitation: string;\n evidence: readonly EvidenceProvenance[];\n };\n\nexport interface CalculatePhotonEnergyFromWavelengthInput {\n wavelengthNanometers: number;\n wavelengthBasis:\n SpectralWavelengthBasis;\n airPhaseRefractiveIndex?:\n SourcedAirPhaseRefractiveIndex;\n airOperatingConditions?:\n AirRefractiveIndexReferenceConditions;\n airConditionPolicy?:\n AirRefractiveIndexConditionPolicy;\n}\n\nexport interface PhotonEnergyFromWavelength {\n inputWavelengthNanometers: number;\n inputWavelengthBasis:\n Exclude<SpectralWavelengthBasis, \"unspecified\">;\n vacuumWavelengthNanometers: number;\n frequencyHertz: number;\n photonEnergyJoules: number;\n wavelengthConversion:\n | \"vacuum-identity\"\n | \"air-to-vacuum-via-phase-refractive-index\";\n exactSiConstants: {\n planckConstantJouleSeconds:\n 6.62607015e-34;\n speedOfLightMetersPerSecond:\n 299792458;\n };\n phaseRefractiveIndexUsed?: number;\n airRefractiveIndexScientificStatus?:\n SensorSpectralResponseScientificStatus;\n airRefractiveIndexUncertainty?:\n SensorSpectralResponseUncertainty;\n airRefractiveIndexReferenceConditions?:\n AirRefractiveIndexReferenceConditions;\n airRefractiveIndexEvidence?:\n readonly EvidenceProvenance[];\n airOperatingConditions?:\n AirRefractiveIndexReferenceConditions;\n airConditionPolicy?:\n AirRefractiveIndexConditionPolicy;\n airConditionCompatibility?:\n | \"exact-match\"\n | \"assumed-compatible\";\n airConditionAssumptionEvidence?:\n readonly EvidenceProvenance[];\n inputUncertaintyPropagated: false;\n}\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireFinite(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be finite.\"\n );\n }\n return value;\n}\n\nfunction requirePositiveFinite(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (parsed <= 0) {\n throw new InvalidConfigurationError(\n path +\n \" must be greater than zero.\"\n );\n }\n return parsed;\n}\n\nfunction requireFraction(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (parsed < 0 || parsed > 1) {\n throw new InvalidConfigurationError(\n path +\n \" must be a fraction from 0 through 1.\"\n );\n }\n return parsed;\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): SensorSpectralResponseUncertainty {\n const record =\n requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", UNCERTAINTY_VARIANT_FIELDS, path);\n\n if (record.kind === \"relative\") {\n const fraction =\n requireFinite(\n record.fraction,\n path + \".fraction\"\n );\n if (fraction < 0) {\n throw new InvalidConfigurationError(\n path +\n \".fraction must be greater than or equal to zero.\"\n );\n }\n if (\n typeof record.basis !== \"string\" ||\n record.basis.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \".basis must be a non-empty string.\"\n );\n }\n return {\n kind: \"relative\",\n fraction,\n basis: record.basis\n };\n }\n\n if (\n record.kind === \"not-quantified\"\n ) {\n if (\n typeof record.limitation !==\n \"string\" ||\n record.limitation.trim().length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \".limitation must be a non-empty string.\"\n );\n }\n return {\n kind: \"not-quantified\",\n limitation:\n record.limitation\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseReferenceConditions(\n value: unknown,\n path: string\n): AirRefractiveIndexReferenceConditions {\n const record =\n requireRecord(value, path, [\"temperatureC\", \"pressurePascal\", \"relativeHumidityFraction\", \"carbonDioxideMoleFraction\"]);\n\n const temperatureC =\n requireFinite(\n record.temperatureC,\n path + \".temperatureC\"\n );\n const pressurePascal =\n requirePositiveFinite(\n record.pressurePascal,\n path + \".pressurePascal\"\n );\n\n const relativeHumidityFraction =\n record.relativeHumidityFraction ===\n undefined\n ? undefined\n : requireFraction(\n record.relativeHumidityFraction,\n path +\n \".relativeHumidityFraction\"\n );\n\n const carbonDioxideMoleFraction =\n record.carbonDioxideMoleFraction ===\n undefined\n ? undefined\n : requireFraction(\n record.carbonDioxideMoleFraction,\n path +\n \".carbonDioxideMoleFraction\"\n );\n\n return {\n temperatureC,\n pressurePascal,\n ...(relativeHumidityFraction ===\n undefined\n ? {}\n : {\n relativeHumidityFraction\n }),\n ...(carbonDioxideMoleFraction ===\n undefined\n ? {}\n : {\n carbonDioxideMoleFraction\n })\n };\n}\n\nfunction parseConditionPolicy(\n value: unknown\n): AirRefractiveIndexConditionPolicy {\n const record = requireRecord(\n value,\n \"airConditionPolicy\", null\n );\n rejectUnknownVariantFields(record, \"kind\", { \"exact-match-required\": [\"kind\"], \"assume-compatible\": [\"kind\", \"limitation\", \"evidence\"] }, \"airConditionPolicy\");\n\n if (\n record.kind === \"exact-match-required\"\n ) {\n return {\n kind: \"exact-match-required\"\n };\n }\n\n if (\n record.kind === \"assume-compatible\"\n ) {\n if (\n typeof record.limitation !==\n \"string\" ||\n record.limitation.trim().length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n \"airConditionPolicy.limitation must be a non-empty string.\"\n );\n }\n return {\n kind: \"assume-compatible\",\n limitation:\n record.limitation,\n evidence: parseEvidenceList(\n record.evidence,\n \"airConditionPolicy.evidence\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n \"airConditionPolicy.kind is invalid.\"\n );\n}\n\nfunction conditionsMatch(\n reference:\n AirRefractiveIndexReferenceConditions,\n operating:\n AirRefractiveIndexReferenceConditions\n): boolean {\n if (\n reference.temperatureC !==\n operating.temperatureC ||\n reference.pressurePascal !==\n operating.pressurePascal\n ) {\n return false;\n }\n if (\n reference.relativeHumidityFraction !==\n undefined &&\n reference.relativeHumidityFraction !==\n operating.relativeHumidityFraction\n ) {\n return false;\n }\n if (\n reference.carbonDioxideMoleFraction !==\n undefined &&\n reference.carbonDioxideMoleFraction !==\n operating.carbonDioxideMoleFraction\n ) {\n return false;\n }\n return true;\n}\n\n/**\n * Validates untrusted input and returns it as a normalized, typed value. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * The index is the phase refractive index n of air at one exact wavelength, from a cited source, for\n * stated atmospheric conditions. It converts air to vacuum wavelength: λ_vacuum = n·λ_air.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseSourcedAirPhaseRefractiveIndex(\n value: unknown\n): SourcedAirPhaseRefractiveIndex {\n const record = requireRecord(\n value,\n \"airPhaseRefractiveIndex\", [\"wavelengthBasis\", \"definition\", \"scientificStatus\", \"uncertainty\", \"referenceConditions\", \"wavelengthNanometers\", \"phaseRefractiveIndex\", \"evidence\"]\n );\n\n if (\n record.wavelengthBasis !== \"air\"\n ) {\n throw new InvalidConfigurationError(\n 'airPhaseRefractiveIndex.wavelengthBasis must be \"air\".'\n );\n }\n if (\n record.definition !==\n \"vacuum-wavelength-divided-by-air-wavelength\"\n ) {\n throw new InvalidConfigurationError(\n \"airPhaseRefractiveIndex.definition is invalid.\"\n );\n }\n if (\n record.scientificStatus !==\n \"calibrated\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"airPhaseRefractiveIndex.scientificStatus is invalid.\"\n );\n }\n\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"airPhaseRefractiveIndex.uncertainty\"\n );\n const referenceConditions =\n record.referenceConditions ===\n undefined\n ? undefined\n : parseReferenceConditions(\n record.referenceConditions,\n \"airPhaseRefractiveIndex.referenceConditions\"\n );\n\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated air phase refractive index must declare quantified relative uncertainty.\"\n );\n }\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n referenceConditions === undefined\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated air phase refractive index must declare temperature and pressure reference conditions.\"\n );\n }\n\n return {\n wavelengthNanometers:\n requirePositiveFinite(\n record.wavelengthNanometers,\n \"airPhaseRefractiveIndex.wavelengthNanometers\"\n ),\n wavelengthBasis: \"air\",\n definition:\n \"vacuum-wavelength-divided-by-air-wavelength\",\n phaseRefractiveIndex:\n requirePositiveFinite(\n record.phaseRefractiveIndex,\n \"airPhaseRefractiveIndex.phaseRefractiveIndex\"\n ),\n scientificStatus:\n record.scientificStatus,\n uncertainty,\n evidence: parseEvidenceList(\n record.evidence,\n \"airPhaseRefractiveIndex.evidence\"\n ),\n ...(referenceConditions ===\n undefined\n ? {}\n : { referenceConditions })\n };\n}\n\n/**\n * Converts a vacuum wavelength, or an air wavelength with its stated atmosphere, into optical\n * frequency and photon energy using the exact SI constants h and c.\n *\n * An air wavelength needs a sourced phase refractive index for that exact wavelength and matching\n * atmosphere; λ_vacuum = n·λ_air. The index's uncertainty is kept but not automatically carried\n * through to the photon energy.\n * @param input - The input; see `CalculatePhotonEnergyFromWavelengthInput` for its fields, units and coordinates.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function calculatePhotonEnergyFromWavelength(\n input:\n CalculatePhotonEnergyFromWavelengthInput\n): CalculationResult<PhotonEnergyFromWavelength> {\n requireInputKeys(input, \"calculatePhotonEnergyFromWavelength\", [\"wavelengthNanometers\", \"wavelengthBasis\", \"airPhaseRefractiveIndex\", \"airOperatingConditions\", \"airConditionPolicy\"]);\n const wavelengthNanometers = input.wavelengthNanometers;\n // A calculation input, not a configuration record, so a bad value is a scientific-input error.\n if (typeof wavelengthNanometers !== \"number\" || !Number.isFinite(wavelengthNanometers)) {\n throw new InvalidScientificInputError(\"wavelengthNanometers must be finite.\");\n }\n if (wavelengthNanometers <= 0) {\n throw new InvalidScientificInputError(\"wavelengthNanometers must be greater than zero.\");\n }\n\n if (\n input.wavelengthBasis ===\n \"unspecified\"\n ) {\n throw new InvalidScientificInputError(\n \"wavelengthBasis must be resolved to air or vacuum before photon-energy calculation.\"\n );\n }\n\n if (\n input.wavelengthBasis !== \"air\" &&\n input.wavelengthBasis !== \"vacuum\"\n ) {\n throw new InvalidConfigurationError(\n \"wavelengthBasis is invalid.\"\n );\n }\n\n let vacuumWavelengthNanometers:\n number;\n let wavelengthConversion:\n PhotonEnergyFromWavelength[\"wavelengthConversion\"];\n let parsedAir:\n SourcedAirPhaseRefractiveIndex |\n undefined;\n\n let parsedConditionPolicy:\n AirRefractiveIndexConditionPolicy |\n undefined;\n let parsedOperatingConditions:\n AirRefractiveIndexReferenceConditions |\n undefined;\n let airConditionCompatibility:\n PhotonEnergyFromWavelength[\"airConditionCompatibility\"] |\n undefined;\n\n if (\n input.wavelengthBasis ===\n \"vacuum\"\n ) {\n if (\n input.airPhaseRefractiveIndex !==\n undefined ||\n input.airOperatingConditions !==\n undefined ||\n input.airConditionPolicy !==\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"Air refractive-index inputs must be omitted for vacuum-basis wavelengths.\"\n );\n }\n vacuumWavelengthNanometers =\n wavelengthNanometers;\n wavelengthConversion =\n \"vacuum-identity\";\n } else {\n if (\n input.airPhaseRefractiveIndex ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"airPhaseRefractiveIndex is required for air-basis photon-energy calculation.\"\n );\n }\n parsedAir =\n parseSourcedAirPhaseRefractiveIndex(\n input.airPhaseRefractiveIndex\n );\n\n if (\n parsedAir.wavelengthNanometers !==\n wavelengthNanometers\n ) {\n throw new InvalidScientificInputError(\n \"airPhaseRefractiveIndex wavelength must exactly match wavelengthNanometers.\"\n );\n }\n\n if (\n input.airConditionPolicy ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"airConditionPolicy is required for air-basis photon-energy calculation.\"\n );\n }\n parsedConditionPolicy =\n parseConditionPolicy(\n input.airConditionPolicy\n );\n\n if (\n parsedConditionPolicy.kind ===\n \"exact-match-required\"\n ) {\n if (\n parsedAir.referenceConditions ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"Exact air-condition matching requires refractive-index reference conditions.\"\n );\n }\n if (\n input.airOperatingConditions ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"airOperatingConditions is required when exact air-condition matching is selected.\"\n );\n }\n parsedOperatingConditions =\n parseReferenceConditions(\n input.airOperatingConditions,\n \"airOperatingConditions\"\n );\n if (\n !conditionsMatch(\n parsedAir.referenceConditions,\n parsedOperatingConditions\n )\n ) {\n throw new InvalidScientificInputError(\n \"airOperatingConditions must match the refractive-index reference conditions.\"\n );\n }\n airConditionCompatibility =\n \"exact-match\";\n } else {\n parsedOperatingConditions =\n input.airOperatingConditions ===\n undefined\n ? undefined\n : parseReferenceConditions(\n input.airOperatingConditions,\n \"airOperatingConditions\"\n );\n airConditionCompatibility =\n \"assumed-compatible\";\n }\n\n vacuumWavelengthNanometers =\n wavelengthNanometers *\n parsedAir.phaseRefractiveIndex;\n wavelengthConversion =\n \"air-to-vacuum-via-phase-refractive-index\";\n }\n\n const vacuumWavelengthMeters =\n vacuumWavelengthNanometers *\n NANOMETERS_TO_METERS;\n const frequencyHertz =\n SPEED_OF_LIGHT_METERS_PER_SECOND /\n vacuumWavelengthMeters;\n const photonEnergyJoules =\n PLANCK_CONSTANT_JOULE_SECONDS *\n frequencyHertz;\n\n if (\n !Number.isFinite(\n vacuumWavelengthNanometers\n ) ||\n !Number.isFinite(frequencyHertz) ||\n !Number.isFinite(\n photonEnergyJoules\n )\n ) {\n throw new InvalidScientificInputError(\n \"Photon-energy calculation must remain finite.\"\n );\n }\n\n return calculatedResult(\n {\n inputWavelengthNanometers:\n wavelengthNanometers,\n inputWavelengthBasis:\n input.wavelengthBasis,\n vacuumWavelengthNanometers,\n frequencyHertz,\n photonEnergyJoules,\n wavelengthConversion,\n exactSiConstants: {\n planckConstantJouleSeconds:\n PLANCK_CONSTANT_JOULE_SECONDS,\n speedOfLightMetersPerSecond:\n SPEED_OF_LIGHT_METERS_PER_SECOND\n },\n ...(parsedAir === undefined\n ? {}\n : {\n phaseRefractiveIndexUsed:\n parsedAir\n .phaseRefractiveIndex,\n airRefractiveIndexScientificStatus:\n parsedAir\n .scientificStatus,\n airRefractiveIndexUncertainty:\n parsedAir.uncertainty,\n ...(parsedAir\n .referenceConditions ===\n undefined\n ? {}\n : {\n airRefractiveIndexReferenceConditions:\n parsedAir\n .referenceConditions\n }),\n airRefractiveIndexEvidence:\n parsedAir.evidence,\n ...(parsedOperatingConditions ===\n undefined\n ? {}\n : {\n airOperatingConditions:\n parsedOperatingConditions\n }),\n ...(parsedConditionPolicy ===\n undefined\n ? {}\n : {\n airConditionPolicy:\n parsedConditionPolicy\n }),\n ...(airConditionCompatibility ===\n undefined\n ? {}\n : {\n airConditionCompatibility\n }),\n ...(parsedConditionPolicy?.kind ===\n \"assume-compatible\"\n ? {\n airConditionAssumptionEvidence:\n parsedConditionPolicy\n .evidence\n }\n : {})\n }),\n inputUncertaintyPropagated:\n false\n },\n \"photon-energy-from-spectral-wavelength\",\n \"1.0.0\",\n [\n \"Planck constant h and vacuum speed of light c use their exact SI defining values.\",\n \"Photon energy is h times optical frequency; frequency is derived from vacuum wavelength.\",\n \"Vacuum-basis wavelength requires no refractive-index correction.\",\n \"Air-basis wavelength is converted with the phase refractive index definition n = lambda_vacuum / lambda_air at the exact requested wavelength.\",\n \"Air refractive index varies with wavelength and atmospheric conditions; this function never substitutes n = 1.\",\n \"Air-basis conversion requires either exact matching to the refractive-index reference atmosphere or an explicit evidence-backed compatibility assumption.\",\n \"Input refractive-index uncertainty is preserved as metadata but is not propagated into photon-energy uncertainty by this foundation.\",\n \"This calculation does not apply QE, calculate photon rate, generate electrons, integrate exposure time, or model saturation/noise.\"\n ]\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"photon-energy.js","sourceRoot":"","sources":["../../src/sensor/photon-energy.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Photon energy and optical frequency from wavelength, using the exact SI values of the Planck\n * constant h and the speed of light c (E = h·c / λ_vacuum).\n *\n * The formula needs the vacuum wavelength. An air wavelength is converted with\n * λ_vacuum = n·λ_air, which requires a sourced phase refractive index n of air at that exact\n * wavelength, for matching atmospheric conditions. The refractive index's uncertainty is kept, but\n * it is not automatically carried through to the photon energy.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n calculatedResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport type {\n SensorSpectralResponseScientificStatus,\n SensorSpectralResponseUncertainty,\n SpectralWavelengthBasis\n} from \"./spectral-response.js\";\nimport { requireInputKeys, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireConfigFinite as requireFinite, requireConfigFiniteAboveZero as requirePositiveFinite } from \"../core/record-validation.js\";\n\nconst PLANCK_CONSTANT_JOULE_SECONDS =\n 6.62607015e-34;\nconst SPEED_OF_LIGHT_METERS_PER_SECOND =\n 299_792_458;\nconst NANOMETERS_TO_METERS = 1e-9;\n\nexport interface AirRefractiveIndexReferenceConditions {\n temperatureC: number;\n pressurePascal: number;\n relativeHumidityFraction?: number;\n carbonDioxideMoleFraction?: number;\n}\n\nexport interface SourcedAirPhaseRefractiveIndex {\n wavelengthNanometers: number;\n wavelengthBasis: \"air\";\n definition:\n \"vacuum-wavelength-divided-by-air-wavelength\";\n phaseRefractiveIndex: number;\n scientificStatus:\n SensorSpectralResponseScientificStatus;\n uncertainty:\n SensorSpectralResponseUncertainty;\n evidence: readonly EvidenceProvenance[];\n referenceConditions?:\n AirRefractiveIndexReferenceConditions;\n}\n\nexport type AirRefractiveIndexConditionPolicy =\n | {\n kind: \"exact-match-required\";\n }\n | {\n kind: \"assume-compatible\";\n limitation: string;\n evidence: readonly EvidenceProvenance[];\n };\n\nexport interface CalculatePhotonEnergyFromWavelengthInput {\n wavelengthNanometers: number;\n wavelengthBasis:\n SpectralWavelengthBasis;\n airPhaseRefractiveIndex?:\n SourcedAirPhaseRefractiveIndex;\n airOperatingConditions?:\n AirRefractiveIndexReferenceConditions;\n airConditionPolicy?:\n AirRefractiveIndexConditionPolicy;\n}\n\nexport interface PhotonEnergyFromWavelength {\n inputWavelengthNanometers: number;\n inputWavelengthBasis:\n Exclude<SpectralWavelengthBasis, \"unspecified\">;\n vacuumWavelengthNanometers: number;\n frequencyHertz: number;\n photonEnergyJoules: number;\n wavelengthConversion:\n | \"vacuum-identity\"\n | \"air-to-vacuum-via-phase-refractive-index\";\n exactSiConstants: {\n planckConstantJouleSeconds:\n 6.62607015e-34;\n speedOfLightMetersPerSecond:\n 299792458;\n };\n phaseRefractiveIndexUsed?: number;\n airRefractiveIndexScientificStatus?:\n SensorSpectralResponseScientificStatus;\n airRefractiveIndexUncertainty?:\n SensorSpectralResponseUncertainty;\n airRefractiveIndexReferenceConditions?:\n AirRefractiveIndexReferenceConditions;\n airRefractiveIndexEvidence?:\n readonly EvidenceProvenance[];\n airOperatingConditions?:\n AirRefractiveIndexReferenceConditions;\n airConditionPolicy?:\n AirRefractiveIndexConditionPolicy;\n airConditionCompatibility?:\n | \"exact-match\"\n | \"assumed-compatible\";\n airConditionAssumptionEvidence?:\n readonly EvidenceProvenance[];\n inputUncertaintyPropagated: false;\n}\n\nfunction requireFraction(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (parsed < 0 || parsed > 1) {\n throw new InvalidConfigurationError(\n path +\n \" must be a fraction from 0 through 1.\"\n );\n }\n return parsed;\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): SensorSpectralResponseUncertainty {\n const record =\n requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", UNCERTAINTY_VARIANT_FIELDS, path);\n\n if (record.kind === \"relative\") {\n const fraction =\n requireFinite(\n record.fraction,\n path + \".fraction\"\n );\n if (fraction < 0) {\n throw new InvalidConfigurationError(\n path +\n \".fraction must be greater than or equal to zero.\"\n );\n }\n if (\n typeof record.basis !== \"string\" ||\n record.basis.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \".basis must be a non-empty string.\"\n );\n }\n return {\n kind: \"relative\",\n fraction,\n basis: record.basis\n };\n }\n\n if (\n record.kind === \"not-quantified\"\n ) {\n if (\n typeof record.limitation !==\n \"string\" ||\n record.limitation.trim().length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \".limitation must be a non-empty string.\"\n );\n }\n return {\n kind: \"not-quantified\",\n limitation:\n record.limitation\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseReferenceConditions(\n value: unknown,\n path: string\n): AirRefractiveIndexReferenceConditions {\n const record =\n requireRecord(value, path, [\"temperatureC\", \"pressurePascal\", \"relativeHumidityFraction\", \"carbonDioxideMoleFraction\"]);\n\n const temperatureC =\n requireFinite(\n record.temperatureC,\n path + \".temperatureC\"\n );\n const pressurePascal =\n requirePositiveFinite(\n record.pressurePascal,\n path + \".pressurePascal\"\n );\n\n const relativeHumidityFraction =\n record.relativeHumidityFraction ===\n undefined\n ? undefined\n : requireFraction(\n record.relativeHumidityFraction,\n path +\n \".relativeHumidityFraction\"\n );\n\n const carbonDioxideMoleFraction =\n record.carbonDioxideMoleFraction ===\n undefined\n ? undefined\n : requireFraction(\n record.carbonDioxideMoleFraction,\n path +\n \".carbonDioxideMoleFraction\"\n );\n\n return {\n temperatureC,\n pressurePascal,\n ...(relativeHumidityFraction ===\n undefined\n ? {}\n : {\n relativeHumidityFraction\n }),\n ...(carbonDioxideMoleFraction ===\n undefined\n ? {}\n : {\n carbonDioxideMoleFraction\n })\n };\n}\n\nfunction parseConditionPolicy(\n value: unknown\n): AirRefractiveIndexConditionPolicy {\n const record = requireRecord(\n value,\n \"airConditionPolicy\", null\n );\n rejectUnknownVariantFields(record, \"kind\", { \"exact-match-required\": [\"kind\"], \"assume-compatible\": [\"kind\", \"limitation\", \"evidence\"] }, \"airConditionPolicy\");\n\n if (\n record.kind === \"exact-match-required\"\n ) {\n return {\n kind: \"exact-match-required\"\n };\n }\n\n if (\n record.kind === \"assume-compatible\"\n ) {\n if (\n typeof record.limitation !==\n \"string\" ||\n record.limitation.trim().length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n \"airConditionPolicy.limitation must be a non-empty string.\"\n );\n }\n return {\n kind: \"assume-compatible\",\n limitation:\n record.limitation,\n evidence: parseEvidenceList(\n record.evidence,\n \"airConditionPolicy.evidence\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n \"airConditionPolicy.kind is invalid.\"\n );\n}\n\nfunction conditionsMatch(\n reference:\n AirRefractiveIndexReferenceConditions,\n operating:\n AirRefractiveIndexReferenceConditions\n): boolean {\n if (\n reference.temperatureC !==\n operating.temperatureC ||\n reference.pressurePascal !==\n operating.pressurePascal\n ) {\n return false;\n }\n if (\n reference.relativeHumidityFraction !==\n undefined &&\n reference.relativeHumidityFraction !==\n operating.relativeHumidityFraction\n ) {\n return false;\n }\n if (\n reference.carbonDioxideMoleFraction !==\n undefined &&\n reference.carbonDioxideMoleFraction !==\n operating.carbonDioxideMoleFraction\n ) {\n return false;\n }\n return true;\n}\n\n/**\n * Validates untrusted input and returns it as a normalized, typed value. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * The index is the phase refractive index n of air at one exact wavelength, from a cited source, for\n * stated atmospheric conditions. It converts air to vacuum wavelength: λ_vacuum = n·λ_air.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseSourcedAirPhaseRefractiveIndex(\n value: unknown\n): SourcedAirPhaseRefractiveIndex {\n const record = requireRecord(\n value,\n \"airPhaseRefractiveIndex\", [\"wavelengthBasis\", \"definition\", \"scientificStatus\", \"uncertainty\", \"referenceConditions\", \"wavelengthNanometers\", \"phaseRefractiveIndex\", \"evidence\"]\n );\n\n if (\n record.wavelengthBasis !== \"air\"\n ) {\n throw new InvalidConfigurationError(\n 'airPhaseRefractiveIndex.wavelengthBasis must be \"air\".'\n );\n }\n if (\n record.definition !==\n \"vacuum-wavelength-divided-by-air-wavelength\"\n ) {\n throw new InvalidConfigurationError(\n \"airPhaseRefractiveIndex.definition is invalid.\"\n );\n }\n if (\n record.scientificStatus !==\n \"calibrated\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"airPhaseRefractiveIndex.scientificStatus is invalid.\"\n );\n }\n\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"airPhaseRefractiveIndex.uncertainty\"\n );\n const referenceConditions =\n record.referenceConditions ===\n undefined\n ? undefined\n : parseReferenceConditions(\n record.referenceConditions,\n \"airPhaseRefractiveIndex.referenceConditions\"\n );\n\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated air phase refractive index must declare quantified relative uncertainty.\"\n );\n }\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n referenceConditions === undefined\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated air phase refractive index must declare temperature and pressure reference conditions.\"\n );\n }\n\n return {\n wavelengthNanometers:\n requirePositiveFinite(\n record.wavelengthNanometers,\n \"airPhaseRefractiveIndex.wavelengthNanometers\"\n ),\n wavelengthBasis: \"air\",\n definition:\n \"vacuum-wavelength-divided-by-air-wavelength\",\n phaseRefractiveIndex:\n requirePositiveFinite(\n record.phaseRefractiveIndex,\n \"airPhaseRefractiveIndex.phaseRefractiveIndex\"\n ),\n scientificStatus:\n record.scientificStatus,\n uncertainty,\n evidence: parseEvidenceList(\n record.evidence,\n \"airPhaseRefractiveIndex.evidence\"\n ),\n ...(referenceConditions ===\n undefined\n ? {}\n : { referenceConditions })\n };\n}\n\n/**\n * Converts a vacuum wavelength, or an air wavelength with its stated atmosphere, into optical\n * frequency and photon energy using the exact SI constants h and c.\n *\n * An air wavelength needs a sourced phase refractive index for that exact wavelength and matching\n * atmosphere; λ_vacuum = n·λ_air. The index's uncertainty is kept but not automatically carried\n * through to the photon energy.\n * @param input - The input; see `CalculatePhotonEnergyFromWavelengthInput` for its fields, units and coordinates.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function calculatePhotonEnergyFromWavelength(\n input:\n CalculatePhotonEnergyFromWavelengthInput\n): CalculationResult<PhotonEnergyFromWavelength> {\n requireInputKeys(input, \"calculatePhotonEnergyFromWavelength\", [\"wavelengthNanometers\", \"wavelengthBasis\", \"airPhaseRefractiveIndex\", \"airOperatingConditions\", \"airConditionPolicy\"]);\n const wavelengthNanometers = input.wavelengthNanometers;\n // A calculation input, not a configuration record, so a bad value is a scientific-input error.\n if (typeof wavelengthNanometers !== \"number\" || !Number.isFinite(wavelengthNanometers)) {\n throw new InvalidScientificInputError(\"wavelengthNanometers must be finite.\");\n }\n if (wavelengthNanometers <= 0) {\n throw new InvalidScientificInputError(\"wavelengthNanometers must be greater than zero.\");\n }\n\n if (\n input.wavelengthBasis ===\n \"unspecified\"\n ) {\n throw new InvalidScientificInputError(\n \"wavelengthBasis must be resolved to air or vacuum before photon-energy calculation.\"\n );\n }\n\n if (\n input.wavelengthBasis !== \"air\" &&\n input.wavelengthBasis !== \"vacuum\"\n ) {\n throw new InvalidConfigurationError(\n \"wavelengthBasis is invalid.\"\n );\n }\n\n let vacuumWavelengthNanometers:\n number;\n let wavelengthConversion:\n PhotonEnergyFromWavelength[\"wavelengthConversion\"];\n let parsedAir:\n SourcedAirPhaseRefractiveIndex |\n undefined;\n\n let parsedConditionPolicy:\n AirRefractiveIndexConditionPolicy |\n undefined;\n let parsedOperatingConditions:\n AirRefractiveIndexReferenceConditions |\n undefined;\n let airConditionCompatibility:\n PhotonEnergyFromWavelength[\"airConditionCompatibility\"] |\n undefined;\n\n if (\n input.wavelengthBasis ===\n \"vacuum\"\n ) {\n if (\n input.airPhaseRefractiveIndex !==\n undefined ||\n input.airOperatingConditions !==\n undefined ||\n input.airConditionPolicy !==\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"Air refractive-index inputs must be omitted for vacuum-basis wavelengths.\"\n );\n }\n vacuumWavelengthNanometers =\n wavelengthNanometers;\n wavelengthConversion =\n \"vacuum-identity\";\n } else {\n if (\n input.airPhaseRefractiveIndex ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"airPhaseRefractiveIndex is required for air-basis photon-energy calculation.\"\n );\n }\n parsedAir =\n parseSourcedAirPhaseRefractiveIndex(\n input.airPhaseRefractiveIndex\n );\n\n if (\n parsedAir.wavelengthNanometers !==\n wavelengthNanometers\n ) {\n throw new InvalidScientificInputError(\n \"airPhaseRefractiveIndex wavelength must exactly match wavelengthNanometers.\"\n );\n }\n\n if (\n input.airConditionPolicy ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"airConditionPolicy is required for air-basis photon-energy calculation.\"\n );\n }\n parsedConditionPolicy =\n parseConditionPolicy(\n input.airConditionPolicy\n );\n\n if (\n parsedConditionPolicy.kind ===\n \"exact-match-required\"\n ) {\n if (\n parsedAir.referenceConditions ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"Exact air-condition matching requires refractive-index reference conditions.\"\n );\n }\n if (\n input.airOperatingConditions ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"airOperatingConditions is required when exact air-condition matching is selected.\"\n );\n }\n parsedOperatingConditions =\n parseReferenceConditions(\n input.airOperatingConditions,\n \"airOperatingConditions\"\n );\n if (\n !conditionsMatch(\n parsedAir.referenceConditions,\n parsedOperatingConditions\n )\n ) {\n throw new InvalidScientificInputError(\n \"airOperatingConditions must match the refractive-index reference conditions.\"\n );\n }\n airConditionCompatibility =\n \"exact-match\";\n } else {\n parsedOperatingConditions =\n input.airOperatingConditions ===\n undefined\n ? undefined\n : parseReferenceConditions(\n input.airOperatingConditions,\n \"airOperatingConditions\"\n );\n airConditionCompatibility =\n \"assumed-compatible\";\n }\n\n vacuumWavelengthNanometers =\n wavelengthNanometers *\n parsedAir.phaseRefractiveIndex;\n wavelengthConversion =\n \"air-to-vacuum-via-phase-refractive-index\";\n }\n\n const vacuumWavelengthMeters =\n vacuumWavelengthNanometers *\n NANOMETERS_TO_METERS;\n const frequencyHertz =\n SPEED_OF_LIGHT_METERS_PER_SECOND /\n vacuumWavelengthMeters;\n const photonEnergyJoules =\n PLANCK_CONSTANT_JOULE_SECONDS *\n frequencyHertz;\n\n if (\n !Number.isFinite(\n vacuumWavelengthNanometers\n ) ||\n !Number.isFinite(frequencyHertz) ||\n !Number.isFinite(\n photonEnergyJoules\n )\n ) {\n throw new InvalidScientificInputError(\n \"Photon-energy calculation must remain finite.\"\n );\n }\n\n return calculatedResult(\n {\n inputWavelengthNanometers:\n wavelengthNanometers,\n inputWavelengthBasis:\n input.wavelengthBasis,\n vacuumWavelengthNanometers,\n frequencyHertz,\n photonEnergyJoules,\n wavelengthConversion,\n exactSiConstants: {\n planckConstantJouleSeconds:\n PLANCK_CONSTANT_JOULE_SECONDS,\n speedOfLightMetersPerSecond:\n SPEED_OF_LIGHT_METERS_PER_SECOND\n },\n ...(parsedAir === undefined\n ? {}\n : {\n phaseRefractiveIndexUsed:\n parsedAir\n .phaseRefractiveIndex,\n airRefractiveIndexScientificStatus:\n parsedAir\n .scientificStatus,\n airRefractiveIndexUncertainty:\n parsedAir.uncertainty,\n ...(parsedAir\n .referenceConditions ===\n undefined\n ? {}\n : {\n airRefractiveIndexReferenceConditions:\n parsedAir\n .referenceConditions\n }),\n airRefractiveIndexEvidence:\n parsedAir.evidence,\n ...(parsedOperatingConditions ===\n undefined\n ? {}\n : {\n airOperatingConditions:\n parsedOperatingConditions\n }),\n ...(parsedConditionPolicy ===\n undefined\n ? {}\n : {\n airConditionPolicy:\n parsedConditionPolicy\n }),\n ...(airConditionCompatibility ===\n undefined\n ? {}\n : {\n airConditionCompatibility\n }),\n ...(parsedConditionPolicy?.kind ===\n \"assume-compatible\"\n ? {\n airConditionAssumptionEvidence:\n parsedConditionPolicy\n .evidence\n }\n : {})\n }),\n inputUncertaintyPropagated:\n false\n },\n \"photon-energy-from-spectral-wavelength\",\n \"1.0.0\",\n [\n \"Planck constant h and vacuum speed of light c use their exact SI defining values.\",\n \"Photon energy is h times optical frequency; frequency is derived from vacuum wavelength.\",\n \"Vacuum-basis wavelength requires no refractive-index correction.\",\n \"Air-basis wavelength is converted with the phase refractive index definition n = lambda_vacuum / lambda_air at the exact requested wavelength.\",\n \"Air refractive index varies with wavelength and atmospheric conditions; this function never substitutes n = 1.\",\n \"Air-basis conversion requires either exact matching to the refractive-index reference atmosphere or an explicit evidence-backed compatibility assumption.\",\n \"Input refractive-index uncertainty is preserved as metadata but is not propagated into photon-energy uncertainty by this foundation.\",\n \"This calculation does not apply QE, calculate photon rate, generate electrons, integrate exposure time, or model saturation/noise.\"\n ]\n );\n}\n"]}
|
|
@@ -14,80 +14,9 @@ import { approximationResult } from "../core/calculation-result.js";
|
|
|
14
14
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
15
15
|
import { parseEvidenceList } from "../core/evidence-provenance.js";
|
|
16
16
|
import { InvalidScientificInputError } from "../core/validation.js";
|
|
17
|
-
import { requireInputObject, requireInputKeys,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
value === null ||
|
|
21
|
-
Array.isArray(value)) {
|
|
22
|
-
throw new InvalidConfigurationError(path + " must be an object.");
|
|
23
|
-
}
|
|
24
|
-
if (allowedKeys !== null)
|
|
25
|
-
rejectUnknownFields(value, allowedKeys, path);
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
function requireNonEmptyString(value, path) {
|
|
29
|
-
if (typeof value !== "string" ||
|
|
30
|
-
value.trim().length === 0) {
|
|
31
|
-
throw new InvalidConfigurationError(path + " must be a non-empty string.");
|
|
32
|
-
}
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
function requireFinite(value, path) {
|
|
36
|
-
if (typeof value !== "number" ||
|
|
37
|
-
!Number.isFinite(value)) {
|
|
38
|
-
throw new InvalidConfigurationError(path + " must be finite.");
|
|
39
|
-
}
|
|
40
|
-
return value;
|
|
41
|
-
}
|
|
42
|
-
function requirePositiveFinite(value, path) {
|
|
43
|
-
const parsed = requireFinite(value, path);
|
|
44
|
-
if (parsed <= 0) {
|
|
45
|
-
throw new InvalidConfigurationError(path +
|
|
46
|
-
" must be greater than zero.");
|
|
47
|
-
}
|
|
48
|
-
return parsed;
|
|
49
|
-
}
|
|
50
|
-
function requireNonNegativeFiniteInput(value, path) {
|
|
51
|
-
if (typeof value !== "number" ||
|
|
52
|
-
!Number.isFinite(value) ||
|
|
53
|
-
value < 0) {
|
|
54
|
-
throw new InvalidScientificInputError(path +
|
|
55
|
-
" must be finite and greater than or equal to zero.");
|
|
56
|
-
}
|
|
57
|
-
return value;
|
|
58
|
-
}
|
|
59
|
-
function requireSiteIndex(value, path) {
|
|
60
|
-
if (typeof value !== "number" ||
|
|
61
|
-
!Number.isSafeInteger(value) ||
|
|
62
|
-
value < 0) {
|
|
63
|
-
throw new InvalidConfigurationError(path +
|
|
64
|
-
" must be a non-negative safe integer.");
|
|
65
|
-
}
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
function parseUncertainty(value, path) {
|
|
69
|
-
const record = requireRecord(value, path, null);
|
|
70
|
-
rejectUnknownVariantFields(record, "kind", UNCERTAINTY_VARIANT_FIELDS, path);
|
|
71
|
-
if (record.kind === "relative") {
|
|
72
|
-
const fraction = requireFinite(record.fraction, path + ".fraction");
|
|
73
|
-
if (fraction < 0) {
|
|
74
|
-
throw new InvalidConfigurationError(path +
|
|
75
|
-
".fraction must be nonnegative.");
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
kind: "relative",
|
|
79
|
-
fraction,
|
|
80
|
-
basis: requireNonEmptyString(record.basis, path + ".basis")
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
if (record.kind === "not-quantified") {
|
|
84
|
-
return {
|
|
85
|
-
kind: "not-quantified",
|
|
86
|
-
limitation: requireNonEmptyString(record.limitation, path + ".limitation")
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
throw new InvalidConfigurationError(path + ".kind is invalid.");
|
|
90
|
-
}
|
|
17
|
+
import { requireInputObject, requireInputKeys, rejectUnknownVariantFields, requireConfigRecord as requireRecord, requireConfigFinite as requireFinite, requireConfigString as requireNonEmptyString, requireInputNonNegativeFinite as requireNonNegativeFiniteInput, requireConfigNonNegativeSafeInteger as requireSiteIndex, requireConfigFiniteAboveZero as requirePositiveFinite } from "../core/record-validation.js";
|
|
18
|
+
import { sameSite } from "../core/shared-helpers.js";
|
|
19
|
+
import { parseUncertainty } from "./camera-saturation-capacity.js";
|
|
91
20
|
function parseSiteApplicability(value) {
|
|
92
21
|
const record = requireRecord(value, "sensorPhysicalChargeCapacity.siteApplicability", null);
|
|
93
22
|
rejectUnknownVariantFields(record, "kind", { "exact-site": ["kind", "site"], "uniform-site-capacity-approximation": ["kind", "limitation", "evidence"] }, "sensorPhysicalChargeCapacity.siteApplicability");
|
|
@@ -196,9 +125,6 @@ export function parseSensorPhysicalChargeCapacityProfile(value) {
|
|
|
196
125
|
temperatureApplicability
|
|
197
126
|
};
|
|
198
127
|
}
|
|
199
|
-
function sameSite(a, b) {
|
|
200
|
-
return a.x === b.x && a.y === b.y;
|
|
201
|
-
}
|
|
202
128
|
function validateCharge(charge) {
|
|
203
129
|
requireInputObject(charge, "charge input");
|
|
204
130
|
if (charge
|