@photivra/engine 0.5.1 → 1.0.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/AGENTS.md +674 -0
- package/CHANGELOG.md +218 -0
- package/CITATION.cff +1 -1
- package/CONTRIBUTING.md +76 -0
- package/DCO +33 -0
- package/NODE_SUPPORT.md +37 -0
- package/NOTICE +2 -0
- package/README.md +157 -56
- package/SECURITY.md +55 -0
- package/THIRD_PARTY.md +63 -0
- package/dist/camera/equivalent-focal-length.d.ts +9 -0
- package/dist/camera/equivalent-focal-length.d.ts.map +1 -1
- package/dist/camera/equivalent-focal-length.js +9 -0
- package/dist/camera/equivalent-focal-length.js.map +1 -1
- package/dist/camera/field-of-view.d.ts +13 -0
- package/dist/camera/field-of-view.d.ts.map +1 -1
- package/dist/camera/field-of-view.js +13 -0
- package/dist/camera/field-of-view.js.map +1 -1
- package/dist/camera/projected-object-size.d.ts +8 -0
- package/dist/camera/projected-object-size.d.ts.map +1 -1
- package/dist/camera/projected-object-size.js +8 -0
- package/dist/camera/projected-object-size.js.map +1 -1
- package/dist/capture/capture-export-metadata.d.ts +60 -0
- package/dist/capture/capture-export-metadata.d.ts.map +1 -0
- package/dist/capture/capture-export-metadata.js +62 -0
- package/dist/capture/capture-export-metadata.js.map +1 -0
- package/dist/capture/environment-raw-producer.d.ts +55 -0
- package/dist/capture/environment-raw-producer.d.ts.map +1 -0
- package/dist/capture/environment-raw-producer.js +88 -0
- package/dist/capture/environment-raw-producer.js.map +1 -0
- package/dist/capture/export-jpeg.d.ts +12 -0
- package/dist/capture/export-jpeg.d.ts.map +1 -0
- package/dist/capture/export-jpeg.js +126 -0
- package/dist/capture/export-jpeg.js.map +1 -0
- package/dist/capture/export-tiff.d.ts +45 -0
- package/dist/capture/export-tiff.d.ts.map +1 -0
- package/dist/capture/export-tiff.js +129 -0
- package/dist/capture/export-tiff.js.map +1 -0
- package/dist/capture/focus-control.d.ts +210 -0
- package/dist/capture/focus-control.d.ts.map +1 -0
- package/dist/capture/focus-control.js +664 -0
- package/dist/capture/focus-control.js.map +1 -0
- package/dist/capture/linear-encoding.d.ts +59 -0
- package/dist/capture/linear-encoding.d.ts.map +1 -0
- package/dist/capture/linear-encoding.js +98 -0
- package/dist/capture/linear-encoding.js.map +1 -0
- package/dist/capture/photographic-export.d.ts +135 -0
- package/dist/capture/photographic-export.d.ts.map +1 -0
- package/dist/capture/photographic-export.js +273 -0
- package/dist/capture/photographic-export.js.map +1 -0
- package/dist/capture/raw-frame-limits.d.ts +12 -0
- package/dist/capture/raw-frame-limits.d.ts.map +1 -0
- package/dist/capture/raw-frame-limits.js +13 -0
- package/dist/capture/raw-frame-limits.js.map +1 -0
- package/dist/capture/raw-frame-reconstruction.d.ts +48 -0
- package/dist/capture/raw-frame-reconstruction.d.ts.map +1 -0
- package/dist/capture/raw-frame-reconstruction.js +146 -0
- package/dist/capture/raw-frame-reconstruction.js.map +1 -0
- package/dist/capture/release-sequence.d.ts +120 -0
- package/dist/capture/release-sequence.d.ts.map +1 -0
- package/dist/capture/release-sequence.js +446 -0
- package/dist/capture/release-sequence.js.map +1 -0
- package/dist/capture/sensor-raw-frame.d.ts +34 -0
- package/dist/capture/sensor-raw-frame.d.ts.map +1 -0
- package/dist/capture/sensor-raw-frame.js +106 -0
- package/dist/capture/sensor-raw-frame.js.map +1 -0
- package/dist/capture/sensor-raw-producer.d.ts +51 -0
- package/dist/capture/sensor-raw-producer.d.ts.map +1 -0
- package/dist/capture/sensor-raw-producer.js +235 -0
- package/dist/capture/sensor-raw-producer.js.map +1 -0
- package/dist/capture/simulated-capture.d.ts +125 -0
- package/dist/capture/simulated-capture.d.ts.map +1 -0
- package/dist/capture/simulated-capture.js +248 -0
- package/dist/capture/simulated-capture.js.map +1 -0
- package/dist/color/capture-color.d.ts +73 -0
- package/dist/color/capture-color.d.ts.map +1 -0
- package/dist/color/capture-color.js +145 -0
- package/dist/color/capture-color.js.map +1 -0
- package/dist/color/sensor-color-development.d.ts +23 -0
- package/dist/color/sensor-color-development.d.ts.map +1 -0
- package/dist/color/sensor-color-development.js +56 -0
- package/dist/color/sensor-color-development.js.map +1 -0
- package/dist/color/white-balance.d.ts +175 -0
- package/dist/color/white-balance.d.ts.map +1 -0
- package/dist/color/white-balance.js +606 -0
- package/dist/color/white-balance.js.map +1 -0
- package/dist/composition/image-formation-plan.d.ts +481 -0
- package/dist/composition/image-formation-plan.d.ts.map +1 -0
- package/dist/composition/image-formation-plan.js +2499 -0
- package/dist/composition/image-formation-plan.js.map +1 -0
- package/dist/composition/plan-consumer.d.ts +53 -0
- package/dist/composition/plan-consumer.d.ts.map +1 -0
- package/dist/composition/plan-consumer.js +119 -0
- package/dist/composition/plan-consumer.js.map +1 -0
- package/dist/core/calculation-result.d.ts.map +1 -1
- package/dist/core/calculation-result.js +6 -0
- package/dist/core/calculation-result.js.map +1 -1
- package/dist/core/canonical-json.d.ts +18 -0
- package/dist/core/canonical-json.d.ts.map +1 -0
- package/dist/core/canonical-json.js +44 -0
- package/dist/core/canonical-json.js.map +1 -0
- package/dist/core/configuration-error.d.ts +6 -0
- package/dist/core/configuration-error.d.ts.map +1 -1
- package/dist/core/configuration-error.js +6 -0
- package/dist/core/configuration-error.js.map +1 -1
- package/dist/core/evidence-provenance.d.ts +6 -0
- package/dist/core/evidence-provenance.d.ts.map +1 -1
- package/dist/core/evidence-provenance.js +7 -0
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/image-formation.d.ts +9 -3
- package/dist/core/image-formation.d.ts.map +1 -1
- package/dist/core/image-formation.js +29 -5
- package/dist/core/image-formation.js.map +1 -1
- package/dist/core/owned-data.d.ts +25 -0
- package/dist/core/owned-data.d.ts.map +1 -0
- package/dist/core/owned-data.js +34 -0
- package/dist/core/owned-data.js.map +1 -0
- package/dist/core/record-validation.d.ts +17 -0
- package/dist/core/record-validation.d.ts.map +1 -0
- package/dist/core/record-validation.js +44 -0
- package/dist/core/record-validation.js.map +1 -0
- package/dist/core/scientific-assurance.d.ts +101 -0
- package/dist/core/scientific-assurance.d.ts.map +1 -0
- package/dist/core/scientific-assurance.js +301 -0
- package/dist/core/scientific-assurance.js.map +1 -0
- package/dist/core/spectral-composition.d.ts +106 -0
- package/dist/core/spectral-composition.d.ts.map +1 -0
- package/dist/core/spectral-composition.js +334 -0
- package/dist/core/spectral-composition.js.map +1 -0
- package/dist/core/spectral.d.ts +34 -0
- package/dist/core/spectral.d.ts.map +1 -0
- package/dist/core/spectral.js +57 -0
- package/dist/core/spectral.js.map +1 -0
- package/dist/core/validation.d.ts +6 -0
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +6 -0
- package/dist/core/validation.js.map +1 -1
- package/dist/core/version.d.ts +14 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +15 -0
- package/dist/core/version.js.map +1 -0
- package/dist/equipment/exposure-capabilities.d.ts +125 -0
- package/dist/equipment/exposure-capabilities.d.ts.map +1 -0
- package/dist/equipment/exposure-capabilities.js +391 -0
- package/dist/equipment/exposure-capabilities.js.map +1 -0
- package/dist/equipment/generic-tier-assets.d.ts +82 -0
- package/dist/equipment/generic-tier-assets.d.ts.map +1 -0
- package/dist/equipment/generic-tier-assets.js +119 -0
- package/dist/equipment/generic-tier-assets.js.map +1 -0
- package/dist/equipment/generic-tier-presets.d.ts +57 -0
- package/dist/equipment/generic-tier-presets.d.ts.map +1 -0
- package/dist/equipment/generic-tier-presets.js +122 -0
- package/dist/equipment/generic-tier-presets.js.map +1 -0
- package/dist/equipment/iso-capabilities.d.ts +143 -0
- package/dist/equipment/iso-capabilities.d.ts.map +1 -0
- package/dist/equipment/iso-capabilities.js +578 -0
- package/dist/equipment/iso-capabilities.js.map +1 -0
- package/dist/equipment/metering-capabilities.d.ts +58 -0
- package/dist/equipment/metering-capabilities.d.ts.map +1 -0
- package/dist/equipment/metering-capabilities.js +151 -0
- package/dist/equipment/metering-capabilities.js.map +1 -0
- package/dist/equipment/release-capabilities.d.ts +33 -0
- package/dist/equipment/release-capabilities.d.ts.map +1 -0
- package/dist/equipment/release-capabilities.js +176 -0
- package/dist/equipment/release-capabilities.js.map +1 -0
- package/dist/exposure/exposure-duration-control.d.ts +72 -0
- package/dist/exposure/exposure-duration-control.d.ts.map +1 -0
- package/dist/exposure/exposure-duration-control.js +161 -0
- package/dist/exposure/exposure-duration-control.js.map +1 -0
- package/dist/exposure/exposure-mode-resolver.d.ts +637 -0
- package/dist/exposure/exposure-mode-resolver.d.ts.map +1 -0
- package/dist/exposure/exposure-mode-resolver.js +1905 -0
- package/dist/exposure/exposure-mode-resolver.js.map +1 -0
- package/dist/exposure/exposure.d.ts +8 -0
- package/dist/exposure/exposure.d.ts.map +1 -1
- package/dist/exposure/exposure.js +8 -0
- package/dist/exposure/exposure.js.map +1 -1
- package/dist/exposure/flash.d.ts +179 -0
- package/dist/exposure/flash.d.ts.map +1 -0
- package/dist/exposure/flash.js +644 -0
- package/dist/exposure/flash.js.map +1 -0
- package/dist/exposure/metering-scene-radiance.d.ts +72 -0
- package/dist/exposure/metering-scene-radiance.d.ts.map +1 -0
- package/dist/exposure/metering-scene-radiance.js +222 -0
- package/dist/exposure/metering-scene-radiance.js.map +1 -0
- package/dist/exposure/metering-target.d.ts +67 -0
- package/dist/exposure/metering-target.d.ts.map +1 -0
- package/dist/exposure/metering-target.js +265 -0
- package/dist/exposure/metering-target.js.map +1 -0
- package/dist/exposure/metering-temporal.d.ts +76 -0
- package/dist/exposure/metering-temporal.d.ts.map +1 -0
- package/dist/exposure/metering-temporal.js +210 -0
- package/dist/exposure/metering-temporal.js.map +1 -0
- package/dist/exposure/metering.d.ts +124 -0
- package/dist/exposure/metering.d.ts.map +1 -0
- package/dist/exposure/metering.js +422 -0
- package/dist/exposure/metering.js.map +1 -0
- package/dist/exposure/program-line.d.ts +29 -0
- package/dist/exposure/program-line.d.ts.map +1 -0
- package/dist/exposure/program-line.js +126 -0
- package/dist/exposure/program-line.js.map +1 -0
- package/dist/index.d.ts +101 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +99 -7
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.d.ts +76 -0
- package/dist/motion/camera-rotation.d.ts.map +1 -1
- package/dist/motion/camera-rotation.js +111 -0
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +113 -0
- package/dist/motion/capture-rotation-inverse-mapping.d.ts.map +1 -0
- package/dist/motion/capture-rotation-inverse-mapping.js +184 -0
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -0
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +104 -0
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts.map +1 -0
- package/dist/motion/capture-rotation-temporal-quadrature.js +131 -0
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -0
- package/dist/motion/capture-rotation-trajectory.d.ts +113 -0
- package/dist/motion/capture-rotation-trajectory.d.ts.map +1 -0
- package/dist/motion/capture-rotation-trajectory.js +168 -0
- package/dist/motion/capture-rotation-trajectory.js.map +1 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +119 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts.map +1 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +263 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -0
- package/dist/motion/extended-object-projection.d.ts +175 -0
- package/dist/motion/extended-object-projection.d.ts.map +1 -0
- package/dist/motion/extended-object-projection.js +402 -0
- package/dist/motion/extended-object-projection.js.map +1 -0
- package/dist/motion/projected-motion.d.ts +11 -0
- package/dist/motion/projected-motion.d.ts.map +1 -1
- package/dist/motion/projected-motion.js +11 -0
- package/dist/motion/projected-motion.js.map +1 -1
- package/dist/optics/aperture.d.ts +9 -0
- package/dist/optics/aperture.d.ts.map +1 -1
- package/dist/optics/aperture.js +9 -0
- package/dist/optics/aperture.js.map +1 -1
- package/dist/optics/circle-of-confusion.d.ts +8 -0
- package/dist/optics/circle-of-confusion.d.ts.map +1 -1
- package/dist/optics/circle-of-confusion.js +8 -0
- package/dist/optics/circle-of-confusion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +128 -0
- package/dist/optics/complex-pupil-psf.d.ts.map +1 -0
- package/dist/optics/complex-pupil-psf.js +462 -0
- package/dist/optics/complex-pupil-psf.js.map +1 -0
- package/dist/optics/depth-of-field.d.ts +18 -0
- package/dist/optics/depth-of-field.d.ts.map +1 -1
- package/dist/optics/depth-of-field.js +29 -4
- package/dist/optics/depth-of-field.js.map +1 -1
- package/dist/optics/diffraction.d.ts +8 -0
- package/dist/optics/diffraction.d.ts.map +1 -1
- package/dist/optics/diffraction.js +8 -0
- package/dist/optics/diffraction.js.map +1 -1
- package/dist/optics/focus-breathing.d.ts +13 -0
- package/dist/optics/focus-breathing.d.ts.map +1 -1
- package/dist/optics/focus-breathing.js +13 -0
- package/dist/optics/focus-breathing.js.map +1 -1
- package/dist/optics/focus-state.d.ts +47 -0
- package/dist/optics/focus-state.d.ts.map +1 -0
- package/dist/optics/focus-state.js +78 -0
- package/dist/optics/focus-state.js.map +1 -0
- package/dist/optics/front-of-lens-filter.d.ts +114 -0
- package/dist/optics/front-of-lens-filter.d.ts.map +1 -0
- package/dist/optics/front-of-lens-filter.js +468 -0
- package/dist/optics/front-of-lens-filter.js.map +1 -0
- package/dist/optics/illumination-vignetting.d.ts +9 -0
- package/dist/optics/illumination-vignetting.d.ts.map +1 -1
- package/dist/optics/illumination-vignetting.js +9 -0
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/lateral-chromatic-aberration.d.ts +11 -0
- package/dist/optics/lateral-chromatic-aberration.d.ts.map +1 -1
- package/dist/optics/lateral-chromatic-aberration.js +23 -4
- package/dist/optics/lateral-chromatic-aberration.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +217 -0
- package/dist/optics/lens-psf-profile.d.ts.map +1 -0
- package/dist/optics/lens-psf-profile.js +823 -0
- package/dist/optics/lens-psf-profile.js.map +1 -0
- package/dist/optics/polygon-diffraction.d.ts +67 -0
- package/dist/optics/polygon-diffraction.d.ts.map +1 -0
- package/dist/optics/polygon-diffraction.js +145 -0
- package/dist/optics/polygon-diffraction.js.map +1 -0
- package/dist/optics/profile-contract.d.ts +42 -0
- package/dist/optics/profile-contract.d.ts.map +1 -0
- package/dist/optics/profile-contract.js +92 -0
- package/dist/optics/profile-contract.js.map +1 -0
- package/dist/optics/psf-foundation.d.ts +16 -3
- package/dist/optics/psf-foundation.d.ts.map +1 -1
- package/dist/optics/psf-foundation.js +28 -15
- package/dist/optics/psf-foundation.js.map +1 -1
- package/dist/optics/radial-distortion.d.ts +22 -2
- package/dist/optics/radial-distortion.d.ts.map +1 -1
- package/dist/optics/radial-distortion.js +101 -23
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +213 -0
- package/dist/optics/scene-to-sensor-irradiance.d.ts.map +1 -0
- package/dist/optics/scene-to-sensor-irradiance.js +662 -0
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -0
- package/dist/optics/scene-to-sensor-quadrature.d.ts +63 -0
- package/dist/optics/scene-to-sensor-quadrature.d.ts.map +1 -0
- package/dist/optics/scene-to-sensor-quadrature.js +82 -0
- package/dist/optics/scene-to-sensor-quadrature.js.map +1 -0
- package/dist/optics/sensor-environment-query.d.ts +60 -0
- package/dist/optics/sensor-environment-query.d.ts.map +1 -0
- package/dist/optics/sensor-environment-query.js +50 -0
- package/dist/optics/sensor-environment-query.js.map +1 -0
- package/dist/optics/sensor-psf-quadrature.d.ts +70 -0
- package/dist/optics/sensor-psf-quadrature.d.ts.map +1 -0
- package/dist/optics/sensor-psf-quadrature.js +101 -0
- package/dist/optics/sensor-psf-quadrature.js.map +1 -0
- package/dist/optics/sensor-psf-support.d.ts +20 -0
- package/dist/optics/sensor-psf-support.d.ts.map +1 -0
- package/dist/optics/sensor-psf-support.js +13 -0
- package/dist/optics/sensor-psf-support.js.map +1 -0
- package/dist/optics/stray-light.d.ts +91 -0
- package/dist/optics/stray-light.d.ts.map +1 -0
- package/dist/optics/stray-light.js +110 -0
- package/dist/optics/stray-light.js.map +1 -0
- package/dist/optics/thin-lens.d.ts +8 -0
- package/dist/optics/thin-lens.d.ts.map +1 -1
- package/dist/optics/thin-lens.js +8 -0
- package/dist/optics/thin-lens.js.map +1 -1
- package/dist/output/capture-corrected-sdr.d.ts +49 -0
- package/dist/output/capture-corrected-sdr.d.ts.map +1 -0
- package/dist/output/capture-corrected-sdr.js +149 -0
- package/dist/output/capture-corrected-sdr.js.map +1 -0
- package/dist/output/capture-geometry.d.ts.map +1 -1
- package/dist/output/capture-geometry.js +32 -11
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/capture-sdr.d.ts +49 -0
- package/dist/output/capture-sdr.d.ts.map +1 -0
- package/dist/output/capture-sdr.js +90 -0
- package/dist/output/capture-sdr.js.map +1 -0
- package/dist/output/crop.d.ts +6 -0
- package/dist/output/crop.d.ts.map +1 -1
- package/dist/output/crop.js +6 -0
- package/dist/output/crop.js.map +1 -1
- package/dist/output/geometric-transforms.d.ts +137 -0
- package/dist/output/geometric-transforms.d.ts.map +1 -0
- package/dist/output/geometric-transforms.js +225 -0
- package/dist/output/geometric-transforms.js.map +1 -0
- package/dist/output/lens-corrections.d.ts +121 -0
- package/dist/output/lens-corrections.d.ts.map +1 -0
- package/dist/output/lens-corrections.js +210 -0
- package/dist/output/lens-corrections.js.map +1 -0
- package/dist/output/sdr-rendering.d.ts +81 -0
- package/dist/output/sdr-rendering.d.ts.map +1 -0
- package/dist/output/sdr-rendering.js +106 -0
- package/dist/output/sdr-rendering.js.map +1 -0
- package/dist/output/subject-framing-crop.d.ts +8 -0
- package/dist/output/subject-framing-crop.d.ts.map +1 -1
- package/dist/output/subject-framing-crop.js +8 -0
- package/dist/output/subject-framing-crop.js.map +1 -1
- package/dist/schema/camera.d.ts +6 -0
- package/dist/schema/camera.d.ts.map +1 -1
- package/dist/schema/illumination-spectral.d.ts +51 -0
- package/dist/schema/illumination-spectral.d.ts.map +1 -0
- package/dist/schema/illumination-spectral.js +132 -0
- package/dist/schema/illumination-spectral.js.map +1 -0
- package/dist/schema/illumination-temporal.d.ts +156 -0
- package/dist/schema/illumination-temporal.d.ts.map +1 -0
- package/dist/schema/illumination-temporal.js +554 -0
- package/dist/schema/illumination-temporal.js.map +1 -0
- package/dist/schema/illumination.d.ts +138 -0
- package/dist/schema/illumination.d.ts.map +1 -0
- package/dist/schema/illumination.js +483 -0
- package/dist/schema/illumination.js.map +1 -0
- package/dist/schema/scene-radiance-temporal.d.ts +107 -0
- package/dist/schema/scene-radiance-temporal.d.ts.map +1 -0
- package/dist/schema/scene-radiance-temporal.js +259 -0
- package/dist/schema/scene-radiance-temporal.js.map +1 -0
- package/dist/schema/scene-radiance.d.ts +185 -0
- package/dist/schema/scene-radiance.d.ts.map +1 -0
- package/dist/schema/scene-radiance.js +535 -0
- package/dist/schema/scene-radiance.js.map +1 -0
- package/dist/schema/scene.d.ts +7 -0
- package/dist/schema/scene.d.ts.map +1 -1
- package/dist/schema/validation.d.ts.map +1 -1
- package/dist/schema/validation.js +7 -0
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.d.ts +199 -0
- package/dist/sensor/accumulated-charge.d.ts.map +1 -0
- package/dist/sensor/accumulated-charge.js +450 -0
- package/dist/sensor/accumulated-charge.js.map +1 -0
- package/dist/sensor/architecture.d.ts +48 -13
- package/dist/sensor/architecture.d.ts.map +1 -1
- package/dist/sensor/architecture.js +58 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +138 -0
- package/dist/sensor/camera-saturation-capacity.d.ts.map +1 -0
- package/dist/sensor/camera-saturation-capacity.js +356 -0
- package/dist/sensor/camera-saturation-capacity.js.map +1 -0
- package/dist/sensor/capture-color-sampling-binding.d.ts +212 -0
- package/dist/sensor/capture-color-sampling-binding.d.ts.map +1 -0
- package/dist/sensor/capture-color-sampling-binding.js +437 -0
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -0
- package/dist/sensor/capture-mode-timing.d.ts +63 -0
- package/dist/sensor/capture-mode-timing.d.ts.map +1 -0
- package/dist/sensor/capture-mode-timing.js +270 -0
- package/dist/sensor/capture-mode-timing.js.map +1 -0
- package/dist/sensor/capture-mode.d.ts +157 -0
- package/dist/sensor/capture-mode.d.ts.map +1 -0
- package/dist/sensor/capture-mode.js +447 -0
- package/dist/sensor/capture-mode.js.map +1 -0
- package/dist/sensor/color-sampling.d.ts +133 -0
- package/dist/sensor/color-sampling.d.ts.map +1 -0
- package/dist/sensor/color-sampling.js +245 -0
- package/dist/sensor/color-sampling.js.map +1 -0
- package/dist/sensor/constant-rate-temporal-integration.d.ts +126 -0
- package/dist/sensor/constant-rate-temporal-integration.d.ts.map +1 -0
- package/dist/sensor/constant-rate-temporal-integration.js +382 -0
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -0
- package/dist/sensor/dark-current.d.ts +169 -0
- package/dist/sensor/dark-current.d.ts.map +1 -0
- package/dist/sensor/dark-current.js +427 -0
- package/dist/sensor/dark-current.js.map +1 -0
- package/dist/sensor/environment-photo-signal.d.ts +123 -0
- package/dist/sensor/environment-photo-signal.d.ts.map +1 -0
- package/dist/sensor/environment-photo-signal.js +186 -0
- package/dist/sensor/environment-photo-signal.js.map +1 -0
- package/dist/sensor/eqe-electron-rate.d.ts +107 -0
- package/dist/sensor/eqe-electron-rate.d.ts.map +1 -0
- package/dist/sensor/eqe-electron-rate.js +561 -0
- package/dist/sensor/eqe-electron-rate.js.map +1 -0
- package/dist/sensor/eqe-local-exposure.d.ts +65 -0
- package/dist/sensor/eqe-local-exposure.d.ts.map +1 -0
- package/dist/sensor/eqe-local-exposure.js +84 -0
- package/dist/sensor/eqe-local-exposure.js.map +1 -0
- package/dist/sensor/eqe-temporal-exposure.d.ts +55 -0
- package/dist/sensor/eqe-temporal-exposure.d.ts.map +1 -0
- package/dist/sensor/eqe-temporal-exposure.js +62 -0
- package/dist/sensor/eqe-temporal-exposure.js.map +1 -0
- package/dist/sensor/exposure-window.d.ts +117 -0
- package/dist/sensor/exposure-window.d.ts.map +1 -0
- package/dist/sensor/exposure-window.js +305 -0
- package/dist/sensor/exposure-window.js.map +1 -0
- package/dist/sensor/iso-signal-chain.d.ts +148 -0
- package/dist/sensor/iso-signal-chain.d.ts.map +1 -0
- package/dist/sensor/iso-signal-chain.js +411 -0
- package/dist/sensor/iso-signal-chain.js.map +1 -0
- package/dist/sensor/local-exposure-binding.d.ts +87 -0
- package/dist/sensor/local-exposure-binding.d.ts.map +1 -0
- package/dist/sensor/local-exposure-binding.js +214 -0
- package/dist/sensor/local-exposure-binding.js.map +1 -0
- package/dist/sensor/optical-stack.d.ts +132 -0
- package/dist/sensor/optical-stack.d.ts.map +1 -0
- package/dist/sensor/optical-stack.js +303 -0
- package/dist/sensor/optical-stack.js.map +1 -0
- package/dist/sensor/photon-energy.d.ts +97 -0
- package/dist/sensor/photon-energy.d.ts.map +1 -0
- package/dist/sensor/photon-energy.js +390 -0
- package/dist/sensor/photon-energy.js.map +1 -0
- package/dist/sensor/physical-charge-capacity.d.ts +130 -0
- package/dist/sensor/physical-charge-capacity.d.ts.map +1 -0
- package/dist/sensor/physical-charge-capacity.js +345 -0
- package/dist/sensor/physical-charge-capacity.js.map +1 -0
- package/dist/sensor/pixel-pitch.d.ts +6 -0
- package/dist/sensor/pixel-pitch.d.ts.map +1 -1
- package/dist/sensor/pixel-pitch.js +6 -0
- package/dist/sensor/pixel-pitch.js.map +1 -1
- package/dist/sensor/radiometry-readiness.d.ts +10 -0
- package/dist/sensor/radiometry-readiness.d.ts.map +1 -1
- package/dist/sensor/radiometry-readiness.js +10 -0
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +314 -0
- package/dist/sensor/raw-readout.d.ts.map +1 -0
- package/dist/sensor/raw-readout.js +914 -0
- package/dist/sensor/raw-readout.js.map +1 -0
- package/dist/sensor/raw-reconstruction.d.ts +170 -0
- package/dist/sensor/raw-reconstruction.d.ts.map +1 -0
- package/dist/sensor/raw-reconstruction.js +424 -0
- package/dist/sensor/raw-reconstruction.js.map +1 -0
- package/dist/sensor/readout-exposure-linkage.d.ts +123 -0
- package/dist/sensor/readout-exposure-linkage.d.ts.map +1 -0
- package/dist/sensor/readout-exposure-linkage.js +222 -0
- package/dist/sensor/readout-exposure-linkage.js.map +1 -0
- package/dist/sensor/readout-timing.d.ts +137 -0
- package/dist/sensor/readout-timing.d.ts.map +1 -0
- package/dist/sensor/readout-timing.js +243 -0
- package/dist/sensor/readout-timing.js.map +1 -0
- package/dist/sensor/response-application-compatibility.d.ts +136 -0
- package/dist/sensor/response-application-compatibility.d.ts.map +1 -0
- package/dist/sensor/response-application-compatibility.js +408 -0
- package/dist/sensor/response-application-compatibility.js.map +1 -0
- package/dist/sensor/response-operating-range.d.ts +173 -0
- package/dist/sensor/response-operating-range.d.ts.map +1 -0
- package/dist/sensor/response-operating-range.js +672 -0
- package/dist/sensor/response-operating-range.js.map +1 -0
- package/dist/sensor/responsivity-photocurrent.d.ts +158 -0
- package/dist/sensor/responsivity-photocurrent.d.ts.map +1 -0
- package/dist/sensor/responsivity-photocurrent.js +644 -0
- package/dist/sensor/responsivity-photocurrent.js.map +1 -0
- package/dist/sensor/sampling-aperture.d.ts +154 -0
- package/dist/sensor/sampling-aperture.d.ts.map +1 -0
- package/dist/sensor/sampling-aperture.js +388 -0
- package/dist/sensor/sampling-aperture.js.map +1 -0
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts +45 -0
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts.map +1 -0
- package/dist/sensor/scene-eqe-temporal-exposure.js +64 -0
- package/dist/sensor/scene-eqe-temporal-exposure.js.map +1 -0
- package/dist/sensor/sensor-geometry.d.ts +12 -0
- package/dist/sensor/sensor-geometry.d.ts.map +1 -1
- package/dist/sensor/sensor-geometry.js +12 -0
- package/dist/sensor/sensor-geometry.js.map +1 -1
- package/dist/sensor/signal-noise.d.ts +10 -0
- package/dist/sensor/signal-noise.d.ts.map +1 -1
- package/dist/sensor/signal-noise.js +10 -0
- package/dist/sensor/signal-noise.js.map +1 -1
- package/dist/sensor/spatial-sample-reduction.d.ts +171 -0
- package/dist/sensor/spatial-sample-reduction.d.ts.map +1 -0
- package/dist/sensor/spatial-sample-reduction.js +345 -0
- package/dist/sensor/spatial-sample-reduction.js.map +1 -0
- package/dist/sensor/spatial-sampling-quadrature.d.ts +179 -0
- package/dist/sensor/spatial-sampling-quadrature.d.ts.map +1 -0
- package/dist/sensor/spatial-sampling-quadrature.js +224 -0
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -0
- package/dist/sensor/spatio-spectral-reduction.d.ts +187 -0
- package/dist/sensor/spatio-spectral-reduction.d.ts.map +1 -0
- package/dist/sensor/spatio-spectral-reduction.js +373 -0
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -0
- package/dist/sensor/spectral-coverage.d.ts +24 -0
- package/dist/sensor/spectral-coverage.d.ts.map +1 -0
- package/dist/sensor/spectral-coverage.js +86 -0
- package/dist/sensor/spectral-coverage.js.map +1 -0
- package/dist/sensor/spectral-quadrature.d.ts +169 -0
- package/dist/sensor/spectral-quadrature.d.ts.map +1 -0
- package/dist/sensor/spectral-quadrature.js +542 -0
- package/dist/sensor/spectral-quadrature.js.map +1 -0
- package/dist/sensor/spectral-response.d.ts +192 -0
- package/dist/sensor/spectral-response.d.ts.map +1 -0
- package/dist/sensor/spectral-response.js +664 -0
- package/dist/sensor/spectral-response.js.map +1 -0
- package/dist/sensor/temporal-eqe-sum.d.ts +15 -0
- package/dist/sensor/temporal-eqe-sum.d.ts.map +1 -0
- package/dist/sensor/temporal-eqe-sum.js +30 -0
- package/dist/sensor/temporal-eqe-sum.js.map +1 -0
- package/dist/sensor/temporal-photo-signal.d.ts +38 -0
- package/dist/sensor/temporal-photo-signal.d.ts.map +1 -0
- package/dist/sensor/temporal-photo-signal.js +110 -0
- package/dist/sensor/temporal-photo-signal.js.map +1 -0
- package/dist/sensor/temporal-sample-binding.d.ts +6 -0
- package/dist/sensor/temporal-sample-binding.d.ts.map +1 -0
- package/dist/sensor/temporal-sample-binding.js +32 -0
- package/dist/sensor/temporal-sample-binding.js.map +1 -0
- package/dist/simulation/poc-simulation.d.ts.map +1 -1
- package/dist/simulation/poc-simulation.js +34 -11
- package/dist/simulation/poc-simulation.js.map +1 -1
- package/dist/stabilization/camera-shake.d.ts +11 -0
- package/dist/stabilization/camera-shake.d.ts.map +1 -1
- package/dist/stabilization/camera-shake.js +11 -0
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.d.ts +218 -0
- package/dist/stabilization/system.d.ts.map +1 -0
- package/dist/stabilization/system.js +695 -0
- package/dist/stabilization/system.js.map +1 -0
- package/docs/API_REFERENCE.md +2017 -0
- package/docs/API_STYLE.md +132 -0
- package/docs/ARCHITECTURE.md +150 -23
- package/docs/AUTOMATION_COORDINATION.md +190 -0
- package/docs/CAPTURE_COLOR.md +25 -0
- package/docs/CAPTURE_CORRECTED_SDR.md +25 -0
- package/docs/CAPTURE_EXPORT_METADATA.md +27 -0
- package/docs/CAPTURE_SDR.md +20 -0
- package/docs/DEVELOPERS.md +60 -0
- package/docs/DIGITAL_OPTICS_FOUNDATION.md +69 -0
- package/docs/ENVIRONMENT_RAW_CAPTURE.md +187 -0
- package/docs/EXPORT_ACCEPTANCE.md +133 -0
- package/docs/GENERIC_TIER_PRESETS.md +269 -0
- package/docs/GEOMETRIC_PREPARATION_REUSE.md +141 -0
- package/docs/IMAGE_FORMATION.md +105 -9
- package/docs/LINEAR_CAPTURE_ENCODING.md +25 -0
- package/docs/MOTION_AND_SIGNAL.md +145 -1
- package/docs/NUMERICAL_CORRECTNESS.md +191 -0
- package/docs/PERFORMANCE_BASELINE.md +56 -0
- package/docs/PHOTOGRAPHIC_EXPORT.md +206 -0
- package/docs/PHYSICS_FOUNDATION.md +152 -5
- package/docs/POC_API.md +2 -0
- package/docs/POC_PROJECTION_REUSE.md +124 -0
- package/docs/PROCESSED_OUTPUT.md +157 -0
- package/docs/PRODUCTION_COMPOSITION.md +373 -0
- package/docs/PRODUCTION_ENVIRONMENT_CAPTURE.md +131 -0
- package/docs/PROVENANCE.md +4 -0
- package/docs/PSF_FOUNDATION.md +110 -88
- package/docs/RAW_FRAME_ENVELOPE.md +56 -0
- package/docs/RAW_FRAME_RECONSTRUCTION.md +30 -0
- package/docs/RELEASE_1_0.md +65 -0
- package/docs/RELEASE_AUDIT.md +38 -0
- package/docs/SCENE_RADIANCE_AND_ILLUMINATION.md +298 -0
- package/docs/SCENE_SENSOR_QUADRATURE.md +98 -0
- package/docs/SCENE_SENSOR_TEMPORAL_EXPOSURE.md +86 -0
- package/docs/SCIENTIFIC_ASSURANCE.md +280 -0
- package/docs/SCIENTIFIC_CONFORMANCE.md +83 -0
- package/docs/SDR_RENDERING.md +33 -0
- package/docs/SENSOR_ENVIRONMENT_QUERY.md +86 -0
- package/docs/SENSOR_EQE_LOCAL_EXPOSURE.md +104 -0
- package/docs/SENSOR_EQE_TEMPORAL_EXPOSURE.md +74 -0
- package/docs/SENSOR_PSF_QUADRATURE.md +90 -0
- package/docs/SENSOR_RAW_FRAME.md +20 -0
- package/docs/SENSOR_RAW_PRODUCER.md +77 -0
- package/docs/SIGNAL_CONFORMANCE.md +23 -0
- package/docs/SIMULATED_CAPTURE.md +65 -0
- package/docs/STABILIZATION.md +160 -17
- package/docs/TEMPORAL_PHOTO_RAW.md +83 -0
- package/docs/TIER_ACCEPTANCE.md +129 -0
- package/docs/TIER_PRESET_ACCEPTANCE.md +59 -0
- package/docs/USAGE.md +5604 -331
- package/docs/V1_COMPOSITION_MAP.md +123 -0
- package/docs/V1_HELPER_REUSE_REVIEW.md +60 -0
- package/docs/V1_PERFORMANCE_DISPOSITION.md +88 -0
- package/docs/api/camera-equivalent-focal-length.md +53 -0
- package/docs/api/camera-field-of-view.md +119 -0
- package/docs/api/camera-projected-object-size.md +54 -0
- package/docs/api/capture-capture-export-metadata.md +107 -0
- package/docs/api/capture-environment-raw-producer.md +56 -0
- package/docs/api/capture-focus-control.md +419 -0
- package/docs/api/capture-linear-encoding.md +99 -0
- package/docs/api/capture-photographic-export.md +172 -0
- package/docs/api/capture-raw-frame-reconstruction.md +87 -0
- package/docs/api/capture-release-sequence.md +252 -0
- package/docs/api/capture-sensor-raw-frame.md +66 -0
- package/docs/api/capture-sensor-raw-producer.md +98 -0
- package/docs/api/capture-simulated-capture.md +179 -0
- package/docs/api/color-capture-color.md +122 -0
- package/docs/api/color-white-balance.md +386 -0
- package/docs/api/composition-image-formation-plan.md +825 -0
- package/docs/api/composition-plan-consumer.md +98 -0
- package/docs/api/core-calculation-result.md +220 -0
- package/docs/api/core-configuration-error.md +19 -0
- package/docs/api/core-image-formation.md +204 -0
- package/docs/api/core-scientific-assurance.md +214 -0
- package/docs/api/core-spectral-composition.md +268 -0
- package/docs/api/core-spectral.md +78 -0
- package/docs/api/core-validation.md +34 -0
- package/docs/api/core-version.md +14 -0
- package/docs/api/equipment-exposure-capabilities.md +270 -0
- package/docs/api/equipment-generic-tier-assets.md +82 -0
- package/docs/api/equipment-generic-tier-presets.md +103 -0
- package/docs/api/equipment-iso-capabilities.md +295 -0
- package/docs/api/equipment-metering-capabilities.md +126 -0
- package/docs/api/equipment-release-capabilities.md +91 -0
- package/docs/api/exports.json +5656 -0
- package/docs/api/exposure-exposure-duration-control.md +115 -0
- package/docs/api/exposure-exposure-mode-resolver.md +966 -0
- package/docs/api/exposure-exposure.md +150 -0
- package/docs/api/exposure-flash.md +327 -0
- package/docs/api/exposure-metering-scene-radiance.md +154 -0
- package/docs/api/exposure-metering-target.md +134 -0
- package/docs/api/exposure-metering-temporal.md +77 -0
- package/docs/api/exposure-metering.md +172 -0
- package/docs/api/exposure-program-line.md +64 -0
- package/docs/api/motion-camera-rotation.md +215 -0
- package/docs/api/motion-capture-rotation-inverse-mapping.md +128 -0
- package/docs/api/motion-capture-rotation-temporal-quadrature.md +127 -0
- package/docs/api/motion-capture-rotation-trajectory.md +132 -0
- package/docs/api/motion-capture-translation-parallax-temporal-quadrature.md +171 -0
- package/docs/api/motion-extended-object-projection.md +312 -0
- package/docs/api/motion-projected-motion.md +60 -0
- package/docs/api/optics-aperture.md +69 -0
- package/docs/api/optics-circle-of-confusion.md +46 -0
- package/docs/api/optics-complex-pupil-psf.md +193 -0
- package/docs/api/optics-depth-of-field.md +92 -0
- package/docs/api/optics-diffraction.md +46 -0
- package/docs/api/optics-focus-breathing.md +119 -0
- package/docs/api/optics-focus-state.md +64 -0
- package/docs/api/optics-front-of-lens-filter.md +263 -0
- package/docs/api/optics-illumination-vignetting.md +95 -0
- package/docs/api/optics-lateral-chromatic-aberration.md +225 -0
- package/docs/api/optics-lens-psf-profile.md +380 -0
- package/docs/api/optics-polygon-diffraction.md +68 -0
- package/docs/api/optics-profile-contract.md +47 -0
- package/docs/api/optics-psf-foundation.md +181 -0
- package/docs/api/optics-radial-distortion.md +194 -0
- package/docs/api/optics-scene-to-sensor-irradiance.md +371 -0
- package/docs/api/optics-scene-to-sensor-quadrature.md +78 -0
- package/docs/api/optics-sensor-environment-query.md +58 -0
- package/docs/api/optics-sensor-psf-quadrature.md +81 -0
- package/docs/api/optics-stray-light.md +109 -0
- package/docs/api/optics-thin-lens.md +53 -0
- package/docs/api/output-capture-corrected-sdr.md +71 -0
- package/docs/api/output-capture-geometry.md +500 -0
- package/docs/api/output-capture-sdr.md +69 -0
- package/docs/api/output-crop.md +47 -0
- package/docs/api/output-geometric-transforms.md +199 -0
- package/docs/api/output-lens-corrections.md +162 -0
- package/docs/api/output-sdr-rendering.md +122 -0
- package/docs/api/output-subject-framing-crop.md +59 -0
- package/docs/api/schema-camera.md +84 -0
- package/docs/api/schema-illumination-spectral.md +77 -0
- package/docs/api/schema-illumination-temporal.md +289 -0
- package/docs/api/schema-illumination.md +246 -0
- package/docs/api/schema-scene-radiance-temporal.md +215 -0
- package/docs/api/schema-scene-radiance.md +415 -0
- package/docs/api/schema-scene.md +105 -0
- package/docs/api/schema-validation.md +25 -0
- package/docs/api/sensor-accumulated-charge.md +273 -0
- package/docs/api/sensor-architecture.md +155 -0
- package/docs/api/sensor-camera-saturation-capacity.md +215 -0
- package/docs/api/sensor-capture-color-sampling-binding.md +323 -0
- package/docs/api/sensor-capture-mode-timing.md +123 -0
- package/docs/api/sensor-capture-mode.md +321 -0
- package/docs/api/sensor-color-sampling.md +228 -0
- package/docs/api/sensor-constant-rate-temporal-integration.md +152 -0
- package/docs/api/sensor-dark-current.md +227 -0
- package/docs/api/sensor-environment-photo-signal.md +77 -0
- package/docs/api/sensor-eqe-electron-rate.md +166 -0
- package/docs/api/sensor-eqe-local-exposure.md +68 -0
- package/docs/api/sensor-eqe-temporal-exposure.md +73 -0
- package/docs/api/sensor-exposure-window.md +183 -0
- package/docs/api/sensor-iso-signal-chain.md +264 -0
- package/docs/api/sensor-local-exposure-binding.md +126 -0
- package/docs/api/sensor-optical-stack.md +211 -0
- package/docs/api/sensor-photon-energy.md +149 -0
- package/docs/api/sensor-physical-charge-capacity.md +196 -0
- package/docs/api/sensor-pixel-pitch.md +41 -0
- package/docs/api/sensor-radiometry-readiness.md +240 -0
- package/docs/api/sensor-raw-readout.md +499 -0
- package/docs/api/sensor-raw-reconstruction.md +260 -0
- package/docs/api/sensor-readout-exposure-linkage.md +172 -0
- package/docs/api/sensor-readout-timing.md +209 -0
- package/docs/api/sensor-response-application-compatibility.md +256 -0
- package/docs/api/sensor-response-operating-range.md +293 -0
- package/docs/api/sensor-responsivity-photocurrent.md +245 -0
- package/docs/api/sensor-sampling-aperture.md +221 -0
- package/docs/api/sensor-scene-eqe-temporal-exposure.md +56 -0
- package/docs/api/sensor-sensor-geometry.md +143 -0
- package/docs/api/sensor-signal-noise.md +75 -0
- package/docs/api/sensor-spatial-sample-reduction.md +186 -0
- package/docs/api/sensor-spatial-sampling-quadrature.md +188 -0
- package/docs/api/sensor-spatio-spectral-reduction.md +217 -0
- package/docs/api/sensor-spectral-coverage.md +33 -0
- package/docs/api/sensor-spectral-quadrature.md +183 -0
- package/docs/api/sensor-spectral-response.md +291 -0
- package/docs/api/sensor-temporal-photo-signal.md +62 -0
- package/docs/api/simulation-poc-simulation.md +364 -0
- package/docs/api/stabilization-camera-shake.md +71 -0
- package/docs/api/stabilization-system.md +442 -0
- package/docs/benchmarks/2026-10-01-main-baseline.json +694 -0
- package/docs/benchmarks/2026-10-02-geometric-preparation-reuse.json +2190 -0
- package/docs/benchmarks/2026-10-02-poc-projection-reuse.json +2423 -0
- package/docs/benchmarks/2026-10-02-v1-environment-gc-profile.json +210 -0
- package/docs/benchmarks/2026-10-02-v1-environment-ordinary.json +187 -0
- package/docs/benchmarks/2026-10-02-v1-geometry-gc-profile.json +756 -0
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-1.json +711 -0
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-2.json +711 -0
- package/docs/benchmarks/2026-10-02-v1-poc-gc-profile.json +885 -0
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-1.json +868 -0
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-2.json +868 -0
- package/docs/examples/production-capture.mjs +34 -0
- package/docs/examples/production-request.json +4613 -0
- package/docs/examples/quick-start.mjs +12 -0
- package/docs/validation/documentation-fragments.json +212 -0
- package/docs/validation/release-audit-inventory.json +1306 -0
- package/docs/validation/tier-acceptance-report-v1.json +2538 -0
- package/package.json +18 -4
|
@@ -0,0 +1,914 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Module boundary and integration notes.
|
|
4
|
+
* Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
|
|
5
|
+
* missing required fields and incompatible scientific data fail at this boundary. Signal ordering is
|
|
6
|
+
* expected charge → independent seeded photo/dark draws → signed electronic read noise → upper pre-ADC
|
|
7
|
+
* threshold → black pedestal → nearest-half-up ADC quantization → unsigned code limits. Signed
|
|
8
|
+
* below-black values survive until the final code clamp. Physical storage saturation, pre-ADC clipping
|
|
9
|
+
* and digital clipping have distinct diagnostics; ISO never invents a conversion regime.
|
|
10
|
+
* Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
|
|
11
|
+
* missing required fields and incompatible scientific data fail at this boundary. Signal ordering is
|
|
12
|
+
* expected charge → independent seeded photo/dark draws → signed electronic read noise → upper pre-ADC
|
|
13
|
+
* threshold → black pedestal → nearest-half-up ADC quantization → unsigned code limits. Signed
|
|
14
|
+
* below-black values survive until the final code clamp. Physical storage saturation, pre-ADC clipping
|
|
15
|
+
* and digital clipping have distinct diagnostics; ISO never invents a conversion regime.
|
|
16
|
+
* @see docs/SENSOR_RAW_PRODUCER.md for equations, coordinate/unit conventions, blockers and support
|
|
17
|
+
* limits.
|
|
18
|
+
*/
|
|
19
|
+
import { approximationResult } from "../core/calculation-result.js";
|
|
20
|
+
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
21
|
+
import { parseEvidenceList } from "../core/evidence-provenance.js";
|
|
22
|
+
import { InvalidScientificInputError } from "../core/validation.js";
|
|
23
|
+
export const SENSOR_CHARGE_SAMPLING_PROFILE_SCHEMA_VERSION = "0.1.0";
|
|
24
|
+
export const SENSOR_READOUT_CONVERSION_PROFILE_SCHEMA_VERSION = "0.1.0";
|
|
25
|
+
function requireRecord(value, path) {
|
|
26
|
+
if (typeof value !== "object" ||
|
|
27
|
+
value === null ||
|
|
28
|
+
Array.isArray(value)) {
|
|
29
|
+
throw new InvalidConfigurationError(path + " must be an object.");
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function requireNonEmptyString(value, path) {
|
|
34
|
+
if (typeof value !== "string" ||
|
|
35
|
+
value.trim().length === 0) {
|
|
36
|
+
throw new InvalidConfigurationError(path + " must be a non-empty string.");
|
|
37
|
+
}
|
|
38
|
+
return value.trim();
|
|
39
|
+
}
|
|
40
|
+
function requireFinite(value, path) {
|
|
41
|
+
if (typeof value !== "number" ||
|
|
42
|
+
!Number.isFinite(value)) {
|
|
43
|
+
throw new InvalidConfigurationError(path + " must be finite.");
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
function requireNonNegativeFinite(value, path) {
|
|
48
|
+
const parsed = requireFinite(value, path);
|
|
49
|
+
if (parsed < 0) {
|
|
50
|
+
throw new InvalidConfigurationError(path +
|
|
51
|
+
" must be greater than or equal to zero.");
|
|
52
|
+
}
|
|
53
|
+
return parsed;
|
|
54
|
+
}
|
|
55
|
+
function requirePositiveFinite(value, path) {
|
|
56
|
+
const parsed = requireFinite(value, path);
|
|
57
|
+
if (parsed <= 0) {
|
|
58
|
+
throw new InvalidConfigurationError(path +
|
|
59
|
+
" must be greater than zero.");
|
|
60
|
+
}
|
|
61
|
+
return parsed;
|
|
62
|
+
}
|
|
63
|
+
function requireUint32(value, path) {
|
|
64
|
+
if (typeof value !== "number" ||
|
|
65
|
+
!Number.isSafeInteger(value) ||
|
|
66
|
+
value < 0 ||
|
|
67
|
+
value > 0xffff_ffff) {
|
|
68
|
+
throw new InvalidScientificInputError(path +
|
|
69
|
+
" must be an unsigned 32-bit integer.");
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
function requireSafeInteger(value, path) {
|
|
74
|
+
if (typeof value !== "number" ||
|
|
75
|
+
!Number.isSafeInteger(value)) {
|
|
76
|
+
throw new InvalidConfigurationError(path + " must be a safe integer.");
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
function parseLimitations(value, path) {
|
|
81
|
+
if (!Array.isArray(value)) {
|
|
82
|
+
throw new InvalidConfigurationError(path + " must be an array.");
|
|
83
|
+
}
|
|
84
|
+
const parsed = value.map((entry, index) => requireNonEmptyString(entry, path +
|
|
85
|
+
"[" +
|
|
86
|
+
index +
|
|
87
|
+
"]"));
|
|
88
|
+
if (new Set(parsed).size !==
|
|
89
|
+
parsed.length) {
|
|
90
|
+
throw new InvalidConfigurationError(path +
|
|
91
|
+
" must not contain duplicates.");
|
|
92
|
+
}
|
|
93
|
+
return parsed;
|
|
94
|
+
}
|
|
95
|
+
function parsePositiveFact(value, path) {
|
|
96
|
+
const record = requireRecord(value, path);
|
|
97
|
+
return {
|
|
98
|
+
value: requirePositiveFinite(record.value, path + ".value"),
|
|
99
|
+
evidence: parseEvidenceList(record.evidence, path + ".evidence")
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function parseNonNegativeFact(value, path) {
|
|
103
|
+
const record = requireRecord(value, path);
|
|
104
|
+
return {
|
|
105
|
+
value: requireNonNegativeFinite(record.value, path + ".value"),
|
|
106
|
+
evidence: parseEvidenceList(record.evidence, path + ".evidence")
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
|
|
111
|
+
* missing required fields and incompatible scientific data fail at this boundary.
|
|
112
|
+
*
|
|
113
|
+
* Signal ordering is expected charge → independent seeded photo/dark draws → signed electronic read
|
|
114
|
+
* noise → upper pre-ADC threshold → black pedestal → nearest-half-up ADC quantization → unsigned code
|
|
115
|
+
* limits. Signed below-black values survive until the final code clamp. Physical storage saturation,
|
|
116
|
+
* pre-ADC clipping and digital clipping have distinct diagnostics; ISO never invents a conversion
|
|
117
|
+
* regime.
|
|
118
|
+
* @param value - unknown. Treated as untrusted data; static typing alone is not validation.
|
|
119
|
+
* @returns SensorChargeSamplingProfile. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
120
|
+
*
|
|
121
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
122
|
+
*/
|
|
123
|
+
export function parseSensorChargeSamplingProfile(value) {
|
|
124
|
+
const record = requireRecord(value, "sensorChargeSamplingProfile");
|
|
125
|
+
if (record.schemaVersion !==
|
|
126
|
+
SENSOR_CHARGE_SAMPLING_PROFILE_SCHEMA_VERSION) {
|
|
127
|
+
throw new InvalidConfigurationError('sensorChargeSamplingProfile.schemaVersion must be "' +
|
|
128
|
+
SENSOR_CHARGE_SAMPLING_PROFILE_SCHEMA_VERSION +
|
|
129
|
+
'".');
|
|
130
|
+
}
|
|
131
|
+
if (record.scientificStatus !==
|
|
132
|
+
"approximation") {
|
|
133
|
+
throw new InvalidConfigurationError('sensorChargeSamplingProfile.scientificStatus must be "approximation".');
|
|
134
|
+
}
|
|
135
|
+
if (record.photoShotNoiseModel !==
|
|
136
|
+
"poisson" ||
|
|
137
|
+
record.darkShotNoiseModel !==
|
|
138
|
+
"poisson") {
|
|
139
|
+
throw new InvalidConfigurationError("sensorChargeSamplingProfile photo/dark shot-noise models must be Poisson.");
|
|
140
|
+
}
|
|
141
|
+
if (!Array.isArray(record.additionalComponentPolicies)) {
|
|
142
|
+
throw new InvalidConfigurationError("sensorChargeSamplingProfile.additionalComponentPolicies must be an array.");
|
|
143
|
+
}
|
|
144
|
+
const additionalComponentPolicies = record.additionalComponentPolicies.map((entry, index) => {
|
|
145
|
+
const path = "sensorChargeSamplingProfile.additionalComponentPolicies[" +
|
|
146
|
+
index +
|
|
147
|
+
"]";
|
|
148
|
+
const policy = requireRecord(entry, path);
|
|
149
|
+
if (policy.model !==
|
|
150
|
+
"poisson" &&
|
|
151
|
+
policy.model !==
|
|
152
|
+
"deterministic-expected-electron-equivalent") {
|
|
153
|
+
throw new InvalidConfigurationError(path +
|
|
154
|
+
".model is invalid.");
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
componentId: requireNonEmptyString(policy.componentId, path +
|
|
158
|
+
".componentId"),
|
|
159
|
+
model: policy.model
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
const ids = additionalComponentPolicies.map((policy) => policy.componentId);
|
|
163
|
+
if (new Set(ids).size !==
|
|
164
|
+
ids.length) {
|
|
165
|
+
throw new InvalidConfigurationError("sensorChargeSamplingProfile.additionalComponentPolicies must not contain duplicate componentId values.");
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
schemaVersion: SENSOR_CHARGE_SAMPLING_PROFILE_SCHEMA_VERSION,
|
|
169
|
+
profileId: requireNonEmptyString(record.profileId, "sensorChargeSamplingProfile.profileId"),
|
|
170
|
+
completenessProfileId: requireNonEmptyString(record.completenessProfileId, "sensorChargeSamplingProfile.completenessProfileId"),
|
|
171
|
+
scientificStatus: "approximation",
|
|
172
|
+
photoShotNoiseModel: "poisson",
|
|
173
|
+
darkShotNoiseModel: "poisson",
|
|
174
|
+
additionalComponentPolicies,
|
|
175
|
+
evidence: parseEvidenceList(record.evidence, "sensorChargeSamplingProfile.evidence"),
|
|
176
|
+
limitations: parseLimitations(record.limitations, "sensorChargeSamplingProfile.limitations")
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function parseStatus(value, path) {
|
|
180
|
+
if (value !== "calibrated" &&
|
|
181
|
+
value !== "approximation") {
|
|
182
|
+
throw new InvalidConfigurationError(path + " is invalid.");
|
|
183
|
+
}
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
function parseReadNoiseComponent(value, path) {
|
|
187
|
+
const record = requireRecord(value, path);
|
|
188
|
+
return {
|
|
189
|
+
componentId: requireNonEmptyString(record.componentId, path + ".componentId"),
|
|
190
|
+
rmsElectrons: parseNonNegativeFact(record.rmsElectrons, path + ".rmsElectrons"),
|
|
191
|
+
evidence: parseEvidenceList(record.evidence, path + ".evidence")
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function parseRegime(value, path) {
|
|
195
|
+
const record = requireRecord(value, path);
|
|
196
|
+
const adc = requireRecord(record.adc, path + ".adc");
|
|
197
|
+
const bitDepth = requireSafeInteger(adc.bitDepth, path + ".adc.bitDepth");
|
|
198
|
+
if (bitDepth < 1 ||
|
|
199
|
+
bitDepth > 30) {
|
|
200
|
+
throw new InvalidConfigurationError(path +
|
|
201
|
+
".adc.bitDepth must be from 1 through 30.");
|
|
202
|
+
}
|
|
203
|
+
const adcMaximumCode = 2 ** bitDepth - 1;
|
|
204
|
+
const blackLevelCode = requireSafeInteger(adc.blackLevelCode, path + ".adc.blackLevelCode");
|
|
205
|
+
const digitalSaturationCode = requireSafeInteger(adc.digitalSaturationCode, path +
|
|
206
|
+
".adc.digitalSaturationCode");
|
|
207
|
+
if (blackLevelCode < 0 ||
|
|
208
|
+
blackLevelCode >
|
|
209
|
+
adcMaximumCode) {
|
|
210
|
+
throw new InvalidConfigurationError(path +
|
|
211
|
+
".adc.blackLevelCode must lie inside the unsigned ADC code range.");
|
|
212
|
+
}
|
|
213
|
+
if (digitalSaturationCode <=
|
|
214
|
+
blackLevelCode ||
|
|
215
|
+
digitalSaturationCode >
|
|
216
|
+
adcMaximumCode) {
|
|
217
|
+
throw new InvalidConfigurationError(path +
|
|
218
|
+
".adc.digitalSaturationCode must be greater than blackLevelCode and at most the ADC maximum code.");
|
|
219
|
+
}
|
|
220
|
+
if (adc.transfer !==
|
|
221
|
+
"uniform-round-half-up") {
|
|
222
|
+
throw new InvalidConfigurationError(path +
|
|
223
|
+
'.adc.transfer must be "uniform-round-half-up".');
|
|
224
|
+
}
|
|
225
|
+
if (!Array.isArray(record.readNoiseComponents)) {
|
|
226
|
+
throw new InvalidConfigurationError(path +
|
|
227
|
+
".readNoiseComponents must be an array.");
|
|
228
|
+
}
|
|
229
|
+
const readNoiseComponents = record.readNoiseComponents.map((entry, index) => parseReadNoiseComponent(entry, path +
|
|
230
|
+
".readNoiseComponents[" +
|
|
231
|
+
index +
|
|
232
|
+
"]"));
|
|
233
|
+
const componentIds = readNoiseComponents.map((entry) => entry.componentId);
|
|
234
|
+
if (new Set(componentIds).size !==
|
|
235
|
+
componentIds.length) {
|
|
236
|
+
throw new InvalidConfigurationError(path +
|
|
237
|
+
".readNoiseComponents must not contain duplicate componentId values.");
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
regimeId: requireNonEmptyString(record.regimeId, path + ".regimeId"),
|
|
241
|
+
scientificStatus: parseStatus(record.scientificStatus, path +
|
|
242
|
+
".scientificStatus"),
|
|
243
|
+
systemConversionGainElectronsPerCode: parsePositiveFact(record
|
|
244
|
+
.systemConversionGainElectronsPerCode, path +
|
|
245
|
+
".systemConversionGainElectronsPerCode"),
|
|
246
|
+
preAdcSaturationElectronEquivalent: parsePositiveFact(record
|
|
247
|
+
.preAdcSaturationElectronEquivalent, path +
|
|
248
|
+
".preAdcSaturationElectronEquivalent"),
|
|
249
|
+
readNoiseComponents,
|
|
250
|
+
adc: {
|
|
251
|
+
bitDepth,
|
|
252
|
+
blackLevelCode,
|
|
253
|
+
digitalSaturationCode,
|
|
254
|
+
transfer: "uniform-round-half-up"
|
|
255
|
+
},
|
|
256
|
+
evidence: parseEvidenceList(record.evidence, path + ".evidence"),
|
|
257
|
+
limitations: parseLimitations(record.limitations, path + ".limitations")
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
|
|
262
|
+
* missing required fields and incompatible scientific data fail at this boundary.
|
|
263
|
+
*
|
|
264
|
+
* Signal ordering is expected charge → independent seeded photo/dark draws → signed electronic read
|
|
265
|
+
* noise → upper pre-ADC threshold → black pedestal → nearest-half-up ADC quantization → unsigned code
|
|
266
|
+
* limits. Signed below-black values survive until the final code clamp. Physical storage saturation,
|
|
267
|
+
* pre-ADC clipping and digital clipping have distinct diagnostics; ISO never invents a conversion
|
|
268
|
+
* regime.
|
|
269
|
+
* @param value - unknown. Treated as untrusted data; static typing alone is not validation.
|
|
270
|
+
* @returns SensorReadoutConversionProfile. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
271
|
+
*
|
|
272
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
273
|
+
*/
|
|
274
|
+
export function parseSensorReadoutConversionProfile(value) {
|
|
275
|
+
const record = requireRecord(value, "sensorReadoutConversionProfile");
|
|
276
|
+
if (record.schemaVersion !==
|
|
277
|
+
SENSOR_READOUT_CONVERSION_PROFILE_SCHEMA_VERSION) {
|
|
278
|
+
throw new InvalidConfigurationError('sensorReadoutConversionProfile.schemaVersion must be "' +
|
|
279
|
+
SENSOR_READOUT_CONVERSION_PROFILE_SCHEMA_VERSION +
|
|
280
|
+
'".');
|
|
281
|
+
}
|
|
282
|
+
if (record.regimeSelectionOwnedBy !==
|
|
283
|
+
"explicit-upstream-camera-state-not-inferred-from-iso") {
|
|
284
|
+
throw new InvalidConfigurationError('sensorReadoutConversionProfile.regimeSelectionOwnedBy must be "explicit-upstream-camera-state-not-inferred-from-iso".');
|
|
285
|
+
}
|
|
286
|
+
if (!Array.isArray(record.regimes) ||
|
|
287
|
+
record.regimes.length === 0) {
|
|
288
|
+
throw new InvalidConfigurationError("sensorReadoutConversionProfile.regimes must be a non-empty array.");
|
|
289
|
+
}
|
|
290
|
+
const regimes = record.regimes.map((entry, index) => parseRegime(entry, "sensorReadoutConversionProfile.regimes[" +
|
|
291
|
+
index +
|
|
292
|
+
"]"));
|
|
293
|
+
const ids = regimes.map((regime) => regime.regimeId);
|
|
294
|
+
if (new Set(ids).size !==
|
|
295
|
+
ids.length) {
|
|
296
|
+
throw new InvalidConfigurationError("sensorReadoutConversionProfile.regimes must not contain duplicate regimeId values.");
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
schemaVersion: SENSOR_READOUT_CONVERSION_PROFILE_SCHEMA_VERSION,
|
|
300
|
+
profileId: requireNonEmptyString(record.profileId, "sensorReadoutConversionProfile.profileId"),
|
|
301
|
+
colorSamplingProfileId: requireNonEmptyString(record.colorSamplingProfileId, "sensorReadoutConversionProfile.colorSamplingProfileId"),
|
|
302
|
+
channelId: requireNonEmptyString(record.channelId, "sensorReadoutConversionProfile.channelId"),
|
|
303
|
+
regimes,
|
|
304
|
+
regimeSelectionOwnedBy: "explicit-upstream-camera-state-not-inferred-from-iso",
|
|
305
|
+
evidence: parseEvidenceList(record.evidence, "sensorReadoutConversionProfile.evidence")
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Select and validate a declared readout regime against exact channel/profile identity rather than
|
|
310
|
+
* inferring it from ISO.
|
|
311
|
+
*
|
|
312
|
+
* Signal ordering is expected charge → independent seeded photo/dark draws → signed electronic read
|
|
313
|
+
* noise → upper pre-ADC threshold → black pedestal → nearest-half-up ADC quantization → unsigned code
|
|
314
|
+
* limits. Signed below-black values survive until the final code clamp. Physical storage saturation,
|
|
315
|
+
* pre-ADC clipping and digital clipping have distinct diagnostics; ISO never invents a conversion
|
|
316
|
+
* regime.
|
|
317
|
+
* @param input - ResolveSensorReadoutRegimeInput. See the linked contract for coordinate, unit and profile binding semantics.
|
|
318
|
+
* @returns ResolvedSensorReadoutRegime. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
319
|
+
*
|
|
320
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
321
|
+
*/
|
|
322
|
+
export function resolveSensorReadoutRegime(input) {
|
|
323
|
+
const profile = parseSensorReadoutConversionProfile(input.profile);
|
|
324
|
+
if (typeof input.regimeId !==
|
|
325
|
+
"string" ||
|
|
326
|
+
input.regimeId.trim().length ===
|
|
327
|
+
0) {
|
|
328
|
+
throw new InvalidScientificInputError("regimeId must be a non-empty string.");
|
|
329
|
+
}
|
|
330
|
+
const regimeId = input.regimeId.trim();
|
|
331
|
+
const regime = profile.regimes.find((entry) => entry.regimeId === regimeId);
|
|
332
|
+
if (regime === undefined) {
|
|
333
|
+
throw new InvalidScientificInputError("regimeId is not declared by the sensor readout conversion profile.");
|
|
334
|
+
}
|
|
335
|
+
const combinedReadNoiseRmsElectrons = Math.sqrt(regime.readNoiseComponents.reduce((sum, component) => sum +
|
|
336
|
+
component
|
|
337
|
+
.rmsElectrons.value *
|
|
338
|
+
component
|
|
339
|
+
.rmsElectrons.value, 0));
|
|
340
|
+
return {
|
|
341
|
+
profileId: profile.profileId,
|
|
342
|
+
colorSamplingProfileId: profile.colorSamplingProfileId,
|
|
343
|
+
channelId: profile.channelId,
|
|
344
|
+
regime,
|
|
345
|
+
regimeSelectionOwnedBy: profile
|
|
346
|
+
.regimeSelectionOwnedBy,
|
|
347
|
+
adcMaximumCode: 2 **
|
|
348
|
+
regime.adc.bitDepth -
|
|
349
|
+
1,
|
|
350
|
+
combinedReadNoiseRmsElectrons
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function validateChargeIdentity(charge, capacity, readout) {
|
|
354
|
+
if (charge.completenessProfileId !==
|
|
355
|
+
capacity
|
|
356
|
+
.completenessProfileId ||
|
|
357
|
+
charge.colorSamplingProfileId !==
|
|
358
|
+
capacity
|
|
359
|
+
.colorSamplingProfileId ||
|
|
360
|
+
charge.channelId !==
|
|
361
|
+
capacity.channelId ||
|
|
362
|
+
charge.site.x !==
|
|
363
|
+
capacity.site.x ||
|
|
364
|
+
charge.site.y !==
|
|
365
|
+
capacity.site.y ||
|
|
366
|
+
charge.bindingId !==
|
|
367
|
+
capacity.bindingId) {
|
|
368
|
+
throw new InvalidScientificInputError("Physical capacity assessment identity must match the accumulated charge.");
|
|
369
|
+
}
|
|
370
|
+
if (readout
|
|
371
|
+
.colorSamplingProfileId !==
|
|
372
|
+
charge.colorSamplingProfileId ||
|
|
373
|
+
readout.channelId !==
|
|
374
|
+
charge.channelId) {
|
|
375
|
+
throw new InvalidScientificInputError("Sensor readout profile color/channel identity must match the accumulated charge.");
|
|
376
|
+
}
|
|
377
|
+
if (capacity
|
|
378
|
+
.expectedChargeCapacityStatus ===
|
|
379
|
+
"above-capacity") {
|
|
380
|
+
throw new InvalidScientificInputError("Expected stored charge above physical capacity cannot enter linear expected readout; the actual post-saturation stored charge is not defined by the upstream assessment.");
|
|
381
|
+
}
|
|
382
|
+
if (charge.saturationAssessed !==
|
|
383
|
+
false ||
|
|
384
|
+
charge.adcQuantizationApplied !==
|
|
385
|
+
false ||
|
|
386
|
+
charge.rawCodeValueProduced !==
|
|
387
|
+
false) {
|
|
388
|
+
throw new InvalidScientificInputError("Sensor readout requires the unmodified accumulated-charge result.");
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function additionalPolicyMap(profile, charge) {
|
|
392
|
+
if (profile.completenessProfileId !==
|
|
393
|
+
charge.completenessProfileId) {
|
|
394
|
+
throw new InvalidScientificInputError("Charge sampling profile completenessProfileId must match the accumulated charge.");
|
|
395
|
+
}
|
|
396
|
+
const chargeIds = charge.additionalComponents.map((component) => component.componentId).sort();
|
|
397
|
+
const policyIds = profile
|
|
398
|
+
.additionalComponentPolicies
|
|
399
|
+
.map((policy) => policy.componentId)
|
|
400
|
+
.sort();
|
|
401
|
+
if (chargeIds.length !==
|
|
402
|
+
policyIds.length ||
|
|
403
|
+
chargeIds.some((id, index) => id !== policyIds[index])) {
|
|
404
|
+
throw new InvalidScientificInputError("Charge sampling profile must declare exactly one policy for every accumulated additional-charge component.");
|
|
405
|
+
}
|
|
406
|
+
return new Map(profile.additionalComponentPolicies.map((policy) => [
|
|
407
|
+
policy.componentId,
|
|
408
|
+
policy
|
|
409
|
+
]));
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Create the deterministic non-cryptographic xorshift32 stream for one charge or
|
|
413
|
+
* read-noise identity. The XOR mix and nonzero fallback avoid the absorbing zero
|
|
414
|
+
* state. Adding 0.5 before division produces values strictly inside (0,1), so
|
|
415
|
+
* logarithmic Poisson/normal transforms never receive a zero or one endpoint.
|
|
416
|
+
* Changing these mechanics changes realized RAW and requires model/replay review.
|
|
417
|
+
*/
|
|
418
|
+
function createRandom(seedUint32) {
|
|
419
|
+
let state = (seedUint32 ^
|
|
420
|
+
0x9e3779b9) >>>
|
|
421
|
+
0;
|
|
422
|
+
if (state === 0) {
|
|
423
|
+
state =
|
|
424
|
+
0x6d2b79f5;
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
next() {
|
|
428
|
+
state ^= state << 13;
|
|
429
|
+
state ^= state >>> 17;
|
|
430
|
+
state ^= state << 5;
|
|
431
|
+
state >>>= 0;
|
|
432
|
+
return ((state + 0.5) /
|
|
433
|
+
0x1_0000_0000);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Compute log(n!) without materializing an overflowing factorial. Small integer
|
|
439
|
+
* counts sum logarithms directly; larger counts use the stated Stirling correction
|
|
440
|
+
* terms 1/(12n) - 1/(360n³). This is internal to the Poisson rejection calculation,
|
|
441
|
+
* not an independent physical accuracy or uncertainty claim.
|
|
442
|
+
*/
|
|
443
|
+
function logFactorial(n) {
|
|
444
|
+
if (n < 2) {
|
|
445
|
+
return 0;
|
|
446
|
+
}
|
|
447
|
+
if (n < 256) {
|
|
448
|
+
let sum = 0;
|
|
449
|
+
for (let value = 2; value <= n; value += 1) {
|
|
450
|
+
sum += Math.log(value);
|
|
451
|
+
}
|
|
452
|
+
return sum;
|
|
453
|
+
}
|
|
454
|
+
const inverse = 1 / n;
|
|
455
|
+
const inverseCubed = inverse * inverse * inverse;
|
|
456
|
+
return ((n + 0.5) * Math.log(n) -
|
|
457
|
+
n +
|
|
458
|
+
0.5 *
|
|
459
|
+
Math.log(2 * Math.PI) +
|
|
460
|
+
inverse / 12 -
|
|
461
|
+
inverseCubed / 360);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Sample a nonnegative integer from the declared Poisson expectation. Zero mean
|
|
465
|
+
* returns exactly zero. Below mean 30, multiply uniforms until the exponential
|
|
466
|
+
* threshold is crossed; larger means use transformed rejection and compare log
|
|
467
|
+
* probabilities to avoid overflow. The same mean and stream reproduce a draw;
|
|
468
|
+
* changing means does not guarantee monotonic individual samples.
|
|
469
|
+
*/
|
|
470
|
+
function samplePoisson(mean, random) {
|
|
471
|
+
if (!Number.isFinite(mean) ||
|
|
472
|
+
mean < 0) {
|
|
473
|
+
throw new InvalidScientificInputError("Poisson mean must be finite and nonnegative.");
|
|
474
|
+
}
|
|
475
|
+
if (mean === 0) {
|
|
476
|
+
return 0;
|
|
477
|
+
}
|
|
478
|
+
if (mean < 30) {
|
|
479
|
+
const threshold = Math.exp(-mean);
|
|
480
|
+
let product = 1;
|
|
481
|
+
let count = 0;
|
|
482
|
+
do {
|
|
483
|
+
count += 1;
|
|
484
|
+
product *=
|
|
485
|
+
random.next();
|
|
486
|
+
} while (product > threshold);
|
|
487
|
+
return count - 1;
|
|
488
|
+
}
|
|
489
|
+
const sqrtMean = Math.sqrt(mean);
|
|
490
|
+
const b = 0.931 +
|
|
491
|
+
2.53 * sqrtMean;
|
|
492
|
+
const a = -0.059 +
|
|
493
|
+
0.02483 * b;
|
|
494
|
+
const inverseAlpha = 1.1239 +
|
|
495
|
+
1.1328 /
|
|
496
|
+
(b - 3.4);
|
|
497
|
+
const vR = 0.9277 -
|
|
498
|
+
3.6224 /
|
|
499
|
+
(b - 2);
|
|
500
|
+
for (;;) {
|
|
501
|
+
const u = random.next() - 0.5;
|
|
502
|
+
const v = random.next();
|
|
503
|
+
const uS = 0.5 - Math.abs(u);
|
|
504
|
+
if (uS <= 0) {
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
const k = Math.floor((2 * a / uS + b) *
|
|
508
|
+
u +
|
|
509
|
+
mean +
|
|
510
|
+
0.43);
|
|
511
|
+
if (uS >= 0.07 &&
|
|
512
|
+
v <= vR &&
|
|
513
|
+
k >= 0) {
|
|
514
|
+
return k;
|
|
515
|
+
}
|
|
516
|
+
if (k < 0 ||
|
|
517
|
+
(uS < 0.013 &&
|
|
518
|
+
v > uS)) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
const lhs = Math.log(v *
|
|
522
|
+
inverseAlpha /
|
|
523
|
+
(a /
|
|
524
|
+
(uS * uS) +
|
|
525
|
+
b));
|
|
526
|
+
const rhs = -mean +
|
|
527
|
+
k * Math.log(mean) -
|
|
528
|
+
logFactorial(k);
|
|
529
|
+
if (lhs <= rhs) {
|
|
530
|
+
return k;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Box–Muller transform of two open-interval uniforms. Each call consumes two
|
|
536
|
+
* values and returns one signed unit-normal sample; no cached partner changes the
|
|
537
|
+
* seed schedule. Electronic noise is allowed to be negative before pedestal/ADC.
|
|
538
|
+
*/
|
|
539
|
+
function sampleStandardNormal(random) {
|
|
540
|
+
const u1 = random.next();
|
|
541
|
+
const u2 = random.next();
|
|
542
|
+
return (Math.sqrt(-2 * Math.log(u1)) *
|
|
543
|
+
Math.cos(2 * Math.PI * u2));
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Draw deterministic independently seeded photo/dark Poisson counts and explicit additional-component
|
|
547
|
+
* policies from expected accumulated charge.
|
|
548
|
+
*
|
|
549
|
+
* Signal ordering is expected charge → independent seeded photo/dark draws → signed electronic read
|
|
550
|
+
* noise → upper pre-ADC threshold → black pedestal → nearest-half-up ADC quantization → unsigned code
|
|
551
|
+
* limits. Signed below-black values survive until the final code clamp. Physical storage saturation,
|
|
552
|
+
* pre-ADC clipping and digital clipping have distinct diagnostics; ISO never invents a conversion
|
|
553
|
+
* regime.
|
|
554
|
+
* @param input - SimulateSensorChargeRealizationInput. See the linked contract for coordinate, unit and profile binding semantics.
|
|
555
|
+
* @returns CalculationResult<SensorChargeRealization>. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
556
|
+
*
|
|
557
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
558
|
+
*/
|
|
559
|
+
export function simulateSensorChargeRealization(input) {
|
|
560
|
+
const profile = parseSensorChargeSamplingProfile(input.samplingProfile);
|
|
561
|
+
const seed = requireUint32(input.seedUint32, "seedUint32");
|
|
562
|
+
const charge = input.accumulatedCharge;
|
|
563
|
+
if (charge.accumulatedChargeCompleteness !==
|
|
564
|
+
"complete-for-physical-storage-capacity-assessment" ||
|
|
565
|
+
charge.saturationAssessed !==
|
|
566
|
+
false ||
|
|
567
|
+
charge.adcQuantizationApplied !==
|
|
568
|
+
false ||
|
|
569
|
+
charge.rawCodeValueProduced !==
|
|
570
|
+
false) {
|
|
571
|
+
throw new InvalidScientificInputError("Charge realization requires a complete unsaturated pre-readout accumulated-charge result.");
|
|
572
|
+
}
|
|
573
|
+
const policies = additionalPolicyMap(profile, charge);
|
|
574
|
+
const random = createRandom(seed);
|
|
575
|
+
const photoRealized = samplePoisson(charge
|
|
576
|
+
.photoExpectedElectronCount, random);
|
|
577
|
+
const darkRealized = samplePoisson(charge
|
|
578
|
+
.darkExpectedElectronCount, random);
|
|
579
|
+
const additionalComponents = charge.additionalComponents.map((component) => {
|
|
580
|
+
const policy = policies.get(component.componentId);
|
|
581
|
+
const realized = policy.model ===
|
|
582
|
+
"poisson"
|
|
583
|
+
? samplePoisson(component
|
|
584
|
+
.expectedElectronCount, random)
|
|
585
|
+
: component
|
|
586
|
+
.expectedElectronCount;
|
|
587
|
+
return {
|
|
588
|
+
componentId: component.componentId,
|
|
589
|
+
expectedElectronCount: component
|
|
590
|
+
.expectedElectronCount,
|
|
591
|
+
realizedElectronEquivalentCount: realized,
|
|
592
|
+
model: policy.model
|
|
593
|
+
};
|
|
594
|
+
});
|
|
595
|
+
const additionalRealized = additionalComponents.reduce((sum, component) => sum +
|
|
596
|
+
component
|
|
597
|
+
.realizedElectronEquivalentCount, 0);
|
|
598
|
+
const totalRealized = photoRealized +
|
|
599
|
+
darkRealized +
|
|
600
|
+
additionalRealized;
|
|
601
|
+
if (!Number.isFinite(totalRealized) ||
|
|
602
|
+
totalRealized < 0) {
|
|
603
|
+
throw new InvalidScientificInputError("Realized stored charge must remain finite and nonnegative.");
|
|
604
|
+
}
|
|
605
|
+
return approximationResult({
|
|
606
|
+
samplingProfileId: profile.profileId,
|
|
607
|
+
completenessProfileId: charge
|
|
608
|
+
.completenessProfileId,
|
|
609
|
+
colorSamplingProfileId: charge
|
|
610
|
+
.colorSamplingProfileId,
|
|
611
|
+
channelId: charge.channelId,
|
|
612
|
+
site: {
|
|
613
|
+
...charge.site
|
|
614
|
+
},
|
|
615
|
+
bindingId: charge.bindingId,
|
|
616
|
+
seedUint32: seed,
|
|
617
|
+
photoExpectedElectronCount: charge
|
|
618
|
+
.photoExpectedElectronCount,
|
|
619
|
+
photoRealizedElectronCount: photoRealized,
|
|
620
|
+
darkExpectedElectronCount: charge
|
|
621
|
+
.darkExpectedElectronCount,
|
|
622
|
+
darkRealizedElectronCount: darkRealized,
|
|
623
|
+
additionalComponents,
|
|
624
|
+
totalExpectedStoredElectronCount: charge
|
|
625
|
+
.totalExpectedStoredElectronCount,
|
|
626
|
+
totalRealizedStoredElectronEquivalentCount: totalRealized,
|
|
627
|
+
photoShotNoiseApplied: true,
|
|
628
|
+
darkShotNoiseApplied: true,
|
|
629
|
+
electronicReadNoiseApplied: false,
|
|
630
|
+
physicalSaturationApplied: false,
|
|
631
|
+
bloomingModeled: false,
|
|
632
|
+
conversionGainApplied: false,
|
|
633
|
+
adcQuantizationApplied: false,
|
|
634
|
+
rawCodeValueProduced: false,
|
|
635
|
+
stochasticModel: "independent-poisson-photo-dark-explicit-additional-policy",
|
|
636
|
+
deterministicSeededRealization: true
|
|
637
|
+
}, "sensor-charge-stochastic-realization", "1.0.0", [
|
|
638
|
+
"Photo-generated and dark-generated electron counts are sampled independently from Poisson distributions using an explicit deterministic seed.",
|
|
639
|
+
"Each additional stored-charge component uses its explicitly declared Poisson or deterministic electron-equivalent policy; Photivra does not infer defect/leakage statistics from the component name.",
|
|
640
|
+
"This is a pre-saturation, pre-electronic-read-noise charge realization and remains separate from expectation-value calculations.",
|
|
641
|
+
"The seeded PRNG is a deterministic simulation mechanism and is not cryptographically secure."
|
|
642
|
+
]);
|
|
643
|
+
}
|
|
644
|
+
function validateCapacityAgainstRealization(charge, capacity, readout) {
|
|
645
|
+
if (charge.completenessProfileId !==
|
|
646
|
+
capacity
|
|
647
|
+
.completenessProfileId ||
|
|
648
|
+
charge.colorSamplingProfileId !==
|
|
649
|
+
capacity
|
|
650
|
+
.colorSamplingProfileId ||
|
|
651
|
+
charge.channelId !==
|
|
652
|
+
capacity.channelId ||
|
|
653
|
+
charge.site.x !==
|
|
654
|
+
capacity.site.x ||
|
|
655
|
+
charge.site.y !==
|
|
656
|
+
capacity.site.y ||
|
|
657
|
+
charge.bindingId !==
|
|
658
|
+
capacity.bindingId) {
|
|
659
|
+
throw new InvalidScientificInputError("Physical capacity assessment identity must match the charge realization.");
|
|
660
|
+
}
|
|
661
|
+
if (readout
|
|
662
|
+
.colorSamplingProfileId !==
|
|
663
|
+
charge.colorSamplingProfileId ||
|
|
664
|
+
readout.channelId !==
|
|
665
|
+
charge.channelId) {
|
|
666
|
+
throw new InvalidScientificInputError("Sensor readout profile color/channel identity must match the charge realization.");
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Map expected charge through declared gain/offset/readout limits without stochastic sampling and
|
|
671
|
+
* retain separate clipping domains.
|
|
672
|
+
*
|
|
673
|
+
* Signal ordering is expected charge → independent seeded photo/dark draws → signed electronic read
|
|
674
|
+
* noise → upper pre-ADC threshold → black pedestal → nearest-half-up ADC quantization → unsigned code
|
|
675
|
+
* limits. Signed below-black values survive until the final code clamp. Physical storage saturation,
|
|
676
|
+
* pre-ADC clipping and digital clipping have distinct diagnostics; ISO never invents a conversion
|
|
677
|
+
* regime.
|
|
678
|
+
* @param input - CalculateExpectedSensorReadoutInput. See the linked contract for coordinate, unit and profile binding semantics.
|
|
679
|
+
* @returns CalculationResult<SensorExpectedReadoutSignal>. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
680
|
+
*
|
|
681
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
682
|
+
*/
|
|
683
|
+
export function calculateExpectedSensorReadout(input) {
|
|
684
|
+
const readout = resolveSensorReadoutRegime({
|
|
685
|
+
profile: input.readoutProfile,
|
|
686
|
+
regimeId: input.regimeId
|
|
687
|
+
});
|
|
688
|
+
validateChargeIdentity(input.accumulatedCharge, input
|
|
689
|
+
.physicalCapacityAssessment, readout);
|
|
690
|
+
const expected = input.accumulatedCharge
|
|
691
|
+
.totalExpectedStoredElectronCount;
|
|
692
|
+
const threshold = readout.regime
|
|
693
|
+
.preAdcSaturationElectronEquivalent
|
|
694
|
+
.value;
|
|
695
|
+
const afterPreAdc = Math.min(expected, threshold);
|
|
696
|
+
const codeSignal = afterPreAdc /
|
|
697
|
+
readout.regime
|
|
698
|
+
.systemConversionGainElectronsPerCode
|
|
699
|
+
.value;
|
|
700
|
+
const codeBeforeQuantization = codeSignal +
|
|
701
|
+
readout.regime
|
|
702
|
+
.adc.blackLevelCode;
|
|
703
|
+
return approximationResult({
|
|
704
|
+
readoutProfileId: readout.profileId,
|
|
705
|
+
regimeId: readout.regime
|
|
706
|
+
.regimeId,
|
|
707
|
+
completenessProfileId: input.accumulatedCharge
|
|
708
|
+
.completenessProfileId,
|
|
709
|
+
capacityProfileId: input
|
|
710
|
+
.physicalCapacityAssessment
|
|
711
|
+
.capacityProfileId,
|
|
712
|
+
colorSamplingProfileId: input.accumulatedCharge
|
|
713
|
+
.colorSamplingProfileId,
|
|
714
|
+
channelId: input.accumulatedCharge
|
|
715
|
+
.channelId,
|
|
716
|
+
site: {
|
|
717
|
+
...input
|
|
718
|
+
.accumulatedCharge
|
|
719
|
+
.site
|
|
720
|
+
},
|
|
721
|
+
bindingId: input.accumulatedCharge
|
|
722
|
+
.bindingId,
|
|
723
|
+
expectedStoredElectronCount: expected,
|
|
724
|
+
expectedStoredChargeBelowOrAtPhysicalCapacity: true,
|
|
725
|
+
expectedElectronEquivalentAfterPreAdcSaturation: afterPreAdc,
|
|
726
|
+
preAdcSaturationAppliedToExpectation: afterPreAdc < expected,
|
|
727
|
+
systemConversionGainElectronsPerCode: readout.regime
|
|
728
|
+
.systemConversionGainElectronsPerCode
|
|
729
|
+
.value,
|
|
730
|
+
expectedCodeBeforeBlackOffset: codeSignal,
|
|
731
|
+
blackLevelCode: readout.regime
|
|
732
|
+
.adc.blackLevelCode,
|
|
733
|
+
expectedCodeBeforeQuantization: codeBeforeQuantization,
|
|
734
|
+
adcBitDepth: readout.regime
|
|
735
|
+
.adc.bitDepth,
|
|
736
|
+
adcMaximumCode: readout.adcMaximumCode,
|
|
737
|
+
digitalSaturationCode: readout.regime
|
|
738
|
+
.adc
|
|
739
|
+
.digitalSaturationCode,
|
|
740
|
+
expectedDigitalSaturation: codeBeforeQuantization >=
|
|
741
|
+
readout.regime
|
|
742
|
+
.adc
|
|
743
|
+
.digitalSaturationCode,
|
|
744
|
+
electronicReadNoiseMeanElectrons: 0,
|
|
745
|
+
electronicReadNoiseRmsElectrons: readout
|
|
746
|
+
.combinedReadNoiseRmsElectrons,
|
|
747
|
+
electronicReadNoiseSampled: false,
|
|
748
|
+
adcQuantizationApplied: false,
|
|
749
|
+
rawCodeValueProduced: false,
|
|
750
|
+
isoUsedToInferRegime: false
|
|
751
|
+
}, "sensor-expected-electronic-readout", "1.0.0", [
|
|
752
|
+
"Expected readout uses complete expected stored charge only after the upstream physical-capacity assessment confirms the expectation is not above physical capacity.",
|
|
753
|
+
"Electronic read-noise mean is zero and is not sampled in this expectation result.",
|
|
754
|
+
"The explicitly selected conversion regime is not inferred from ISO, sensor technology family or marketing mode names.",
|
|
755
|
+
"Pre-ADC electron-equivalent saturation, black offset and ADC/digital saturation remain separate domains.",
|
|
756
|
+
"ADC quantization is not applied to the expectation value."
|
|
757
|
+
]);
|
|
758
|
+
}
|
|
759
|
+
function roundHalfUp(value) {
|
|
760
|
+
return Math.floor(value + 0.5);
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Use the declared seed/regime to preserve signed electronic noise through pedestal and quantization,
|
|
764
|
+
* then return the bounded native ADC code and stage diagnostics.
|
|
765
|
+
*
|
|
766
|
+
* Signal ordering is expected charge → independent seeded photo/dark draws → signed electronic read
|
|
767
|
+
* noise → upper pre-ADC threshold → black pedestal → nearest-half-up ADC quantization → unsigned code
|
|
768
|
+
* limits. Signed below-black values survive until the final code clamp. Physical storage saturation,
|
|
769
|
+
* pre-ADC clipping and digital clipping have distinct diagnostics; ISO never invents a conversion
|
|
770
|
+
* regime.
|
|
771
|
+
* @param input - SimulateSensorRawCodeInput. See the linked contract for coordinate, unit and profile binding semantics.
|
|
772
|
+
* @returns CalculationResult<SensorRawCodeSample>. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
773
|
+
*
|
|
774
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
775
|
+
*/
|
|
776
|
+
export function simulateSensorRawCode(input) {
|
|
777
|
+
const readout = resolveSensorReadoutRegime({
|
|
778
|
+
profile: input.readoutProfile,
|
|
779
|
+
regimeId: input.regimeId
|
|
780
|
+
});
|
|
781
|
+
validateCapacityAgainstRealization(input.chargeRealization, input
|
|
782
|
+
.physicalCapacityAssessment, readout);
|
|
783
|
+
const readNoiseSeed = requireUint32(input.readNoiseSeedUint32, "readNoiseSeedUint32");
|
|
784
|
+
const random = createRandom(readNoiseSeed);
|
|
785
|
+
const realized = input.chargeRealization
|
|
786
|
+
.totalRealizedStoredElectronEquivalentCount;
|
|
787
|
+
if (!Number.isFinite(realized) ||
|
|
788
|
+
realized < 0) {
|
|
789
|
+
throw new InvalidScientificInputError("Charge realization total must be finite and nonnegative.");
|
|
790
|
+
}
|
|
791
|
+
const physicalCapacity = input
|
|
792
|
+
.physicalCapacityAssessment
|
|
793
|
+
.physicalChargeCapacityElectrons;
|
|
794
|
+
const afterPhysical = Math.min(realized, physicalCapacity);
|
|
795
|
+
const physicalSaturation = afterPhysical < realized;
|
|
796
|
+
const overflow = Math.max(0, realized -
|
|
797
|
+
physicalCapacity);
|
|
798
|
+
const readNoiseComponents = readout.regime
|
|
799
|
+
.readNoiseComponents.map((component) => {
|
|
800
|
+
const sampled = component
|
|
801
|
+
.rmsElectrons.value ===
|
|
802
|
+
0
|
|
803
|
+
? 0
|
|
804
|
+
: sampleStandardNormal(random) *
|
|
805
|
+
component
|
|
806
|
+
.rmsElectrons.value;
|
|
807
|
+
return {
|
|
808
|
+
componentId: component
|
|
809
|
+
.componentId,
|
|
810
|
+
rmsElectrons: component
|
|
811
|
+
.rmsElectrons
|
|
812
|
+
.value,
|
|
813
|
+
sampledElectrons: sampled
|
|
814
|
+
};
|
|
815
|
+
});
|
|
816
|
+
const totalReadNoise = readNoiseComponents.reduce((sum, component) => sum +
|
|
817
|
+
component
|
|
818
|
+
.sampledElectrons, 0);
|
|
819
|
+
const afterReadNoise = afterPhysical +
|
|
820
|
+
totalReadNoise;
|
|
821
|
+
const preAdcThreshold = readout.regime
|
|
822
|
+
.preAdcSaturationElectronEquivalent
|
|
823
|
+
.value;
|
|
824
|
+
// Stored charge is nonnegative; the downstream electronic signal is signed.
|
|
825
|
+
// Preserve negative read noise until the black pedestal and unsigned ADC boundary.
|
|
826
|
+
const afterPreAdc = Math.min(afterReadNoise, preAdcThreshold);
|
|
827
|
+
const preAdcSaturation = afterReadNoise >
|
|
828
|
+
preAdcThreshold;
|
|
829
|
+
const codeBeforeQuantization = afterPreAdc /
|
|
830
|
+
readout.regime
|
|
831
|
+
.systemConversionGainElectronsPerCode
|
|
832
|
+
.value +
|
|
833
|
+
readout.regime
|
|
834
|
+
.adc.blackLevelCode;
|
|
835
|
+
const quantized = roundHalfUp(codeBeforeQuantization);
|
|
836
|
+
const rawCode = Math.max(0, Math.min(quantized, readout.regime
|
|
837
|
+
.adc
|
|
838
|
+
.digitalSaturationCode));
|
|
839
|
+
return approximationResult({
|
|
840
|
+
readoutProfileId: readout.profileId,
|
|
841
|
+
regimeId: readout.regime
|
|
842
|
+
.regimeId,
|
|
843
|
+
samplingProfileId: input.chargeRealization
|
|
844
|
+
.samplingProfileId,
|
|
845
|
+
completenessProfileId: input.chargeRealization
|
|
846
|
+
.completenessProfileId,
|
|
847
|
+
capacityProfileId: input
|
|
848
|
+
.physicalCapacityAssessment
|
|
849
|
+
.capacityProfileId,
|
|
850
|
+
colorSamplingProfileId: input.chargeRealization
|
|
851
|
+
.colorSamplingProfileId,
|
|
852
|
+
channelId: input.chargeRealization
|
|
853
|
+
.channelId,
|
|
854
|
+
site: {
|
|
855
|
+
...input
|
|
856
|
+
.chargeRealization.site
|
|
857
|
+
},
|
|
858
|
+
bindingId: input.chargeRealization
|
|
859
|
+
.bindingId,
|
|
860
|
+
chargeSeedUint32: input.chargeRealization
|
|
861
|
+
.seedUint32,
|
|
862
|
+
readNoiseSeedUint32: readNoiseSeed,
|
|
863
|
+
realizedStoredElectronEquivalentCountBeforePhysicalCapacity: realized,
|
|
864
|
+
physicalChargeCapacityElectrons: physicalCapacity,
|
|
865
|
+
electronEquivalentAfterPhysicalScalarSaturation: afterPhysical,
|
|
866
|
+
physicalScalarSaturationApplied: physicalSaturation,
|
|
867
|
+
overflowElectronEquivalentDiagnostic: overflow,
|
|
868
|
+
bloomingModeled: false,
|
|
869
|
+
electronicReadNoiseComponents: readNoiseComponents,
|
|
870
|
+
totalElectronicReadNoiseElectrons: totalReadNoise,
|
|
871
|
+
electronEquivalentAfterReadNoise: afterReadNoise,
|
|
872
|
+
preAdcSaturationElectronEquivalent: preAdcThreshold,
|
|
873
|
+
electronEquivalentAfterPreAdcSaturation: afterPreAdc,
|
|
874
|
+
preAdcSaturationApplied: preAdcSaturation,
|
|
875
|
+
systemConversionGainElectronsPerCode: readout.regime
|
|
876
|
+
.systemConversionGainElectronsPerCode
|
|
877
|
+
.value,
|
|
878
|
+
blackLevelCode: readout.regime
|
|
879
|
+
.adc.blackLevelCode,
|
|
880
|
+
codeBeforeQuantization,
|
|
881
|
+
quantizedCodeBeforeDigitalClamp: quantized,
|
|
882
|
+
adcBitDepth: readout.regime
|
|
883
|
+
.adc.bitDepth,
|
|
884
|
+
adcMaximumCode: readout.adcMaximumCode,
|
|
885
|
+
digitalSaturationCode: readout.regime
|
|
886
|
+
.adc
|
|
887
|
+
.digitalSaturationCode,
|
|
888
|
+
rawCode,
|
|
889
|
+
digitalSaturationApplied: quantized >
|
|
890
|
+
readout.regime
|
|
891
|
+
.adc
|
|
892
|
+
.digitalSaturationCode,
|
|
893
|
+
lowerCodeClampApplied: quantized < 0,
|
|
894
|
+
adcTransfer: "uniform-round-half-up",
|
|
895
|
+
physicalSaturationApplied: physicalSaturation,
|
|
896
|
+
electronicReadNoiseApplied: readNoiseComponents
|
|
897
|
+
.some((component) => component
|
|
898
|
+
.rmsElectrons >
|
|
899
|
+
0),
|
|
900
|
+
conversionGainApplied: true,
|
|
901
|
+
adcQuantizationApplied: true,
|
|
902
|
+
rawCodeValueProduced: true,
|
|
903
|
+
isoUsedToInferRegime: false,
|
|
904
|
+
deterministicSeededRealization: true
|
|
905
|
+
}, "sensor-raw-code-stochastic-readout", "2.0.0", [
|
|
906
|
+
"A stochastic stored-charge realization is scalar-clamped at the explicit physical storage capacity; this is a bounded saturation approximation and does not model blooming, neighbor transport or anti-blooming behavior.",
|
|
907
|
+
"Independent input-referred Gaussian electronic read-noise components are sampled after physical charge saturation and before the explicit pre-ADC electron-equivalent saturation threshold.",
|
|
908
|
+
"System conversion gain is expressed in electrons per digital-number code unit for the explicitly selected regime and is not inferred from ISO.",
|
|
909
|
+
"Signed electronic read noise survives the upper-only pre-ADC saturation threshold. Black level is added before uniform round-half-up quantization and clamping to zero/digital saturation; valid below-black codes are retained.",
|
|
910
|
+
"Physical storage capacity, pre-ADC saturation and digital/ADC saturation remain separate thresholds.",
|
|
911
|
+
"The charge seed and read-noise seed are separate deterministic simulation identities; neither is cryptographically secure."
|
|
912
|
+
]);
|
|
913
|
+
}
|
|
914
|
+
//# sourceMappingURL=raw-readout.js.map
|