@photivra/engine 1.4.0 → 2.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/CHANGELOG.md +401 -6
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +64 -12
- package/README.md +301 -182
- package/SECURITY.md +37 -28
- package/THIRD_PARTY.md +148 -4
- package/dist/camera/equivalent-focal-length.d.ts +13 -14
- package/dist/camera/equivalent-focal-length.js +15 -13
- package/dist/camera/equivalent-focal-length.js.map +1 -1
- package/dist/camera/field-of-view.d.ts +30 -19
- package/dist/camera/field-of-view.js +67 -18
- package/dist/camera/field-of-view.js.map +1 -1
- package/dist/camera/lens-projection.d.ts +170 -0
- package/dist/camera/lens-projection.js +444 -0
- package/dist/camera/lens-projection.js.map +1 -0
- package/dist/camera/projected-object-size.d.ts +10 -11
- package/dist/camera/projected-object-size.js +12 -10
- package/dist/camera/projected-object-size.js.map +1 -1
- package/dist/capture/capture-export-metadata.d.ts +9 -10
- package/dist/capture/capture-export-metadata.js +8 -5
- package/dist/capture/capture-export-metadata.js.map +1 -1
- package/dist/capture/dng-import.d.ts +91 -0
- package/dist/capture/dng-import.js +343 -0
- package/dist/capture/dng-import.js.map +1 -0
- package/dist/capture/environment-raw-producer.d.ts +37 -17
- package/dist/capture/environment-raw-producer.js +43 -19
- package/dist/capture/environment-raw-producer.js.map +1 -1
- package/dist/capture/export-jpeg.d.ts +35 -4
- package/dist/capture/export-jpeg.js +133 -47
- package/dist/capture/export-jpeg.js.map +1 -1
- package/dist/capture/export-tiff.d.ts +48 -24
- package/dist/capture/export-tiff.js +91 -31
- package/dist/capture/export-tiff.js.map +1 -1
- package/dist/capture/focus-control.d.ts +42 -65
- package/dist/capture/focus-control.js +56 -75
- package/dist/capture/focus-control.js.map +1 -1
- package/dist/capture/host-yield-cadence.d.ts +25 -0
- package/dist/capture/host-yield-cadence.js +25 -0
- package/dist/capture/host-yield-cadence.js.map +1 -0
- package/dist/capture/linear-encoding.d.ts +14 -12
- package/dist/capture/linear-encoding.js +14 -13
- package/dist/capture/linear-encoding.js.map +1 -1
- package/dist/capture/lossless-jpeg.d.ts +27 -0
- package/dist/capture/lossless-jpeg.js +237 -0
- package/dist/capture/lossless-jpeg.js.map +1 -0
- package/dist/capture/native-environment-lean.d.ts +227 -0
- package/dist/capture/native-environment-lean.js +974 -0
- package/dist/capture/native-environment-lean.js.map +1 -0
- package/dist/capture/native-environment-optical-stage.d.ts +97 -0
- package/dist/capture/native-environment-optical-stage.js +340 -0
- package/dist/capture/native-environment-optical-stage.js.map +1 -0
- package/dist/capture/native-environment-raw.d.ts +140 -6
- package/dist/capture/native-environment-raw.js +435 -34
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/capture/native-raw-development.d.ts +118 -5
- package/dist/capture/native-raw-development.js +224 -59
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/capture/native-raw-dng.d.ts +60 -0
- package/dist/capture/native-raw-dng.js +167 -0
- package/dist/capture/native-raw-dng.js.map +1 -0
- package/dist/capture/native-raw.d.ts +67 -10
- package/dist/capture/native-raw.js +90 -24
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/packed-sensor-raw.d.ts +160 -0
- package/dist/capture/packed-sensor-raw.js +221 -0
- package/dist/capture/packed-sensor-raw.js.map +1 -0
- package/dist/capture/photographic-export.d.ts +58 -35
- package/dist/capture/photographic-export.js +177 -70
- package/dist/capture/photographic-export.js.map +1 -1
- package/dist/capture/raw-development-kernel.d.ts +52 -0
- package/dist/capture/raw-development-kernel.js +88 -0
- package/dist/capture/raw-development-kernel.js.map +1 -0
- package/dist/capture/raw-frame-limits.d.ts +7 -7
- package/dist/capture/raw-frame-limits.js +7 -6
- package/dist/capture/raw-frame-limits.js.map +1 -1
- package/dist/capture/raw-frame-reconstruction.d.ts +8 -9
- package/dist/capture/raw-frame-reconstruction.js +9 -8
- package/dist/capture/raw-frame-reconstruction.js.map +1 -1
- package/dist/capture/raw-white-level.d.ts +55 -0
- package/dist/capture/raw-white-level.js +165 -0
- package/dist/capture/raw-white-level.js.map +1 -0
- package/dist/capture/release-sequence.d.ts +5 -7
- package/dist/capture/release-sequence.js +15 -13
- package/dist/capture/release-sequence.js.map +1 -1
- package/dist/capture/sensor-raw-frame.d.ts +5 -6
- package/dist/capture/sensor-raw-frame.js +26 -9
- package/dist/capture/sensor-raw-frame.js.map +1 -1
- package/dist/capture/sensor-raw-producer.d.ts +21 -13
- package/dist/capture/sensor-raw-producer.js +86 -25
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/capture/simulated-capture.d.ts +15 -16
- package/dist/capture/simulated-capture.js +22 -12
- package/dist/capture/simulated-capture.js.map +1 -1
- package/dist/color/camera-color-matrix.d.ts +69 -0
- package/dist/color/camera-color-matrix.js +132 -0
- package/dist/color/camera-color-matrix.js.map +1 -0
- package/dist/color/capture-color.d.ts +17 -10
- package/dist/color/capture-color.js +50 -17
- package/dist/color/capture-color.js.map +1 -1
- package/dist/color/chromatic-adaptation.d.ts +63 -0
- package/dist/color/chromatic-adaptation.js +91 -0
- package/dist/color/chromatic-adaptation.js.map +1 -0
- package/dist/color/color-difference.d.ts +104 -0
- package/dist/color/color-difference.js +205 -0
- package/dist/color/color-difference.js.map +1 -0
- package/dist/color/color-matching-functions.d.ts +168 -0
- package/dist/color/color-matching-functions.js +309 -0
- package/dist/color/color-matching-functions.js.map +1 -0
- package/dist/color/colorimetry-math.d.ts +52 -0
- package/dist/color/colorimetry-math.js +144 -0
- package/dist/color/colorimetry-math.js.map +1 -0
- package/dist/color/gamut-mapping.d.ts +54 -0
- package/dist/color/gamut-mapping.js +107 -0
- package/dist/color/gamut-mapping.js.map +1 -0
- package/dist/color/illuminants.d.ts +182 -0
- package/dist/color/illuminants.js +434 -0
- package/dist/color/illuminants.js.map +1 -0
- package/dist/color/rgb-color-spaces.d.ts +79 -0
- package/dist/color/rgb-color-spaces.js +115 -0
- package/dist/color/rgb-color-spaces.js.map +1 -0
- package/dist/color/sensor-color-development.d.ts +33 -11
- package/dist/color/sensor-color-development.js +104 -30
- package/dist/color/sensor-color-development.js.map +1 -1
- package/dist/color/srgb-icc.d.ts +9 -2
- package/dist/color/srgb-icc.js +16 -5
- package/dist/color/srgb-icc.js.map +1 -1
- package/dist/color/srgb-transfer.d.ts +1 -2
- package/dist/color/srgb-transfer.js +1 -1
- package/dist/color/srgb-transfer.js.map +1 -1
- package/dist/color/white-balance.d.ts +68 -19
- package/dist/color/white-balance.js +168 -35
- package/dist/color/white-balance.js.map +1 -1
- package/dist/composition/image-formation-plan.d.ts +152 -128
- package/dist/composition/image-formation-plan.js +292 -138
- package/dist/composition/image-formation-plan.js.map +1 -1
- package/dist/composition/plan-consumer.d.ts +6 -7
- package/dist/composition/plan-consumer.js +14 -11
- package/dist/composition/plan-consumer.js.map +1 -1
- package/dist/core/calculation-result.d.ts +21 -14
- package/dist/core/calculation-result.js +209 -11
- package/dist/core/calculation-result.js.map +1 -1
- package/dist/core/canonical-json.d.ts +13 -8
- package/dist/core/canonical-json.js +34 -15
- package/dist/core/canonical-json.js.map +1 -1
- package/dist/core/configuration-error.d.ts +5 -4
- package/dist/core/configuration-error.js +5 -3
- package/dist/core/configuration-error.js.map +1 -1
- package/dist/core/evidence-provenance.d.ts +12 -12
- package/dist/core/evidence-provenance.js +10 -9
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/image-formation.d.ts +11 -10
- package/dist/core/image-formation.js +11 -9
- package/dist/core/image-formation.js.map +1 -1
- package/dist/core/owned-data.d.ts +9 -17
- package/dist/core/owned-data.js +9 -16
- package/dist/core/owned-data.js.map +1 -1
- package/dist/core/portable-math.d.ts +15 -0
- package/dist/core/portable-math.js +56 -0
- package/dist/core/portable-math.js.map +1 -0
- package/dist/core/record-validation.d.ts +48 -9
- package/dist/core/record-validation.js +93 -19
- package/dist/core/record-validation.js.map +1 -1
- package/dist/core/scientific-assurance.d.ts +16 -14
- package/dist/core/scientific-assurance.js +22 -18
- package/dist/core/scientific-assurance.js.map +1 -1
- package/dist/core/spectral-composition.d.ts +13 -14
- package/dist/core/spectral-composition.js +30 -27
- package/dist/core/spectral-composition.js.map +1 -1
- package/dist/core/spectral.d.ts +5 -6
- package/dist/core/spectral.js +9 -7
- package/dist/core/spectral.js.map +1 -1
- package/dist/core/validation.d.ts +3 -6
- package/dist/core/validation.js +3 -5
- package/dist/core/validation.js.map +1 -1
- package/dist/core/version.d.ts +6 -6
- package/dist/core/version.js +6 -5
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/exposure-capabilities.d.ts +10 -10
- package/dist/equipment/exposure-capabilities.js +40 -30
- package/dist/equipment/exposure-capabilities.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +13 -6
- package/dist/equipment/generic-tier-assets.js +34 -15
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.d.ts +5 -6
- package/dist/equipment/generic-tier-presets.js +15 -13
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/equipment/iso-capabilities.d.ts +21 -22
- package/dist/equipment/iso-capabilities.js +49 -44
- package/dist/equipment/iso-capabilities.js.map +1 -1
- package/dist/equipment/metering-capabilities.d.ts +5 -6
- package/dist/equipment/metering-capabilities.js +22 -19
- package/dist/equipment/metering-capabilities.js.map +1 -1
- package/dist/equipment/release-capabilities.d.ts +3 -4
- package/dist/equipment/release-capabilities.js +18 -14
- package/dist/equipment/release-capabilities.js.map +1 -1
- package/dist/exposure/exposure-duration-control.d.ts +19 -17
- package/dist/exposure/exposure-duration-control.js +27 -23
- package/dist/exposure/exposure-duration-control.js.map +1 -1
- package/dist/exposure/exposure-mode-resolver.d.ts +42 -39
- package/dist/exposure/exposure-mode-resolver.js +127 -82
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/exposure/exposure.d.ts +17 -16
- package/dist/exposure/exposure.js +22 -15
- package/dist/exposure/exposure.js.map +1 -1
- package/dist/exposure/flash-ttl.d.ts +135 -0
- package/dist/exposure/flash-ttl.js +193 -0
- package/dist/exposure/flash-ttl.js.map +1 -0
- package/dist/exposure/flash.d.ts +144 -36
- package/dist/exposure/flash.js +259 -59
- package/dist/exposure/flash.js.map +1 -1
- package/dist/exposure/metering-scene-radiance.d.ts +10 -10
- package/dist/exposure/metering-scene-radiance.js +42 -23
- package/dist/exposure/metering-scene-radiance.js.map +1 -1
- package/dist/exposure/metering-target.d.ts +8 -8
- package/dist/exposure/metering-target.js +30 -20
- package/dist/exposure/metering-target.js.map +1 -1
- package/dist/exposure/metering-temporal.d.ts +16 -15
- package/dist/exposure/metering-temporal.js +41 -19
- package/dist/exposure/metering-temporal.js.map +1 -1
- package/dist/exposure/metering.d.ts +64 -17
- package/dist/exposure/metering.js +159 -30
- package/dist/exposure/metering.js.map +1 -1
- package/dist/exposure/program-line.d.ts +5 -5
- package/dist/exposure/program-line.js +20 -13
- package/dist/exposure/program-line.js.map +1 -1
- package/dist/facade/camera-preset.d.ts +8 -0
- package/dist/facade/camera-preset.js +102 -0
- package/dist/facade/camera-preset.js.map +1 -0
- package/dist/facade/chart-radiance-batch.d.ts +57 -0
- package/dist/facade/chart-radiance-batch.js +121 -0
- package/dist/facade/chart-radiance-batch.js.map +1 -0
- package/dist/facade/chart-scenes.d.ts +177 -0
- package/dist/facade/chart-scenes.js +232 -0
- package/dist/facade/chart-scenes.js.map +1 -0
- package/dist/facade/host-yield.d.ts +7 -0
- package/dist/facade/host-yield.js +23 -0
- package/dist/facade/host-yield.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +117 -0
- package/dist/facade/scene-radiance.js +205 -0
- package/dist/facade/scene-radiance.js.map +1 -0
- package/dist/facade/simulate-capture.d.ts +284 -0
- package/dist/facade/simulate-capture.js +1026 -0
- package/dist/facade/simulate-capture.js.map +1 -0
- package/dist/gpu/chart-radiance-gpu.d.ts +17 -0
- package/dist/gpu/chart-radiance-gpu.js +176 -0
- package/dist/gpu/chart-radiance-gpu.js.map +1 -0
- package/dist/gpu/image-kernel-accelerator.d.ts +132 -0
- package/dist/gpu/image-kernel-accelerator.js +720 -0
- package/dist/gpu/image-kernel-accelerator.js.map +1 -0
- package/dist/gpu/image-kernel-execution.d.ts +92 -0
- package/dist/gpu/image-kernel-execution.js +84 -0
- package/dist/gpu/image-kernel-execution.js.map +1 -0
- package/dist/gpu/sensor-stage-gpu.d.ts +44 -0
- package/dist/gpu/sensor-stage-gpu.js +317 -0
- package/dist/gpu/sensor-stage-gpu.js.map +1 -0
- package/dist/gpu/temporal-sum-gpu.d.ts +23 -0
- package/dist/gpu/temporal-sum-gpu.js +150 -0
- package/dist/gpu/temporal-sum-gpu.js.map +1 -0
- package/dist/gpu/webgpu-runtime.d.ts +63 -0
- package/dist/gpu/webgpu-runtime.js +215 -0
- package/dist/gpu/webgpu-runtime.js.map +1 -0
- package/dist/gpu/wgsl-chart-kernel.d.ts +30 -0
- package/dist/gpu/wgsl-chart-kernel.js +165 -0
- package/dist/gpu/wgsl-chart-kernel.js.map +1 -0
- package/dist/gpu/wgsl-kernels.d.ts +53 -0
- package/dist/gpu/wgsl-kernels.js +365 -0
- package/dist/gpu/wgsl-kernels.js.map +1 -0
- package/dist/gpu/wgsl-sensor-kernel.d.ts +64 -0
- package/dist/gpu/wgsl-sensor-kernel.js +409 -0
- package/dist/gpu/wgsl-sensor-kernel.js.map +1 -0
- package/dist/index.d.ts +89 -25
- package/dist/index.js +59 -15
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.d.ts +92 -40
- package/dist/motion/camera-rotation.js +84 -47
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +37 -34
- package/dist/motion/capture-rotation-inverse-mapping.js +32 -24
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +39 -35
- package/dist/motion/capture-rotation-temporal-quadrature.js +37 -28
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
- package/dist/motion/capture-rotation-trajectory.d.ts +32 -28
- package/dist/motion/capture-rotation-trajectory.js +36 -26
- package/dist/motion/capture-rotation-trajectory.js.map +1 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +23 -21
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +33 -14
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
- package/dist/motion/extended-object-projection.d.ts +19 -16
- package/dist/motion/extended-object-projection.js +38 -18
- package/dist/motion/extended-object-projection.js.map +1 -1
- package/dist/motion/projected-motion.d.ts +18 -17
- package/dist/motion/projected-motion.js +25 -17
- package/dist/motion/projected-motion.js.map +1 -1
- package/dist/motion/temporal-exposure-sum.d.ts +55 -0
- package/dist/motion/temporal-exposure-sum.js +141 -0
- package/dist/motion/temporal-exposure-sum.js.map +1 -0
- package/dist/motion/video-sequence.d.ts +111 -0
- package/dist/motion/video-sequence.js +179 -0
- package/dist/motion/video-sequence.js.map +1 -0
- package/dist/optics/aperture.d.ts +14 -15
- package/dist/optics/aperture.js +13 -11
- package/dist/optics/aperture.js.map +1 -1
- package/dist/optics/atmospheric-haze.d.ts +83 -0
- package/dist/optics/atmospheric-haze.js +113 -0
- package/dist/optics/atmospheric-haze.js.map +1 -0
- package/dist/optics/brown-conrady-distortion.d.ts +116 -0
- package/dist/optics/brown-conrady-distortion.js +291 -0
- package/dist/optics/brown-conrady-distortion.js.map +1 -0
- package/dist/optics/circle-of-confusion.d.ts +10 -10
- package/dist/optics/circle-of-confusion.js +15 -11
- package/dist/optics/circle-of-confusion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +64 -33
- package/dist/optics/complex-pupil-psf.js +190 -98
- package/dist/optics/complex-pupil-psf.js.map +1 -1
- package/dist/optics/depth-of-field.d.ts +25 -15
- package/dist/optics/depth-of-field.js +67 -27
- package/dist/optics/depth-of-field.js.map +1 -1
- package/dist/optics/diffraction.d.ts +14 -13
- package/dist/optics/diffraction.js +14 -10
- package/dist/optics/diffraction.js.map +1 -1
- package/dist/optics/focus-breathing.d.ts +88 -27
- package/dist/optics/focus-breathing.js +114 -23
- package/dist/optics/focus-breathing.js.map +1 -1
- package/dist/optics/focus-state.d.ts +18 -18
- package/dist/optics/focus-state.js +21 -15
- package/dist/optics/focus-state.js.map +1 -1
- package/dist/optics/front-of-lens-filter.d.ts +45 -14
- package/dist/optics/front-of-lens-filter.js +259 -88
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/illumination-vignetting.d.ts +16 -17
- package/dist/optics/illumination-vignetting.js +40 -17
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/irradiance-convolution.d.ts +59 -0
- package/dist/optics/irradiance-convolution.js +138 -0
- package/dist/optics/irradiance-convolution.js.map +1 -0
- package/dist/optics/lateral-chromatic-aberration.d.ts +33 -30
- package/dist/optics/lateral-chromatic-aberration.js +33 -23
- package/dist/optics/lateral-chromatic-aberration.js.map +1 -1
- package/dist/optics/lens-psf-kernels.d.ts +89 -0
- package/dist/optics/lens-psf-kernels.js +175 -0
- package/dist/optics/lens-psf-kernels.js.map +1 -0
- package/dist/optics/lens-psf-profile.d.ts +78 -46
- package/dist/optics/lens-psf-profile.js +335 -124
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/optics/longitudinal-chromatic-aberration.d.ts +102 -0
- package/dist/optics/longitudinal-chromatic-aberration.js +210 -0
- package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -0
- package/dist/optics/polygon-diffraction.d.ts +80 -23
- package/dist/optics/polygon-diffraction.js +130 -25
- package/dist/optics/polygon-diffraction.js.map +1 -1
- package/dist/optics/profile-contract.d.ts +5 -6
- package/dist/optics/profile-contract.js +14 -11
- package/dist/optics/profile-contract.js.map +1 -1
- package/dist/optics/psf-foundation.d.ts +23 -23
- package/dist/optics/psf-foundation.js +24 -21
- package/dist/optics/psf-foundation.js.map +1 -1
- package/dist/optics/pupil-vignetting.d.ts +118 -0
- package/dist/optics/pupil-vignetting.js +264 -0
- package/dist/optics/pupil-vignetting.js.map +1 -0
- package/dist/optics/radial-distortion.d.ts +34 -33
- package/dist/optics/radial-distortion.js +37 -30
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +47 -33
- package/dist/optics/scene-to-sensor-irradiance.js +73 -45
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/optics/scene-to-sensor-quadrature.d.ts +23 -18
- package/dist/optics/scene-to-sensor-quadrature.js +16 -11
- package/dist/optics/scene-to-sensor-quadrature.js.map +1 -1
- package/dist/optics/sensor-aperture-rays.d.ts +20 -4
- package/dist/optics/sensor-aperture-rays.js +32 -14
- package/dist/optics/sensor-aperture-rays.js.map +1 -1
- package/dist/optics/sensor-environment-query.d.ts +81 -16
- package/dist/optics/sensor-environment-query.js +145 -12
- package/dist/optics/sensor-environment-query.js.map +1 -1
- package/dist/optics/sensor-psf-quadrature.d.ts +12 -10
- package/dist/optics/sensor-psf-quadrature.js +18 -11
- package/dist/optics/sensor-psf-quadrature.js.map +1 -1
- package/dist/optics/sensor-psf-support.d.ts +8 -6
- package/dist/optics/sensor-psf-support.js +8 -5
- package/dist/optics/sensor-psf-support.js.map +1 -1
- package/dist/optics/stray-light.d.ts +22 -19
- package/dist/optics/stray-light.js +18 -12
- package/dist/optics/stray-light.js.map +1 -1
- package/dist/optics/thin-lens.d.ts +10 -9
- package/dist/optics/thin-lens.js +12 -8
- package/dist/optics/thin-lens.js.map +1 -1
- package/dist/optics/zernike-wavefront.d.ts +154 -0
- package/dist/optics/zernike-wavefront.js +352 -0
- package/dist/optics/zernike-wavefront.js.map +1 -0
- package/dist/output/capture-corrected-sdr.d.ts +16 -8
- package/dist/output/capture-corrected-sdr.js +16 -8
- package/dist/output/capture-corrected-sdr.js.map +1 -1
- package/dist/output/capture-geometry.d.ts +34 -36
- package/dist/output/capture-geometry.js +52 -32
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/capture-sdr.d.ts +7 -6
- package/dist/output/capture-sdr.js +11 -8
- package/dist/output/capture-sdr.js.map +1 -1
- package/dist/output/crop.d.ts +22 -6
- package/dist/output/crop.js +40 -6
- package/dist/output/crop.js.map +1 -1
- package/dist/output/geometric-transforms.d.ts +60 -23
- package/dist/output/geometric-transforms.js +111 -24
- package/dist/output/geometric-transforms.js.map +1 -1
- package/dist/output/lens-corrections.d.ts +27 -19
- package/dist/output/lens-corrections.js +29 -13
- package/dist/output/lens-corrections.js.map +1 -1
- package/dist/output/native-capture-sdr.d.ts +71 -16
- package/dist/output/native-capture-sdr.js +190 -33
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/png-encoder.d.ts +65 -0
- package/dist/output/png-encoder.js +461 -0
- package/dist/output/png-encoder.js.map +1 -0
- package/dist/output/print-contrast-reference.d.ts +10 -9
- package/dist/output/print-contrast-reference.js +10 -8
- package/dist/output/print-contrast-reference.js.map +1 -1
- package/dist/output/print-detail.d.ts +18 -17
- package/dist/output/print-detail.js +12 -10
- package/dist/output/print-detail.js.map +1 -1
- package/dist/output/print-jpeg.d.ts +26 -5
- package/dist/output/print-jpeg.js +117 -50
- package/dist/output/print-jpeg.js.map +1 -1
- package/dist/output/print-plan.d.ts +19 -19
- package/dist/output/print-plan.js +11 -10
- package/dist/output/print-plan.js.map +1 -1
- package/dist/output/print-region-statistics.d.ts +14 -15
- package/dist/output/print-region-statistics.js +11 -11
- package/dist/output/print-region-statistics.js.map +1 -1
- package/dist/output/sdr-rendering.d.ts +48 -10
- package/dist/output/sdr-rendering.js +114 -25
- package/dist/output/sdr-rendering.js.map +1 -1
- package/dist/output/subject-framing-crop.d.ts +6 -10
- package/dist/output/subject-framing-crop.js +23 -13
- package/dist/output/subject-framing-crop.js.map +1 -1
- package/dist/processing/demosaic.d.ts +90 -0
- package/dist/processing/demosaic.js +275 -0
- package/dist/processing/demosaic.js.map +1 -0
- package/dist/processing/denoise.d.ts +68 -0
- package/dist/processing/denoise.js +214 -0
- package/dist/processing/denoise.js.map +1 -0
- package/dist/processing/focus-stacking.d.ts +17 -0
- package/dist/processing/focus-stacking.js +80 -0
- package/dist/processing/focus-stacking.js.map +1 -0
- package/dist/processing/hdr.d.ts +54 -0
- package/dist/processing/hdr.js +172 -0
- package/dist/processing/hdr.js.map +1 -0
- package/dist/processing/image-ops.d.ts +66 -0
- package/dist/processing/image-ops.js +192 -0
- package/dist/processing/image-ops.js.map +1 -0
- package/dist/processing/panorama.d.ts +51 -0
- package/dist/processing/panorama.js +305 -0
- package/dist/processing/panorama.js.map +1 -0
- package/dist/processing/processing-task.d.ts +85 -0
- package/dist/processing/processing-task.js +164 -0
- package/dist/processing/processing-task.js.map +1 -0
- package/dist/processing/tone-mapping.d.ts +69 -0
- package/dist/processing/tone-mapping.js +310 -0
- package/dist/processing/tone-mapping.js.map +1 -0
- package/dist/schema/camera.d.ts +5 -4
- package/dist/schema/illumination-spectral.d.ts +13 -19
- package/dist/schema/illumination-spectral.js +23 -19
- package/dist/schema/illumination-spectral.js.map +1 -1
- package/dist/schema/illumination-temporal.d.ts +12 -15
- package/dist/schema/illumination-temporal.js +43 -28
- package/dist/schema/illumination-temporal.js.map +1 -1
- package/dist/schema/illumination.d.ts +5 -4
- package/dist/schema/illumination.js +55 -20
- package/dist/schema/illumination.js.map +1 -1
- package/dist/schema/scene-radiance-temporal.d.ts +9 -11
- package/dist/schema/scene-radiance-temporal.js +26 -23
- package/dist/schema/scene-radiance-temporal.js.map +1 -1
- package/dist/schema/scene-radiance.d.ts +17 -17
- package/dist/schema/scene-radiance.js +56 -34
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/schema/scene.d.ts +14 -13
- package/dist/schema/validation.d.ts +0 -1
- package/dist/schema/validation.js +17 -15
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.d.ts +45 -64
- package/dist/sensor/accumulated-charge.js +41 -47
- package/dist/sensor/accumulated-charge.js.map +1 -1
- package/dist/sensor/architecture.d.ts +22 -25
- package/dist/sensor/architecture.js +17 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +21 -28
- package/dist/sensor/camera-saturation-capacity.js +36 -34
- package/dist/sensor/camera-saturation-capacity.js.map +1 -1
- package/dist/sensor/capture-color-sampling-binding.d.ts +46 -51
- package/dist/sensor/capture-color-sampling-binding.js +39 -41
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
- package/dist/sensor/capture-mode-timing.d.ts +8 -9
- package/dist/sensor/capture-mode-timing.js +24 -21
- package/dist/sensor/capture-mode-timing.js.map +1 -1
- package/dist/sensor/capture-mode.d.ts +28 -30
- package/dist/sensor/capture-mode.js +33 -31
- package/dist/sensor/capture-mode.js.map +1 -1
- package/dist/sensor/color-sampling.d.ts +30 -33
- package/dist/sensor/color-sampling.js +32 -37
- package/dist/sensor/color-sampling.js.map +1 -1
- package/dist/sensor/constant-rate-temporal-integration.d.ts +19 -23
- package/dist/sensor/constant-rate-temporal-integration.js +28 -26
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
- package/dist/sensor/dark-current.d.ts +53 -49
- package/dist/sensor/dark-current.js +87 -46
- package/dist/sensor/dark-current.js.map +1 -1
- package/dist/sensor/environment-photo-signal.d.ts +71 -30
- package/dist/sensor/environment-photo-signal.js +127 -46
- package/dist/sensor/environment-photo-signal.js.map +1 -1
- package/dist/sensor/eqe-electron-rate.d.ts +14 -13
- package/dist/sensor/eqe-electron-rate.js +34 -14
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/eqe-local-exposure.d.ts +24 -24
- package/dist/sensor/eqe-local-exposure.js +15 -11
- package/dist/sensor/eqe-local-exposure.js.map +1 -1
- package/dist/sensor/eqe-temporal-exposure.d.ts +11 -11
- package/dist/sensor/eqe-temporal-exposure.js +15 -10
- package/dist/sensor/eqe-temporal-exposure.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +48 -34
- package/dist/sensor/exposure-window.js +77 -36
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/fixed-pattern-noise.d.ts +108 -0
- package/dist/sensor/fixed-pattern-noise.js +166 -0
- package/dist/sensor/fixed-pattern-noise.js.map +1 -0
- package/dist/sensor/iso-gain.d.ts +44 -0
- package/dist/sensor/iso-gain.js +119 -0
- package/dist/sensor/iso-gain.js.map +1 -0
- package/dist/sensor/iso-signal-chain.d.ts +25 -48
- package/dist/sensor/iso-signal-chain.js +52 -66
- package/dist/sensor/iso-signal-chain.js.map +1 -1
- package/dist/sensor/local-exposure-binding.d.ts +21 -21
- package/dist/sensor/local-exposure-binding.js +22 -18
- package/dist/sensor/local-exposure-binding.js.map +1 -1
- package/dist/sensor/optical-stack.d.ts +36 -40
- package/dist/sensor/optical-stack.js +34 -37
- package/dist/sensor/optical-stack.js.map +1 -1
- package/dist/sensor/photon-energy.d.ts +22 -28
- package/dist/sensor/photon-energy.js +42 -34
- package/dist/sensor/photon-energy.js.map +1 -1
- package/dist/sensor/physical-charge-capacity.d.ts +20 -30
- package/dist/sensor/physical-charge-capacity.js +35 -36
- package/dist/sensor/physical-charge-capacity.js.map +1 -1
- package/dist/sensor/pixel-pitch.d.ts +2 -3
- package/dist/sensor/pixel-pitch.js +4 -2
- package/dist/sensor/pixel-pitch.js.map +1 -1
- package/dist/sensor/radiometry-readiness.d.ts +13 -15
- package/dist/sensor/radiometry-readiness.js +20 -17
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +173 -83
- package/dist/sensor/raw-readout.js +425 -160
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/raw-reconstruction.d.ts +112 -44
- package/dist/sensor/raw-reconstruction.js +200 -47
- package/dist/sensor/raw-reconstruction.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.d.ts +103 -34
- package/dist/sensor/readout-exposure-linkage.js +125 -27
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/dist/sensor/readout-timing.d.ts +43 -44
- package/dist/sensor/readout-timing.js +38 -30
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.d.ts +21 -28
- package/dist/sensor/response-application-compatibility.js +35 -34
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/response-operating-range.d.ts +26 -35
- package/dist/sensor/response-operating-range.js +40 -39
- package/dist/sensor/response-operating-range.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.d.ts +21 -29
- package/dist/sensor/responsivity-photocurrent.js +57 -40
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sampling-aperture.d.ts +21 -25
- package/dist/sensor/sampling-aperture.js +29 -28
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts +14 -12
- package/dist/sensor/scene-eqe-temporal-exposure.js +13 -8
- package/dist/sensor/scene-eqe-temporal-exposure.js.map +1 -1
- package/dist/sensor/sensor-geometry.d.ts +28 -32
- package/dist/sensor/sensor-geometry.js +35 -20
- package/dist/sensor/sensor-geometry.js.map +1 -1
- package/dist/sensor/signal-noise.d.ts +14 -16
- package/dist/sensor/signal-noise.js +15 -13
- package/dist/sensor/signal-noise.js.map +1 -1
- package/dist/sensor/spatial-sample-reduction.d.ts +45 -60
- package/dist/sensor/spatial-sample-reduction.js +39 -48
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.d.ts +46 -54
- package/dist/sensor/spatial-sampling-quadrature.js +31 -36
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
- package/dist/sensor/spatio-spectral-reduction.d.ts +32 -42
- package/dist/sensor/spatio-spectral-reduction.js +24 -29
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
- package/dist/sensor/spectral-coverage.d.ts +6 -9
- package/dist/sensor/spectral-coverage.js +9 -6
- package/dist/sensor/spectral-coverage.js.map +1 -1
- package/dist/sensor/spectral-quadrature.d.ts +46 -60
- package/dist/sensor/spectral-quadrature.js +38 -48
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/spectral-response.d.ts +53 -41
- package/dist/sensor/spectral-response.js +80 -47
- package/dist/sensor/spectral-response.js.map +1 -1
- package/dist/sensor/stochastic-seed.d.ts +50 -0
- package/dist/sensor/stochastic-seed.js +123 -0
- package/dist/sensor/stochastic-seed.js.map +1 -0
- package/dist/sensor/temporal-eqe-sum.d.ts +2 -4
- package/dist/sensor/temporal-eqe-sum.js +5 -6
- package/dist/sensor/temporal-eqe-sum.js.map +1 -1
- package/dist/sensor/temporal-photo-signal.d.ts +5 -6
- package/dist/sensor/temporal-photo-signal.js +11 -10
- package/dist/sensor/temporal-photo-signal.js.map +1 -1
- package/dist/sensor/temporal-sample-binding.d.ts +1 -2
- package/dist/sensor/temporal-sample-binding.js +3 -3
- package/dist/sensor/temporal-sample-binding.js.map +1 -1
- package/dist/simulation/poc-simulation.d.ts +16 -16
- package/dist/simulation/poc-simulation.js +20 -15
- package/dist/simulation/poc-simulation.js.map +1 -1
- package/dist/stabilization/camera-shake.d.ts +42 -18
- package/dist/stabilization/camera-shake.js +43 -20
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.d.ts +44 -41
- package/dist/stabilization/system.js +196 -108
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +183 -0
- package/docs/API_REFERENCE.md +761 -2
- package/docs/QUICK_START.md +495 -0
- package/docs/USAGE.md +1719 -714
- package/docs/api/camera-equivalent-focal-length.md +6 -7
- package/docs/api/camera-field-of-view.md +16 -8
- package/docs/api/camera-lens-projection.md +246 -0
- package/docs/api/camera-projected-object-size.md +6 -5
- package/docs/api/capture-capture-export-metadata.md +10 -10
- package/docs/api/capture-dng-import.md +134 -0
- package/docs/api/capture-environment-raw-producer.md +17 -11
- package/docs/api/capture-export-jpeg.md +16 -0
- package/docs/api/capture-focus-control.md +25 -47
- package/docs/api/capture-linear-encoding.md +21 -12
- package/docs/api/capture-lossless-jpeg.md +49 -0
- package/docs/api/capture-native-environment-optical-stage.md +75 -0
- package/docs/api/capture-native-environment-raw.md +161 -4
- package/docs/api/capture-native-raw-development.md +69 -4
- package/docs/api/capture-native-raw-dng.md +84 -0
- package/docs/api/capture-native-raw.md +23 -8
- package/docs/api/capture-packed-sensor-raw.md +156 -0
- package/docs/api/capture-photographic-export.md +69 -31
- package/docs/api/capture-raw-frame-reconstruction.md +8 -8
- package/docs/api/capture-raw-white-level.md +37 -0
- package/docs/api/capture-release-sequence.md +6 -7
- package/docs/api/capture-sensor-raw-frame.md +6 -6
- package/docs/api/capture-sensor-raw-producer.md +17 -11
- package/docs/api/capture-simulated-capture.md +15 -15
- package/docs/api/color-camera-color-matrix.md +103 -0
- package/docs/api/color-capture-color.md +22 -11
- package/docs/api/color-chromatic-adaptation.md +82 -0
- package/docs/api/color-color-difference.md +134 -0
- package/docs/api/color-color-matching-functions.md +259 -0
- package/docs/api/color-colorimetry-math.md +54 -0
- package/docs/api/color-gamut-mapping.md +72 -0
- package/docs/api/color-illuminants.md +280 -0
- package/docs/api/color-rgb-color-spaces.md +151 -0
- package/docs/api/color-sensor-color-development.md +27 -0
- package/docs/api/color-srgb-icc.md +2 -4
- package/docs/api/color-white-balance.md +95 -19
- package/docs/api/composition-image-formation-plan.md +124 -95
- package/docs/api/composition-plan-consumer.md +7 -7
- package/docs/api/core-calculation-result.md +18 -14
- package/docs/api/core-configuration-error.md +1 -1
- package/docs/api/core-image-formation.md +7 -7
- package/docs/api/core-scientific-assurance.md +12 -10
- package/docs/api/core-spectral-composition.md +14 -14
- package/docs/api/core-spectral.md +6 -6
- package/docs/api/core-validation.md +3 -3
- package/docs/api/core-version.md +7 -6
- package/docs/api/equipment-exposure-capabilities.md +11 -10
- package/docs/api/equipment-generic-tier-assets.md +7 -2
- package/docs/api/equipment-generic-tier-presets.md +6 -6
- package/docs/api/equipment-iso-capabilities.md +18 -18
- package/docs/api/equipment-metering-capabilities.md +6 -6
- package/docs/api/equipment-release-capabilities.md +4 -4
- package/docs/api/exports.json +2213 -8
- package/docs/api/exposure-exposure-duration-control.md +9 -9
- package/docs/api/exposure-exposure-mode-resolver.md +35 -31
- package/docs/api/exposure-exposure.md +10 -10
- package/docs/api/exposure-flash-ttl.md +182 -0
- package/docs/api/exposure-flash.md +183 -28
- package/docs/api/exposure-metering-scene-radiance.md +11 -10
- package/docs/api/exposure-metering-target.md +9 -8
- package/docs/api/exposure-metering-temporal.md +8 -8
- package/docs/api/exposure-metering.md +69 -9
- package/docs/api/exposure-program-line.md +6 -5
- package/docs/api/facade-chart-radiance-batch.md +96 -0
- package/docs/api/facade-chart-scenes.md +240 -0
- package/docs/api/facade-scene-radiance.md +122 -0
- package/docs/api/facade-simulate-capture.md +324 -0
- package/docs/api/gpu-image-kernel-accelerator.md +157 -0
- package/docs/api/gpu-image-kernel-execution.md +152 -0
- package/docs/api/motion-camera-rotation.md +43 -26
- package/docs/api/motion-capture-rotation-inverse-mapping.md +24 -23
- package/docs/api/motion-capture-rotation-temporal-quadrature.md +22 -22
- package/docs/api/motion-capture-rotation-trajectory.md +15 -15
- package/docs/api/motion-capture-translation-parallax-temporal-quadrature.md +15 -14
- package/docs/api/motion-extended-object-projection.md +10 -8
- package/docs/api/motion-projected-motion.md +8 -8
- package/docs/api/motion-temporal-exposure-sum.md +98 -0
- package/docs/api/motion-video-sequence.md +159 -0
- package/docs/api/optics-aperture.md +8 -8
- package/docs/api/optics-atmospheric-haze.md +104 -0
- package/docs/api/optics-brown-conrady-distortion.md +123 -0
- package/docs/api/optics-circle-of-confusion.md +5 -4
- package/docs/api/optics-complex-pupil-psf.md +57 -16
- package/docs/api/optics-depth-of-field.md +12 -6
- package/docs/api/optics-diffraction.md +8 -7
- package/docs/api/optics-focus-breathing.md +104 -16
- package/docs/api/optics-focus-state.md +9 -10
- package/docs/api/optics-front-of-lens-filter.md +72 -14
- package/docs/api/optics-illumination-vignetting.md +10 -10
- package/docs/api/optics-irradiance-convolution.md +95 -0
- package/docs/api/optics-lateral-chromatic-aberration.md +22 -21
- package/docs/api/optics-lens-psf-kernels.md +72 -0
- package/docs/api/optics-lens-psf-profile.md +48 -26
- package/docs/api/optics-longitudinal-chromatic-aberration.md +128 -0
- package/docs/api/optics-polygon-diffraction.md +78 -13
- package/docs/api/optics-profile-contract.md +4 -4
- package/docs/api/optics-psf-foundation.md +12 -12
- package/docs/api/optics-pupil-vignetting.md +132 -0
- package/docs/api/optics-radial-distortion.md +12 -12
- package/docs/api/optics-scene-to-sensor-irradiance.md +25 -14
- package/docs/api/optics-scene-to-sensor-quadrature.md +15 -12
- package/docs/api/optics-sensor-aperture-rays.md +3 -2
- package/docs/api/optics-sensor-environment-query.md +52 -9
- package/docs/api/optics-sensor-psf-quadrature.md +13 -10
- package/docs/api/optics-stray-light.md +12 -11
- package/docs/api/optics-thin-lens.md +4 -3
- package/docs/api/optics-zernike-wavefront.md +229 -0
- package/docs/api/output-capture-corrected-sdr.md +10 -7
- package/docs/api/output-capture-geometry.md +35 -36
- package/docs/api/output-capture-sdr.md +4 -4
- package/docs/api/output-crop.md +7 -4
- package/docs/api/output-geometric-transforms.md +65 -19
- package/docs/api/output-lens-corrections.md +17 -15
- package/docs/api/output-native-capture-sdr.md +26 -13
- package/docs/api/output-png-encoder.md +105 -0
- package/docs/api/output-print-contrast-reference.md +8 -8
- package/docs/api/output-print-detail.md +14 -14
- package/docs/api/output-print-jpeg.md +22 -5
- package/docs/api/output-print-plan.md +18 -18
- package/docs/api/output-print-region-statistics.md +14 -14
- package/docs/api/output-sdr-rendering.md +52 -10
- package/docs/api/output-subject-framing-crop.md +5 -6
- package/docs/api/processing-demosaic.md +120 -0
- package/docs/api/processing-denoise.md +148 -0
- package/docs/api/processing-focus-stacking.md +41 -0
- package/docs/api/processing-hdr.md +113 -0
- package/docs/api/processing-panorama.md +82 -0
- package/docs/api/processing-processing-task.md +107 -0
- package/docs/api/processing-tone-mapping.md +142 -0
- package/docs/api/schema-camera.md +6 -4
- package/docs/api/schema-illumination-spectral.md +10 -11
- package/docs/api/schema-illumination-temporal.md +13 -15
- package/docs/api/schema-illumination.md +4 -4
- package/docs/api/schema-scene-radiance-temporal.md +10 -11
- package/docs/api/schema-scene-radiance.md +18 -17
- package/docs/api/schema-scene.md +9 -9
- package/docs/api/schema-validation.md +1 -1
- package/docs/api/sensor-accumulated-charge.md +12 -20
- package/docs/api/sensor-architecture.md +15 -16
- package/docs/api/sensor-camera-saturation-capacity.md +9 -11
- package/docs/api/sensor-capture-color-sampling-binding.md +47 -51
- package/docs/api/sensor-capture-mode-timing.md +9 -9
- package/docs/api/sensor-capture-mode.md +29 -30
- package/docs/api/sensor-color-sampling.md +31 -33
- package/docs/api/sensor-constant-rate-temporal-integration.md +10 -11
- package/docs/api/sensor-dark-current.md +30 -14
- package/docs/api/sensor-environment-photo-signal.md +13 -6
- package/docs/api/sensor-eqe-electron-rate.md +9 -8
- package/docs/api/sensor-eqe-local-exposure.md +18 -17
- package/docs/api/sensor-eqe-temporal-exposure.md +12 -11
- package/docs/api/sensor-exposure-window.md +24 -24
- package/docs/api/sensor-fixed-pattern-noise.md +104 -0
- package/docs/api/sensor-iso-gain.md +63 -0
- package/docs/api/sensor-iso-signal-chain.md +13 -22
- package/docs/api/sensor-local-exposure-binding.md +12 -13
- package/docs/api/sensor-optical-stack.md +37 -40
- package/docs/api/sensor-photon-energy.md +10 -11
- package/docs/api/sensor-physical-charge-capacity.md +8 -13
- package/docs/api/sensor-pixel-pitch.md +1 -1
- package/docs/api/sensor-radiometry-readiness.md +9 -9
- package/docs/api/sensor-raw-readout.md +118 -52
- package/docs/api/sensor-raw-reconstruction.md +97 -20
- package/docs/api/sensor-readout-exposure-linkage.md +120 -24
- package/docs/api/sensor-readout-timing.md +33 -35
- package/docs/api/sensor-response-application-compatibility.md +9 -11
- package/docs/api/sensor-response-operating-range.md +14 -18
- package/docs/api/sensor-responsivity-photocurrent.md +9 -12
- package/docs/api/sensor-sampling-aperture.md +22 -25
- package/docs/api/sensor-scene-eqe-temporal-exposure.md +9 -8
- package/docs/api/sensor-sensor-geometry.md +23 -24
- package/docs/api/sensor-signal-noise.md +10 -10
- package/docs/api/sensor-spatial-sample-reduction.md +27 -30
- package/docs/api/sensor-spatial-sampling-quadrature.md +37 -39
- package/docs/api/sensor-spatio-spectral-reduction.md +27 -29
- package/docs/api/sensor-spectral-coverage.md +5 -5
- package/docs/api/sensor-spectral-quadrature.md +33 -35
- package/docs/api/sensor-spectral-response.md +28 -16
- package/docs/api/sensor-temporal-photo-signal.md +6 -6
- package/docs/api/simulation-poc-simulation.md +17 -16
- package/docs/api/stabilization-camera-shake.md +29 -10
- package/docs/api/stabilization-system.md +25 -21
- package/docs/examples/production-request.json +3821 -2157
- package/docs/examples/simulate-capture.mjs +14 -0
- package/llms.txt +35 -0
- package/package.json +32 -12
- package/AGENTS.md +0 -674
- package/CONTRIBUTING.md +0 -76
- package/DCO +0 -33
- package/dist/camera/equivalent-focal-length.d.ts.map +0 -1
- package/dist/camera/field-of-view.d.ts.map +0 -1
- package/dist/camera/projected-object-size.d.ts.map +0 -1
- package/dist/capture/capture-export-metadata.d.ts.map +0 -1
- package/dist/capture/environment-raw-producer.d.ts.map +0 -1
- package/dist/capture/export-jpeg.d.ts.map +0 -1
- package/dist/capture/export-tiff.d.ts.map +0 -1
- package/dist/capture/focus-control.d.ts.map +0 -1
- package/dist/capture/linear-encoding.d.ts.map +0 -1
- package/dist/capture/native-environment-raw.d.ts.map +0 -1
- package/dist/capture/native-raw-development.d.ts.map +0 -1
- package/dist/capture/native-raw.d.ts.map +0 -1
- package/dist/capture/photographic-export.d.ts.map +0 -1
- package/dist/capture/raw-frame-limits.d.ts.map +0 -1
- package/dist/capture/raw-frame-reconstruction.d.ts.map +0 -1
- package/dist/capture/release-sequence.d.ts.map +0 -1
- package/dist/capture/sensor-raw-frame.d.ts.map +0 -1
- package/dist/capture/sensor-raw-producer.d.ts.map +0 -1
- package/dist/capture/simulated-capture.d.ts.map +0 -1
- package/dist/color/capture-color.d.ts.map +0 -1
- package/dist/color/sensor-color-development.d.ts.map +0 -1
- package/dist/color/srgb-icc.d.ts.map +0 -1
- package/dist/color/srgb-transfer.d.ts.map +0 -1
- package/dist/color/white-balance.d.ts.map +0 -1
- package/dist/composition/image-formation-plan.d.ts.map +0 -1
- package/dist/composition/plan-consumer.d.ts.map +0 -1
- package/dist/core/calculation-result.d.ts.map +0 -1
- package/dist/core/canonical-json.d.ts.map +0 -1
- package/dist/core/configuration-error.d.ts.map +0 -1
- package/dist/core/evidence-provenance.d.ts.map +0 -1
- package/dist/core/image-formation.d.ts.map +0 -1
- package/dist/core/owned-data.d.ts.map +0 -1
- package/dist/core/record-validation.d.ts.map +0 -1
- package/dist/core/scientific-assurance.d.ts.map +0 -1
- package/dist/core/spectral-composition.d.ts.map +0 -1
- package/dist/core/spectral.d.ts.map +0 -1
- package/dist/core/validation.d.ts.map +0 -1
- package/dist/core/version.d.ts.map +0 -1
- package/dist/equipment/exposure-capabilities.d.ts.map +0 -1
- package/dist/equipment/generic-tier-assets.d.ts.map +0 -1
- package/dist/equipment/generic-tier-presets.d.ts.map +0 -1
- package/dist/equipment/iso-capabilities.d.ts.map +0 -1
- package/dist/equipment/metering-capabilities.d.ts.map +0 -1
- package/dist/equipment/release-capabilities.d.ts.map +0 -1
- package/dist/exposure/exposure-duration-control.d.ts.map +0 -1
- package/dist/exposure/exposure-mode-resolver.d.ts.map +0 -1
- package/dist/exposure/exposure.d.ts.map +0 -1
- package/dist/exposure/flash.d.ts.map +0 -1
- package/dist/exposure/metering-scene-radiance.d.ts.map +0 -1
- package/dist/exposure/metering-target.d.ts.map +0 -1
- package/dist/exposure/metering-temporal.d.ts.map +0 -1
- package/dist/exposure/metering.d.ts.map +0 -1
- package/dist/exposure/program-line.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/motion/camera-rotation.d.ts.map +0 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts.map +0 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts.map +0 -1
- package/dist/motion/capture-rotation-trajectory.d.ts.map +0 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts.map +0 -1
- package/dist/motion/extended-object-projection.d.ts.map +0 -1
- package/dist/motion/projected-motion.d.ts.map +0 -1
- package/dist/optics/aperture.d.ts.map +0 -1
- package/dist/optics/circle-of-confusion.d.ts.map +0 -1
- package/dist/optics/complex-pupil-psf.d.ts.map +0 -1
- package/dist/optics/depth-of-field.d.ts.map +0 -1
- package/dist/optics/diffraction.d.ts.map +0 -1
- package/dist/optics/focus-breathing.d.ts.map +0 -1
- package/dist/optics/focus-state.d.ts.map +0 -1
- package/dist/optics/front-of-lens-filter.d.ts.map +0 -1
- package/dist/optics/illumination-vignetting.d.ts.map +0 -1
- package/dist/optics/lateral-chromatic-aberration.d.ts.map +0 -1
- package/dist/optics/lens-psf-profile.d.ts.map +0 -1
- package/dist/optics/polygon-diffraction.d.ts.map +0 -1
- package/dist/optics/profile-contract.d.ts.map +0 -1
- package/dist/optics/psf-foundation.d.ts.map +0 -1
- package/dist/optics/radial-distortion.d.ts.map +0 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts.map +0 -1
- package/dist/optics/scene-to-sensor-quadrature.d.ts.map +0 -1
- package/dist/optics/sensor-aperture-rays.d.ts.map +0 -1
- package/dist/optics/sensor-environment-query.d.ts.map +0 -1
- package/dist/optics/sensor-psf-quadrature.d.ts.map +0 -1
- package/dist/optics/sensor-psf-support.d.ts.map +0 -1
- package/dist/optics/stray-light.d.ts.map +0 -1
- package/dist/optics/thin-lens.d.ts.map +0 -1
- package/dist/output/capture-corrected-sdr.d.ts.map +0 -1
- package/dist/output/capture-geometry.d.ts.map +0 -1
- package/dist/output/capture-sdr.d.ts.map +0 -1
- package/dist/output/crop.d.ts.map +0 -1
- package/dist/output/geometric-transforms.d.ts.map +0 -1
- package/dist/output/lens-corrections.d.ts.map +0 -1
- package/dist/output/native-capture-sdr.d.ts.map +0 -1
- package/dist/output/print-contrast-reference.d.ts.map +0 -1
- package/dist/output/print-detail.d.ts.map +0 -1
- package/dist/output/print-jpeg.d.ts.map +0 -1
- package/dist/output/print-plan.d.ts.map +0 -1
- package/dist/output/print-region-statistics.d.ts.map +0 -1
- package/dist/output/sdr-rendering.d.ts.map +0 -1
- package/dist/output/subject-framing-crop.d.ts.map +0 -1
- package/dist/schema/camera.d.ts.map +0 -1
- package/dist/schema/camera.js +0 -3
- package/dist/schema/camera.js.map +0 -1
- package/dist/schema/illumination-spectral.d.ts.map +0 -1
- package/dist/schema/illumination-temporal.d.ts.map +0 -1
- package/dist/schema/illumination.d.ts.map +0 -1
- package/dist/schema/scene-radiance-temporal.d.ts.map +0 -1
- package/dist/schema/scene-radiance.d.ts.map +0 -1
- package/dist/schema/scene.d.ts.map +0 -1
- package/dist/schema/scene.js +0 -3
- package/dist/schema/scene.js.map +0 -1
- package/dist/schema/validation.d.ts.map +0 -1
- package/dist/sensor/accumulated-charge.d.ts.map +0 -1
- package/dist/sensor/architecture.d.ts.map +0 -1
- package/dist/sensor/camera-saturation-capacity.d.ts.map +0 -1
- package/dist/sensor/capture-color-sampling-binding.d.ts.map +0 -1
- package/dist/sensor/capture-mode-timing.d.ts.map +0 -1
- package/dist/sensor/capture-mode.d.ts.map +0 -1
- package/dist/sensor/color-sampling.d.ts.map +0 -1
- package/dist/sensor/constant-rate-temporal-integration.d.ts.map +0 -1
- package/dist/sensor/dark-current.d.ts.map +0 -1
- package/dist/sensor/environment-photo-signal.d.ts.map +0 -1
- package/dist/sensor/eqe-electron-rate.d.ts.map +0 -1
- package/dist/sensor/eqe-local-exposure.d.ts.map +0 -1
- package/dist/sensor/eqe-temporal-exposure.d.ts.map +0 -1
- package/dist/sensor/exposure-window.d.ts.map +0 -1
- package/dist/sensor/iso-signal-chain.d.ts.map +0 -1
- package/dist/sensor/local-exposure-binding.d.ts.map +0 -1
- package/dist/sensor/optical-stack.d.ts.map +0 -1
- package/dist/sensor/photon-energy.d.ts.map +0 -1
- package/dist/sensor/physical-charge-capacity.d.ts.map +0 -1
- package/dist/sensor/pixel-pitch.d.ts.map +0 -1
- package/dist/sensor/radiometry-readiness.d.ts.map +0 -1
- package/dist/sensor/raw-readout.d.ts.map +0 -1
- package/dist/sensor/raw-reconstruction.d.ts.map +0 -1
- package/dist/sensor/readout-exposure-linkage.d.ts.map +0 -1
- package/dist/sensor/readout-timing.d.ts.map +0 -1
- package/dist/sensor/response-application-compatibility.d.ts.map +0 -1
- package/dist/sensor/response-operating-range.d.ts.map +0 -1
- package/dist/sensor/responsivity-photocurrent.d.ts.map +0 -1
- package/dist/sensor/sampling-aperture.d.ts.map +0 -1
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts.map +0 -1
- package/dist/sensor/sensor-geometry.d.ts.map +0 -1
- package/dist/sensor/signal-noise.d.ts.map +0 -1
- package/dist/sensor/spatial-sample-reduction.d.ts.map +0 -1
- package/dist/sensor/spatial-sampling-quadrature.d.ts.map +0 -1
- package/dist/sensor/spatio-spectral-reduction.d.ts.map +0 -1
- package/dist/sensor/spectral-coverage.d.ts.map +0 -1
- package/dist/sensor/spectral-quadrature.d.ts.map +0 -1
- package/dist/sensor/spectral-response.d.ts.map +0 -1
- package/dist/sensor/temporal-eqe-sum.d.ts.map +0 -1
- package/dist/sensor/temporal-photo-signal.d.ts.map +0 -1
- package/dist/sensor/temporal-sample-binding.d.ts.map +0 -1
- package/dist/simulation/poc-simulation.d.ts.map +0 -1
- package/dist/stabilization/camera-shake.d.ts.map +0 -1
- package/dist/stabilization/system.d.ts.map +0 -1
- package/docs/API_STYLE.md +0 -235
- package/docs/ARCHITECTURE.md +0 -356
- package/docs/AUTOMATION_COORDINATION.md +0 -190
- package/docs/CAPTURE_COLOR.md +0 -25
- package/docs/CAPTURE_CORRECTED_SDR.md +0 -25
- package/docs/CAPTURE_EXPORT_METADATA.md +0 -27
- package/docs/CAPTURE_SDR.md +0 -22
- package/docs/DEVELOPERS.md +0 -68
- package/docs/DIGITAL_OPTICS_FOUNDATION.md +0 -69
- package/docs/ENVIRONMENT_RAW_CAPTURE.md +0 -208
- package/docs/EXPORT_ACCEPTANCE.md +0 -133
- package/docs/GENERIC_TIER_PRESETS.md +0 -269
- package/docs/GEOMETRIC_PREPARATION_REUSE.md +0 -141
- package/docs/IMAGE_FORMATION.md +0 -247
- package/docs/LINEAR_CAPTURE_ENCODING.md +0 -25
- package/docs/MOTION_AND_SIGNAL.md +0 -250
- package/docs/NATIVE_CAPTURE_SDR.md +0 -70
- package/docs/NATIVE_CAPTURE_SDR_REVIEW.md +0 -37
- package/docs/NATIVE_CAPTURE_SDR_VALIDATION.md +0 -34
- package/docs/NATIVE_RAW_AND_PRINT.md +0 -47
- package/docs/NUMERICAL_CORRECTNESS.md +0 -191
- package/docs/PERFORMANCE_BASELINE.md +0 -56
- package/docs/PHOTOGRAPHIC_EXPORT.md +0 -206
- package/docs/PHYSICS_FOUNDATION.md +0 -426
- package/docs/POC_API.md +0 -278
- package/docs/POC_PROJECTION_PLATFORM_REFERENCE.md +0 -12
- package/docs/POC_PROJECTION_REUSE.md +0 -124
- package/docs/PRINT_195_196_REVIEW.md +0 -93
- package/docs/PRINT_196_ENGINE_ACCEPTANCE.md +0 -45
- package/docs/PRINT_CONTRAST_REFERENCE.md +0 -43
- package/docs/PRINT_DETAIL_ASSESSMENT.md +0 -81
- package/docs/PRINT_DETAIL_JPEG_EVIDENCE.md +0 -36
- package/docs/PRINT_DETAIL_SDR_EVIDENCE.md +0 -29
- package/docs/PRINT_DETAIL_VALIDATION.md +0 -36
- package/docs/PRINT_PLANNING.md +0 -75
- package/docs/PRINT_REGION_STATISTICS.md +0 -38
- package/docs/PROCESSED_OUTPUT.md +0 -157
- package/docs/PRODUCTION_COMPOSITION.md +0 -373
- package/docs/PRODUCTION_ENVIRONMENT_CAPTURE.md +0 -131
- package/docs/PROVENANCE.md +0 -115
- package/docs/PSF_FOUNDATION.md +0 -165
- package/docs/RAW_FRAME_ENVELOPE.md +0 -56
- package/docs/RAW_FRAME_RECONSTRUCTION.md +0 -30
- package/docs/RELEASE_1_0.md +0 -66
- package/docs/RELEASE_1_0_1.md +0 -61
- package/docs/RELEASE_1_1_0.md +0 -25
- package/docs/RELEASE_1_2_0.md +0 -51
- package/docs/RELEASE_1_3_0.md +0 -15
- package/docs/RELEASE_1_4_0.md +0 -23
- package/docs/RELEASE_AUDIT.md +0 -39
- package/docs/SCENE_RADIANCE_AND_ILLUMINATION.md +0 -298
- package/docs/SCENE_SENSOR_QUADRATURE.md +0 -98
- package/docs/SCENE_SENSOR_TEMPORAL_EXPOSURE.md +0 -86
- package/docs/SCIENTIFIC_ASSURANCE.md +0 -280
- package/docs/SCIENTIFIC_CONFORMANCE.md +0 -83
- package/docs/SDR_RENDERING.md +0 -33
- package/docs/SENSOR_APERTURE_RAYS.md +0 -23
- package/docs/SENSOR_ENVIRONMENT_QUERY.md +0 -86
- package/docs/SENSOR_EQE_LOCAL_EXPOSURE.md +0 -104
- package/docs/SENSOR_EQE_TEMPORAL_EXPOSURE.md +0 -74
- package/docs/SENSOR_PSF_QUADRATURE.md +0 -90
- package/docs/SENSOR_RAW_FRAME.md +0 -20
- package/docs/SENSOR_RAW_PRODUCER.md +0 -77
- package/docs/SIGNAL_CONFORMANCE.md +0 -23
- package/docs/SIMULATED_CAPTURE.md +0 -65
- package/docs/STABILIZATION.md +0 -234
- package/docs/TEMPORAL_PHOTO_RAW.md +0 -83
- package/docs/TIER_ACCEPTANCE.md +0 -129
- package/docs/TIER_PRESET_ACCEPTANCE.md +0 -59
- package/docs/V1_COMPOSITION_MAP.md +0 -123
- package/docs/V1_HELPER_REUSE_REVIEW.md +0 -60
- package/docs/V1_PERFORMANCE_DISPOSITION.md +0 -88
- package/docs/benchmarks/2026-10-01-main-baseline.json +0 -694
- package/docs/benchmarks/2026-10-02-geometric-preparation-reuse.json +0 -2190
- package/docs/benchmarks/2026-10-02-poc-projection-reuse.json +0 -2423
- package/docs/benchmarks/2026-10-02-v1-environment-gc-profile.json +0 -210
- package/docs/benchmarks/2026-10-02-v1-environment-ordinary.json +0 -187
- package/docs/benchmarks/2026-10-02-v1-geometry-gc-profile.json +0 -756
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-1.json +0 -711
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-2.json +0 -711
- package/docs/benchmarks/2026-10-02-v1-poc-gc-profile.json +0 -885
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-1.json +0 -868
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-2.json +0 -868
- package/docs/licenses/castleCSF-MIT.txt +0 -21
- package/docs/validation/documentation-fragments.json +0 -212
- package/docs/validation/native-capture-sdr-darwin-arm64-node26-review.jsonl +0 -4
- package/docs/validation/native-capture-sdr-darwin-arm64.jsonl +0 -3
- package/docs/validation/native-raw-print-2026-10-04/fractional-asymmetric-crop.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/gray-ramp.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/linear-area-checker.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/manifest.json +0 -218
- package/docs/validation/native-raw-print-2026-10-04/megapixel-native.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/native-color.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel-validation.json +0 -9
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json +0 -29
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.codes.u16le.gz +0 -0
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.rgb.gz +0 -0
- package/docs/validation/native-raw-print-2026-10-04/srgb.icc +0 -0
- package/docs/validation/native-raw-print-2026-10-04/validation.json +0 -41
- package/docs/validation/print-196-candidate-capabilities.json +0 -28
- package/docs/validation/print-196-candidate-evidence.json +0 -356
- package/docs/validation/print-196-engine-acceptance.json +0 -81
- package/docs/validation/print-detail-capabilities.json +0 -103
- package/docs/validation/print-detail-jpeg-evidence.json +0 -116
- package/docs/validation/print-detail-sdr-evidence.json +0 -81
- package/docs/validation/release-audit-inventory.json +0 -1306
- package/docs/validation/tier-acceptance-report-v1.json +0 -2538
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describes lens aberrations as a wavefront, for the complex-pupil PSF (point-spread function)
|
|
3
|
+
* reference.
|
|
4
|
+
*
|
|
5
|
+
* This module builds the declared pupil grid: relative amplitude plus optical path difference (OPD)
|
|
6
|
+
* in micrometres. calculateLensComplexPupilPsf() uses that grid unchanged. This module does no light
|
|
7
|
+
* propagation itself.
|
|
8
|
+
*
|
|
9
|
+
* Zernike polynomials use Noll's single index j >= 1 and Noll's normalisation (Noll 1976, JOSA
|
|
10
|
+
* 66:207):
|
|
11
|
+
* - m = 0: Z_j = sqrt(n + 1) R_n^0(rho)
|
|
12
|
+
* - m != 0: Z_j = sqrt(2 (n + 1)) R_n^|m|(rho) cos(m theta) for even j, or sin(m theta) for odd j
|
|
13
|
+
* So each term has an RMS of 1 over the unit disk. The RMS wavefront error of sum_j c_j Z_j (piston
|
|
14
|
+
* excluded) is sqrt(sum_{j>=2} c_j^2). The radial polynomial R_n^m is the standard one in Noll's
|
|
15
|
+
* nomenclature (Mathar, arXiv:0809.2368, eq. 1, free). Also see: Born & Wolf, Principles of Optics,
|
|
16
|
+
* 7th ed., sec. 9.2 and app. VII.
|
|
17
|
+
*
|
|
18
|
+
* Primary (Seidel) aberrations use the wave-aberration expansion in normalised field height H and
|
|
19
|
+
* normalised pupil coordinates (rho, phi), phi measured from the field direction (Hopkins 1950,
|
|
20
|
+
* Wave Theory of Aberrations; Wyant & Creath 1992, Applied Optics and Optical Engineering XI ch. 1):
|
|
21
|
+
* W = W020 rho^2 + W111 H rho cos(phi) + W040 rho^4 + W131 H rho^3 cos(phi)
|
|
22
|
+
* + W222 H^2 rho^2 cos^2(phi) + W220 H^2 rho^2 + W311 H^3 rho cos(phi).
|
|
23
|
+
*
|
|
24
|
+
* Paraxial defocus: an image-plane defocus dz at working f-number N gives W020 = dz / (8 N^2)
|
|
25
|
+
* (Wyant & Creath 1992, Applied Optics and Optical Engineering XI ch. 1, eq. 18, free author copy.
|
|
26
|
+
* Also see: Goodman, Introduction to Fourier Optics, 3rd ed., sec. 6.4; Mahajan, Optical Imaging and
|
|
27
|
+
* Aberrations Part I, sec. 3.4). That is a Zernike Z4 coefficient of W020 / (2 sqrt 3).
|
|
28
|
+
*
|
|
29
|
+
* Marechal/Mahajan approximation: Strehl ratio ~ exp(-(2 pi sigma / lambda)^2) for a small RMS
|
|
30
|
+
* wavefront error sigma (Marechal 1947; Mahajan 1982 JOSA 72:1258; free: Wyant & Creath 1992,
|
|
31
|
+
* ch. 1, eq. 67). It is an approximation, valid
|
|
32
|
+
* roughly for Strehl ratios above 0.3.
|
|
33
|
+
*
|
|
34
|
+
* Pupil coordinates are in metric units, aligned with the image plane (+X right, +Y up). theta is
|
|
35
|
+
* measured counter-clockwise from +X.
|
|
36
|
+
* @see docs/PSF_FOUNDATION.md for the equations, units, coordinate conventions, known blockers and
|
|
37
|
+
* support limits.
|
|
38
|
+
*/
|
|
39
|
+
import { type CalculationResult } from "../core/calculation-result.js";
|
|
40
|
+
import type { LensComplexPupilGrid } from "./complex-pupil-psf.js";
|
|
41
|
+
/** Largest supported Noll index (radial order n <= 10). */
|
|
42
|
+
export declare const ZERNIKE_MAXIMUM_NOLL_INDEX = 66;
|
|
43
|
+
/** Largest odd pupil grid width: 63 x 63 = 3969 samples, within the complex-pupil 4096 limit. */
|
|
44
|
+
export declare const ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS = 63;
|
|
45
|
+
export interface ZernikeOrder {
|
|
46
|
+
nollIndex: number;
|
|
47
|
+
/** Radial order n. */
|
|
48
|
+
radialOrder: number;
|
|
49
|
+
/** Signed azimuthal frequency m. Positive means cos(m theta); negative means sin(|m| theta). */
|
|
50
|
+
azimuthalFrequency: number;
|
|
51
|
+
}
|
|
52
|
+
export interface ZernikeCoefficient {
|
|
53
|
+
nollIndex: number;
|
|
54
|
+
/** Coefficient of the unit-RMS Noll polynomial, in micrometres of optical path difference. */
|
|
55
|
+
coefficientMicrometers: number;
|
|
56
|
+
}
|
|
57
|
+
/** Peak Seidel wave-aberration coefficients in micrometres of optical path difference. */
|
|
58
|
+
export interface SeidelWavefrontCoefficients {
|
|
59
|
+
/** Defocus rho^2. */
|
|
60
|
+
w020Micrometers?: number;
|
|
61
|
+
/** Tilt H rho cos(phi). */
|
|
62
|
+
w111Micrometers?: number;
|
|
63
|
+
/** Spherical aberration rho^4. */
|
|
64
|
+
w040Micrometers?: number;
|
|
65
|
+
/** Coma H rho^3 cos(phi). */
|
|
66
|
+
w131Micrometers?: number;
|
|
67
|
+
/** Astigmatism H^2 rho^2 cos^2(phi). */
|
|
68
|
+
w222Micrometers?: number;
|
|
69
|
+
/** Field curvature H^2 rho^2. */
|
|
70
|
+
w220Micrometers?: number;
|
|
71
|
+
/** Distortion H^3 rho cos(phi). */
|
|
72
|
+
w311Micrometers?: number;
|
|
73
|
+
}
|
|
74
|
+
export interface SeidelFieldPosition {
|
|
75
|
+
/** Normalised field height H in [0, 1]. */
|
|
76
|
+
normalizedFieldHeight: number;
|
|
77
|
+
/** Image-plane direction of the field point, degrees counter-clockwise from +X. */
|
|
78
|
+
fieldAzimuthDegrees: number;
|
|
79
|
+
}
|
|
80
|
+
export interface CreateWavefrontPupilGridInput {
|
|
81
|
+
/** Pupil diameter in mm; rho = 1 at radius pupilDiameterMm / 2. */
|
|
82
|
+
pupilDiameterMm: number;
|
|
83
|
+
/** Odd number of samples across the pupil diameter, from 3 to 63. */
|
|
84
|
+
samplesAcross: number;
|
|
85
|
+
zernikeCoefficients?: readonly ZernikeCoefficient[];
|
|
86
|
+
seidelCoefficients?: SeidelWavefrontCoefficients;
|
|
87
|
+
/** Required when any field-dependent Seidel coefficient is non-zero. */
|
|
88
|
+
seidelField?: SeidelFieldPosition;
|
|
89
|
+
/**
|
|
90
|
+
* Optional additional aperture mask: a simple polygon in pupil-plane mm (for example the
|
|
91
|
+
* cat's-eye pupil from calculateMechanicalVignetting). Samples outside it get zero amplitude.
|
|
92
|
+
*/
|
|
93
|
+
apertureMaskVerticesMm?: readonly {
|
|
94
|
+
x: number;
|
|
95
|
+
y: number;
|
|
96
|
+
}[];
|
|
97
|
+
}
|
|
98
|
+
export interface WavefrontPupilGrid {
|
|
99
|
+
/** Grid for LensComplexPupilProfile.grid. Amplitude is 1 inside and 0 outside; OPD is in micrometres. */
|
|
100
|
+
grid: LensComplexPupilGrid;
|
|
101
|
+
pupilDiameterMm: number;
|
|
102
|
+
/** Number of samples with non-zero amplitude. */
|
|
103
|
+
openSampleCount: number;
|
|
104
|
+
/** sqrt(sum c_j^2, j >= 2): RMS of the Zernike terms alone over the continuous unit disk. */
|
|
105
|
+
zernikeRmsMicrometers: number;
|
|
106
|
+
/** RMS of the sampled OPD over open samples, with piston removed (all terms). */
|
|
107
|
+
sampledRmsMicrometers: number;
|
|
108
|
+
/** Peak-to-valley of the sampled OPD over open samples. */
|
|
109
|
+
sampledPeakToValleyMicrometers: number;
|
|
110
|
+
}
|
|
111
|
+
export interface CalculateDefocusWavefrontInput {
|
|
112
|
+
/** Signed image-plane defocus, sensor minus image distance, in micrometres. */
|
|
113
|
+
signedDefocusImagePlaneMicrometers: number;
|
|
114
|
+
/** Image-side working f-number (image distance / pupil diameter). */
|
|
115
|
+
workingFNumber: number;
|
|
116
|
+
}
|
|
117
|
+
export interface DefocusWavefront {
|
|
118
|
+
signedDefocusImagePlaneMicrometers: number;
|
|
119
|
+
workingFNumber: number;
|
|
120
|
+
/** Peak defocus coefficient W020 = dz / (8 N^2), micrometres. */
|
|
121
|
+
w020Micrometers: number;
|
|
122
|
+
/** Equivalent Noll Z4 coefficient W020 / (2 sqrt 3), micrometres (equals the RMS). */
|
|
123
|
+
zernikeZ4Micrometers: number;
|
|
124
|
+
}
|
|
125
|
+
export interface EstimateMarechalStrehlRatioInput {
|
|
126
|
+
rmsWavefrontErrorMicrometers: number;
|
|
127
|
+
wavelengthNm: number;
|
|
128
|
+
}
|
|
129
|
+
/** Converts a Noll index to radial order n and signed azimuthal frequency m (Noll 1976). */
|
|
130
|
+
export declare function resolveZernikeNollOrder(nollIndex: number): ZernikeOrder;
|
|
131
|
+
/** Evaluates the unit-RMS Noll Zernike polynomial at normalised pupil polar coordinates. */
|
|
132
|
+
export declare function evaluateZernikePolynomial(nollIndex: number, normalizedRadius: number, azimuthRadians: number): number;
|
|
133
|
+
/**
|
|
134
|
+
* Builds a complex-pupil grid: a circular pupil, an optional polygon mask, and an OPD from Zernike
|
|
135
|
+
* coefficients, Seidel coefficients or both. If every coefficient is zero, the OPD is exactly zero,
|
|
136
|
+
* so the PSF equals the existing aberration-free circular-pupil reference.
|
|
137
|
+
*/
|
|
138
|
+
export declare function createWavefrontPupilGrid(input: CreateWavefrontPupilGridInput): CalculationResult<WavefrontPupilGrid>;
|
|
139
|
+
/**
|
|
140
|
+
* Converts a signed paraxial image-plane defocus into the defocus wave aberration
|
|
141
|
+
* W020 = dz / (8 N^2) and its Noll Z4 coefficient W020 / (2 sqrt 3).
|
|
142
|
+
*
|
|
143
|
+
* Sign convention: dz = sensor distance minus image distance. Positive W020 means the image lies in
|
|
144
|
+
* front of the sensor. With pure defocus, the PSF intensity does not depend on the sign.
|
|
145
|
+
*/
|
|
146
|
+
export declare function calculateDefocusWavefront(input: CalculateDefocusWavefrontInput): CalculationResult<DefocusWavefront>;
|
|
147
|
+
/**
|
|
148
|
+
* Marechal/Mahajan approximation of the Strehl ratio: exp(-(2 pi sigma / lambda)^2). Valid only for a
|
|
149
|
+
* small RMS wavefront error (Strehl roughly above 0.3). It is not an exact PSF calculation.
|
|
150
|
+
*/
|
|
151
|
+
export declare function estimateMarechalStrehlRatio(input: EstimateMarechalStrehlRatioInput): CalculationResult<{
|
|
152
|
+
strehlRatio: number;
|
|
153
|
+
rmsWaves: number;
|
|
154
|
+
}>;
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Describes lens aberrations as a wavefront, for the complex-pupil PSF (point-spread function)
|
|
4
|
+
* reference.
|
|
5
|
+
*
|
|
6
|
+
* This module builds the declared pupil grid: relative amplitude plus optical path difference (OPD)
|
|
7
|
+
* in micrometres. calculateLensComplexPupilPsf() uses that grid unchanged. This module does no light
|
|
8
|
+
* propagation itself.
|
|
9
|
+
*
|
|
10
|
+
* Zernike polynomials use Noll's single index j >= 1 and Noll's normalisation (Noll 1976, JOSA
|
|
11
|
+
* 66:207):
|
|
12
|
+
* - m = 0: Z_j = sqrt(n + 1) R_n^0(rho)
|
|
13
|
+
* - m != 0: Z_j = sqrt(2 (n + 1)) R_n^|m|(rho) cos(m theta) for even j, or sin(m theta) for odd j
|
|
14
|
+
* So each term has an RMS of 1 over the unit disk. The RMS wavefront error of sum_j c_j Z_j (piston
|
|
15
|
+
* excluded) is sqrt(sum_{j>=2} c_j^2). The radial polynomial R_n^m is the standard one in Noll's
|
|
16
|
+
* nomenclature (Mathar, arXiv:0809.2368, eq. 1, free). Also see: Born & Wolf, Principles of Optics,
|
|
17
|
+
* 7th ed., sec. 9.2 and app. VII.
|
|
18
|
+
*
|
|
19
|
+
* Primary (Seidel) aberrations use the wave-aberration expansion in normalised field height H and
|
|
20
|
+
* normalised pupil coordinates (rho, phi), phi measured from the field direction (Hopkins 1950,
|
|
21
|
+
* Wave Theory of Aberrations; Wyant & Creath 1992, Applied Optics and Optical Engineering XI ch. 1):
|
|
22
|
+
* W = W020 rho^2 + W111 H rho cos(phi) + W040 rho^4 + W131 H rho^3 cos(phi)
|
|
23
|
+
* + W222 H^2 rho^2 cos^2(phi) + W220 H^2 rho^2 + W311 H^3 rho cos(phi).
|
|
24
|
+
*
|
|
25
|
+
* Paraxial defocus: an image-plane defocus dz at working f-number N gives W020 = dz / (8 N^2)
|
|
26
|
+
* (Wyant & Creath 1992, Applied Optics and Optical Engineering XI ch. 1, eq. 18, free author copy.
|
|
27
|
+
* Also see: Goodman, Introduction to Fourier Optics, 3rd ed., sec. 6.4; Mahajan, Optical Imaging and
|
|
28
|
+
* Aberrations Part I, sec. 3.4). That is a Zernike Z4 coefficient of W020 / (2 sqrt 3).
|
|
29
|
+
*
|
|
30
|
+
* Marechal/Mahajan approximation: Strehl ratio ~ exp(-(2 pi sigma / lambda)^2) for a small RMS
|
|
31
|
+
* wavefront error sigma (Marechal 1947; Mahajan 1982 JOSA 72:1258; free: Wyant & Creath 1992,
|
|
32
|
+
* ch. 1, eq. 67). It is an approximation, valid
|
|
33
|
+
* roughly for Strehl ratios above 0.3.
|
|
34
|
+
*
|
|
35
|
+
* Pupil coordinates are in metric units, aligned with the image plane (+X right, +Y up). theta is
|
|
36
|
+
* measured counter-clockwise from +X.
|
|
37
|
+
* @see docs/PSF_FOUNDATION.md for the equations, units, coordinate conventions, known blockers and
|
|
38
|
+
* support limits.
|
|
39
|
+
*/
|
|
40
|
+
import { approximationResult, calculatedResult } from "../core/calculation-result.js";
|
|
41
|
+
import { InvalidScientificInputError, requirePositiveFinite } from "../core/validation.js";
|
|
42
|
+
import { requireInputKeys } from "../core/record-validation.js";
|
|
43
|
+
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
44
|
+
/** Largest supported Noll index (radial order n <= 10). */
|
|
45
|
+
export const ZERNIKE_MAXIMUM_NOLL_INDEX = 66;
|
|
46
|
+
/** Largest odd pupil grid width: 63 x 63 = 3969 samples, within the complex-pupil 4096 limit. */
|
|
47
|
+
export const ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS = 63;
|
|
48
|
+
function requireFinite(name, value) {
|
|
49
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
50
|
+
throw new InvalidScientificInputError(`${name} must be finite.`);
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
function requireNollIndex(value) {
|
|
55
|
+
if (typeof value !== "number" ||
|
|
56
|
+
!Number.isSafeInteger(value) ||
|
|
57
|
+
value < 1 ||
|
|
58
|
+
value > ZERNIKE_MAXIMUM_NOLL_INDEX) {
|
|
59
|
+
throw new InvalidScientificInputError(`nollIndex must be an integer from 1 through ${ZERNIKE_MAXIMUM_NOLL_INDEX}.`);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
/** Converts a Noll index to radial order n and signed azimuthal frequency m (Noll 1976). */
|
|
64
|
+
export function resolveZernikeNollOrder(nollIndex) {
|
|
65
|
+
const j = requireNollIndex(nollIndex);
|
|
66
|
+
let n = 0;
|
|
67
|
+
while (((n + 1) * (n + 2)) / 2 < j) {
|
|
68
|
+
n += 1;
|
|
69
|
+
}
|
|
70
|
+
// Position within radial order n; |m| increases with it, two indices per non-zero |m|.
|
|
71
|
+
const k = j - (n * (n + 1)) / 2 - 1;
|
|
72
|
+
const absoluteM = n % 2 === 0 ? 2 * Math.floor((k + 1) / 2) : 2 * Math.floor(k / 2) + 1;
|
|
73
|
+
return {
|
|
74
|
+
nollIndex: j,
|
|
75
|
+
radialOrder: n,
|
|
76
|
+
azimuthalFrequency: absoluteM === 0 ? 0 : j % 2 === 0 ? absoluteM : -absoluteM
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function factorial(value) {
|
|
80
|
+
let result = 1;
|
|
81
|
+
for (let k = 2; k <= value; k += 1)
|
|
82
|
+
result *= k;
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
function radialPolynomial(n, m, rho) {
|
|
86
|
+
let sum = 0;
|
|
87
|
+
for (let k = 0; k <= (n - m) / 2; k += 1) {
|
|
88
|
+
const coefficient = ((k % 2 === 0 ? 1 : -1) * factorial(n - k)) /
|
|
89
|
+
(factorial(k) * factorial((n + m) / 2 - k) * factorial((n - m) / 2 - k));
|
|
90
|
+
sum += coefficient * rho ** (n - 2 * k);
|
|
91
|
+
}
|
|
92
|
+
return sum;
|
|
93
|
+
}
|
|
94
|
+
/** Evaluates the unit-RMS Noll Zernike polynomial at normalised pupil polar coordinates. */
|
|
95
|
+
export function evaluateZernikePolynomial(nollIndex, normalizedRadius, azimuthRadians) {
|
|
96
|
+
const order = resolveZernikeNollOrder(nollIndex);
|
|
97
|
+
const rho = requireFinite("normalizedRadius", normalizedRadius);
|
|
98
|
+
const theta = requireFinite("azimuthRadians", azimuthRadians);
|
|
99
|
+
if (rho < 0 || rho > 1 + 1e-12) {
|
|
100
|
+
throw new InvalidScientificInputError("normalizedRadius must lie in [0, 1].");
|
|
101
|
+
}
|
|
102
|
+
const n = order.radialOrder;
|
|
103
|
+
const m = Math.abs(order.azimuthalFrequency);
|
|
104
|
+
const radial = radialPolynomial(n, m, Math.min(1, rho));
|
|
105
|
+
if (m === 0) {
|
|
106
|
+
return Math.sqrt(n + 1) * radial;
|
|
107
|
+
}
|
|
108
|
+
const angular = order.azimuthalFrequency > 0 ? Math.cos(m * theta) : Math.sin(m * theta);
|
|
109
|
+
return Math.sqrt(2 * (n + 1)) * radial * angular;
|
|
110
|
+
}
|
|
111
|
+
function parseZernike(value) {
|
|
112
|
+
if (value === undefined)
|
|
113
|
+
return [];
|
|
114
|
+
if (!Array.isArray(value)) {
|
|
115
|
+
throw new InvalidConfigurationError("zernikeCoefficients must be an array.");
|
|
116
|
+
}
|
|
117
|
+
const seen = new Set();
|
|
118
|
+
return value.map((entry, index) => {
|
|
119
|
+
if (typeof entry !== "object" || entry === null) {
|
|
120
|
+
throw new InvalidConfigurationError(`zernikeCoefficients[${index}] must be an object.`);
|
|
121
|
+
}
|
|
122
|
+
const nollIndex = requireNollIndex(entry.nollIndex);
|
|
123
|
+
if (seen.has(nollIndex)) {
|
|
124
|
+
throw new InvalidScientificInputError("zernikeCoefficients must not repeat a nollIndex.");
|
|
125
|
+
}
|
|
126
|
+
seen.add(nollIndex);
|
|
127
|
+
return {
|
|
128
|
+
nollIndex,
|
|
129
|
+
coefficientMicrometers: requireFinite(`zernikeCoefficients[${index}].coefficientMicrometers`, entry.coefficientMicrometers)
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
const SEIDEL_KEYS = [
|
|
134
|
+
"w020Micrometers",
|
|
135
|
+
"w111Micrometers",
|
|
136
|
+
"w040Micrometers",
|
|
137
|
+
"w131Micrometers",
|
|
138
|
+
"w222Micrometers",
|
|
139
|
+
"w220Micrometers",
|
|
140
|
+
"w311Micrometers"
|
|
141
|
+
];
|
|
142
|
+
function parseSeidel(value) {
|
|
143
|
+
const result = {
|
|
144
|
+
w020Micrometers: 0,
|
|
145
|
+
w111Micrometers: 0,
|
|
146
|
+
w040Micrometers: 0,
|
|
147
|
+
w131Micrometers: 0,
|
|
148
|
+
w222Micrometers: 0,
|
|
149
|
+
w220Micrometers: 0,
|
|
150
|
+
w311Micrometers: 0
|
|
151
|
+
};
|
|
152
|
+
if (value === undefined)
|
|
153
|
+
return result;
|
|
154
|
+
if (typeof value !== "object" || value === null) {
|
|
155
|
+
throw new InvalidConfigurationError("seidelCoefficients must be an object.");
|
|
156
|
+
}
|
|
157
|
+
for (const key of Object.keys(value)) {
|
|
158
|
+
if (!SEIDEL_KEYS.includes(key)) {
|
|
159
|
+
throw new InvalidConfigurationError(`seidelCoefficients.${key} is not supported.`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
for (const key of SEIDEL_KEYS) {
|
|
163
|
+
if (value[key] !== undefined) {
|
|
164
|
+
result[key] = requireFinite(`seidelCoefficients.${key}`, value[key]);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
function pointInPolygon(x, y, vertices) {
|
|
170
|
+
let inside = false;
|
|
171
|
+
for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i, i += 1) {
|
|
172
|
+
const a = vertices[i];
|
|
173
|
+
const b = vertices[j];
|
|
174
|
+
if (a.y > y !== b.y > y &&
|
|
175
|
+
x < ((b.x - a.x) * (y - a.y)) / (b.y - a.y) + a.x) {
|
|
176
|
+
inside = !inside;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return inside;
|
|
180
|
+
}
|
|
181
|
+
function parseMask(value) {
|
|
182
|
+
if (value === undefined)
|
|
183
|
+
return undefined;
|
|
184
|
+
if (!Array.isArray(value) || value.length < 3 || value.length > 4096) {
|
|
185
|
+
throw new InvalidScientificInputError("apertureMaskVerticesMm must contain 3 through 4096 vertices.");
|
|
186
|
+
}
|
|
187
|
+
return value.map((vertex, index) => {
|
|
188
|
+
if (typeof vertex !== "object" || vertex === null) {
|
|
189
|
+
throw new InvalidConfigurationError(`apertureMaskVerticesMm[${index}] must be an object.`);
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
x: requireFinite(`apertureMaskVerticesMm[${index}].x`, vertex.x),
|
|
193
|
+
y: requireFinite(`apertureMaskVerticesMm[${index}].y`, vertex.y)
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Builds a complex-pupil grid: a circular pupil, an optional polygon mask, and an OPD from Zernike
|
|
199
|
+
* coefficients, Seidel coefficients or both. If every coefficient is zero, the OPD is exactly zero,
|
|
200
|
+
* so the PSF equals the existing aberration-free circular-pupil reference.
|
|
201
|
+
*/
|
|
202
|
+
export function createWavefrontPupilGrid(input) {
|
|
203
|
+
requireInputKeys(input, "createWavefrontPupilGrid", ["pupilDiameterMm", "samplesAcross", "zernikeCoefficients", "seidelCoefficients", "seidelField", "apertureMaskVerticesMm"]);
|
|
204
|
+
requirePositiveFinite("pupilDiameterMm", input.pupilDiameterMm);
|
|
205
|
+
const n = input.samplesAcross;
|
|
206
|
+
if (!Number.isSafeInteger(n) ||
|
|
207
|
+
n < 3 ||
|
|
208
|
+
n > ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS ||
|
|
209
|
+
n % 2 === 0) {
|
|
210
|
+
throw new InvalidScientificInputError(`samplesAcross must be an odd integer from 3 through ${ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS}.`);
|
|
211
|
+
}
|
|
212
|
+
const zernike = parseZernike(input.zernikeCoefficients);
|
|
213
|
+
const seidel = parseSeidel(input.seidelCoefficients);
|
|
214
|
+
const mask = parseMask(input.apertureMaskVerticesMm);
|
|
215
|
+
const fieldDependent = seidel.w111Micrometers !== 0 ||
|
|
216
|
+
seidel.w131Micrometers !== 0 ||
|
|
217
|
+
seidel.w222Micrometers !== 0 ||
|
|
218
|
+
seidel.w220Micrometers !== 0 ||
|
|
219
|
+
seidel.w311Micrometers !== 0;
|
|
220
|
+
let fieldHeight = 0;
|
|
221
|
+
let fieldAzimuth = 0;
|
|
222
|
+
if (input.seidelField !== undefined) {
|
|
223
|
+
if (typeof input.seidelField !== "object" || input.seidelField === null) {
|
|
224
|
+
throw new InvalidConfigurationError("seidelField must be an object.");
|
|
225
|
+
}
|
|
226
|
+
fieldHeight = requireFinite("seidelField.normalizedFieldHeight", input.seidelField.normalizedFieldHeight);
|
|
227
|
+
if (fieldHeight < 0 || fieldHeight > 1) {
|
|
228
|
+
throw new InvalidScientificInputError("seidelField.normalizedFieldHeight must lie in [0, 1].");
|
|
229
|
+
}
|
|
230
|
+
fieldAzimuth =
|
|
231
|
+
(requireFinite("seidelField.fieldAzimuthDegrees", input.seidelField.fieldAzimuthDegrees) *
|
|
232
|
+
Math.PI) /
|
|
233
|
+
180;
|
|
234
|
+
}
|
|
235
|
+
else if (fieldDependent) {
|
|
236
|
+
throw new InvalidScientificInputError("seidelField is required when a field-dependent Seidel coefficient is non-zero.");
|
|
237
|
+
}
|
|
238
|
+
const radiusMm = input.pupilDiameterMm / 2;
|
|
239
|
+
const pitch = input.pupilDiameterMm / (n - 1);
|
|
240
|
+
const center = (n - 1) / 2;
|
|
241
|
+
const amplitude = [];
|
|
242
|
+
const opd = [];
|
|
243
|
+
const open = [];
|
|
244
|
+
for (let row = 0; row < n; row += 1) {
|
|
245
|
+
for (let column = 0; column < n; column += 1) {
|
|
246
|
+
const xMm = (column - center) * pitch;
|
|
247
|
+
const yMm = (row - center) * pitch;
|
|
248
|
+
const rho = Math.hypot(xMm, yMm) / radiusMm;
|
|
249
|
+
const inside = rho <= 1 + 1e-12 && (mask === undefined || pointInPolygon(xMm, yMm, mask));
|
|
250
|
+
if (!inside) {
|
|
251
|
+
amplitude.push(0);
|
|
252
|
+
opd.push(0);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const r = Math.min(1, rho);
|
|
256
|
+
const theta = Math.atan2(yMm, xMm);
|
|
257
|
+
let w = 0;
|
|
258
|
+
for (const term of zernike) {
|
|
259
|
+
if (term.coefficientMicrometers !== 0) {
|
|
260
|
+
w += term.coefficientMicrometers * evaluateZernikePolynomial(term.nollIndex, r, theta);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const cosPhi = Math.cos(theta - fieldAzimuth);
|
|
264
|
+
const r2 = r * r;
|
|
265
|
+
w +=
|
|
266
|
+
seidel.w020Micrometers * r2 +
|
|
267
|
+
seidel.w040Micrometers * r2 * r2 +
|
|
268
|
+
seidel.w111Micrometers * fieldHeight * r * cosPhi +
|
|
269
|
+
seidel.w131Micrometers * fieldHeight * r2 * r * cosPhi +
|
|
270
|
+
seidel.w222Micrometers * fieldHeight * fieldHeight * r2 * cosPhi * cosPhi +
|
|
271
|
+
seidel.w220Micrometers * fieldHeight * fieldHeight * r2 +
|
|
272
|
+
seidel.w311Micrometers * fieldHeight ** 3 * r * cosPhi;
|
|
273
|
+
amplitude.push(1);
|
|
274
|
+
opd.push(w);
|
|
275
|
+
open.push(w);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (open.length === 0) {
|
|
279
|
+
throw new InvalidScientificInputError("The aperture mask leaves no open pupil samples.");
|
|
280
|
+
}
|
|
281
|
+
const mean = open.reduce((sum, value) => sum + value, 0) / open.length;
|
|
282
|
+
const variance = open.reduce((sum, value) => sum + (value - mean) ** 2, 0) / open.length;
|
|
283
|
+
const zernikeRms = Math.sqrt(zernike
|
|
284
|
+
.filter((term) => term.nollIndex >= 2)
|
|
285
|
+
.reduce((sum, term) => sum + term.coefficientMicrometers ** 2, 0));
|
|
286
|
+
return approximationResult({
|
|
287
|
+
grid: {
|
|
288
|
+
widthSamples: n,
|
|
289
|
+
heightSamples: n,
|
|
290
|
+
pupilSamplePitchMmX: pitch,
|
|
291
|
+
pupilSamplePitchMmY: pitch,
|
|
292
|
+
centerSampleX: center,
|
|
293
|
+
centerSampleY: center,
|
|
294
|
+
relativeAmplitude: amplitude,
|
|
295
|
+
opticalPathDifferenceMicrometers: opd
|
|
296
|
+
},
|
|
297
|
+
pupilDiameterMm: input.pupilDiameterMm,
|
|
298
|
+
openSampleCount: open.length,
|
|
299
|
+
zernikeRmsMicrometers: zernikeRms,
|
|
300
|
+
sampledRmsMicrometers: Math.sqrt(variance),
|
|
301
|
+
sampledPeakToValleyMicrometers: Math.max(...open) - Math.min(...open)
|
|
302
|
+
}, "zernike-seidel-wavefront-pupil-grid", "1.0.0", [
|
|
303
|
+
"Uniform unit amplitude inside the circular pupil (and inside the optional polygon mask); zero outside",
|
|
304
|
+
"Noll-indexed, unit-RMS Zernike polynomials over the unit disk; Seidel terms are peak wave-aberration coefficients",
|
|
305
|
+
"Pupil coordinates are metric and aligned with the image plane (+X right, +Y up)",
|
|
306
|
+
"Sampled RMS differs slightly from the continuous Zernike RMS because the disk is represented by discrete samples",
|
|
307
|
+
"Coefficients are caller inputs; no named-lens calibration is implied"
|
|
308
|
+
]);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Converts a signed paraxial image-plane defocus into the defocus wave aberration
|
|
312
|
+
* W020 = dz / (8 N^2) and its Noll Z4 coefficient W020 / (2 sqrt 3).
|
|
313
|
+
*
|
|
314
|
+
* Sign convention: dz = sensor distance minus image distance. Positive W020 means the image lies in
|
|
315
|
+
* front of the sensor. With pure defocus, the PSF intensity does not depend on the sign.
|
|
316
|
+
*/
|
|
317
|
+
export function calculateDefocusWavefront(input) {
|
|
318
|
+
requireInputKeys(input, "calculateDefocusWavefront", ["signedDefocusImagePlaneMicrometers", "workingFNumber"]);
|
|
319
|
+
const dz = requireFinite("signedDefocusImagePlaneMicrometers", input.signedDefocusImagePlaneMicrometers);
|
|
320
|
+
requirePositiveFinite("workingFNumber", input.workingFNumber);
|
|
321
|
+
const w020 = dz / (8 * input.workingFNumber * input.workingFNumber);
|
|
322
|
+
return calculatedResult({
|
|
323
|
+
signedDefocusImagePlaneMicrometers: dz,
|
|
324
|
+
workingFNumber: input.workingFNumber,
|
|
325
|
+
w020Micrometers: w020,
|
|
326
|
+
zernikeZ4Micrometers: w020 / (2 * Math.sqrt(3))
|
|
327
|
+
}, "paraxial-defocus-wavefront", "1.0.0", [
|
|
328
|
+
"Paraxial (small-angle) relation between longitudinal image-plane defocus and the rho^2 wave aberration",
|
|
329
|
+
"Sign convention: defocus is sensor minus image distance"
|
|
330
|
+
]);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Marechal/Mahajan approximation of the Strehl ratio: exp(-(2 pi sigma / lambda)^2). Valid only for a
|
|
334
|
+
* small RMS wavefront error (Strehl roughly above 0.3). It is not an exact PSF calculation.
|
|
335
|
+
*/
|
|
336
|
+
export function estimateMarechalStrehlRatio(input) {
|
|
337
|
+
requireInputKeys(input, "estimateMarechalStrehlRatio", ["rmsWavefrontErrorMicrometers", "wavelengthNm"]);
|
|
338
|
+
const sigma = requireFinite("rmsWavefrontErrorMicrometers", input.rmsWavefrontErrorMicrometers);
|
|
339
|
+
if (sigma < 0) {
|
|
340
|
+
throw new InvalidScientificInputError("rmsWavefrontErrorMicrometers must be non-negative.");
|
|
341
|
+
}
|
|
342
|
+
requirePositiveFinite("wavelengthNm", input.wavelengthNm);
|
|
343
|
+
const rmsWaves = sigma / (input.wavelengthNm / 1000);
|
|
344
|
+
return approximationResult({
|
|
345
|
+
strehlRatio: Math.exp(-((2 * Math.PI * rmsWaves) ** 2)),
|
|
346
|
+
rmsWaves
|
|
347
|
+
}, "marechal-mahajan-strehl-approximation", "1.0.0", [
|
|
348
|
+
"Strehl ratio approximated as exp(-(2 pi sigma / lambda)^2) (Marechal 1947; Mahajan 1982)",
|
|
349
|
+
"Valid for small RMS wavefront error, roughly Strehl above 0.3; it is not an exact PSF evaluation"
|
|
350
|
+
]);
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=zernike-wavefront.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zernike-wavefront.js","sourceRoot":"","sources":["../../src/optics/zernike-wavefront.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Describes lens aberrations as a wavefront, for the complex-pupil PSF (point-spread function)\n * reference.\n *\n * This module builds the declared pupil grid: relative amplitude plus optical path difference (OPD)\n * in micrometres. calculateLensComplexPupilPsf() uses that grid unchanged. This module does no light\n * propagation itself.\n *\n * Zernike polynomials use Noll's single index j >= 1 and Noll's normalisation (Noll 1976, JOSA\n * 66:207):\n * - m = 0: Z_j = sqrt(n + 1) R_n^0(rho)\n * - m != 0: Z_j = sqrt(2 (n + 1)) R_n^|m|(rho) cos(m theta) for even j, or sin(m theta) for odd j\n * So each term has an RMS of 1 over the unit disk. The RMS wavefront error of sum_j c_j Z_j (piston\n * excluded) is sqrt(sum_{j>=2} c_j^2). The radial polynomial R_n^m is the standard one in Noll's\n * nomenclature (Mathar, arXiv:0809.2368, eq. 1, free). Also see: Born & Wolf, Principles of Optics,\n * 7th ed., sec. 9.2 and app. VII.\n *\n * Primary (Seidel) aberrations use the wave-aberration expansion in normalised field height H and\n * normalised pupil coordinates (rho, phi), phi measured from the field direction (Hopkins 1950,\n * Wave Theory of Aberrations; Wyant & Creath 1992, Applied Optics and Optical Engineering XI ch. 1):\n * W = W020 rho^2 + W111 H rho cos(phi) + W040 rho^4 + W131 H rho^3 cos(phi)\n * + W222 H^2 rho^2 cos^2(phi) + W220 H^2 rho^2 + W311 H^3 rho cos(phi).\n *\n * Paraxial defocus: an image-plane defocus dz at working f-number N gives W020 = dz / (8 N^2)\n * (Wyant & Creath 1992, Applied Optics and Optical Engineering XI ch. 1, eq. 18, free author copy.\n * Also see: Goodman, Introduction to Fourier Optics, 3rd ed., sec. 6.4; Mahajan, Optical Imaging and\n * Aberrations Part I, sec. 3.4). That is a Zernike Z4 coefficient of W020 / (2 sqrt 3).\n *\n * Marechal/Mahajan approximation: Strehl ratio ~ exp(-(2 pi sigma / lambda)^2) for a small RMS\n * wavefront error sigma (Marechal 1947; Mahajan 1982 JOSA 72:1258; free: Wyant & Creath 1992,\n * ch. 1, eq. 67). It is an approximation, valid\n * roughly for Strehl ratios above 0.3.\n *\n * Pupil coordinates are in metric units, aligned with the image plane (+X right, +Y up). theta is\n * measured counter-clockwise from +X.\n * @see docs/PSF_FOUNDATION.md for the equations, units, coordinate conventions, known blockers and\n * support limits.\n */\n\nimport {\n approximationResult,\n calculatedResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport {\n InvalidScientificInputError,\n requirePositiveFinite\n} from \"../core/validation.js\";\nimport type { LensComplexPupilGrid } from \"./complex-pupil-psf.js\";\nimport { requireInputKeys } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\n/** Largest supported Noll index (radial order n <= 10). */\nexport const ZERNIKE_MAXIMUM_NOLL_INDEX = 66;\n/** Largest odd pupil grid width: 63 x 63 = 3969 samples, within the complex-pupil 4096 limit. */\nexport const ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS = 63;\n\nexport interface ZernikeOrder {\n nollIndex: number;\n /** Radial order n. */\n radialOrder: number;\n /** Signed azimuthal frequency m. Positive means cos(m theta); negative means sin(|m| theta). */\n azimuthalFrequency: number;\n}\n\nexport interface ZernikeCoefficient {\n nollIndex: number;\n /** Coefficient of the unit-RMS Noll polynomial, in micrometres of optical path difference. */\n coefficientMicrometers: number;\n}\n\n/** Peak Seidel wave-aberration coefficients in micrometres of optical path difference. */\nexport interface SeidelWavefrontCoefficients {\n /** Defocus rho^2. */\n w020Micrometers?: number;\n /** Tilt H rho cos(phi). */\n w111Micrometers?: number;\n /** Spherical aberration rho^4. */\n w040Micrometers?: number;\n /** Coma H rho^3 cos(phi). */\n w131Micrometers?: number;\n /** Astigmatism H^2 rho^2 cos^2(phi). */\n w222Micrometers?: number;\n /** Field curvature H^2 rho^2. */\n w220Micrometers?: number;\n /** Distortion H^3 rho cos(phi). */\n w311Micrometers?: number;\n}\n\nexport interface SeidelFieldPosition {\n /** Normalised field height H in [0, 1]. */\n normalizedFieldHeight: number;\n /** Image-plane direction of the field point, degrees counter-clockwise from +X. */\n fieldAzimuthDegrees: number;\n}\n\nexport interface CreateWavefrontPupilGridInput {\n /** Pupil diameter in mm; rho = 1 at radius pupilDiameterMm / 2. */\n pupilDiameterMm: number;\n /** Odd number of samples across the pupil diameter, from 3 to 63. */\n samplesAcross: number;\n zernikeCoefficients?: readonly ZernikeCoefficient[];\n seidelCoefficients?: SeidelWavefrontCoefficients;\n /** Required when any field-dependent Seidel coefficient is non-zero. */\n seidelField?: SeidelFieldPosition;\n /**\n * Optional additional aperture mask: a simple polygon in pupil-plane mm (for example the\n * cat's-eye pupil from calculateMechanicalVignetting). Samples outside it get zero amplitude.\n */\n apertureMaskVerticesMm?: readonly { x: number; y: number }[];\n}\n\nexport interface WavefrontPupilGrid {\n /** Grid for LensComplexPupilProfile.grid. Amplitude is 1 inside and 0 outside; OPD is in micrometres. */\n grid: LensComplexPupilGrid;\n pupilDiameterMm: number;\n /** Number of samples with non-zero amplitude. */\n openSampleCount: number;\n /** sqrt(sum c_j^2, j >= 2): RMS of the Zernike terms alone over the continuous unit disk. */\n zernikeRmsMicrometers: number;\n /** RMS of the sampled OPD over open samples, with piston removed (all terms). */\n sampledRmsMicrometers: number;\n /** Peak-to-valley of the sampled OPD over open samples. */\n sampledPeakToValleyMicrometers: number;\n}\n\nexport interface CalculateDefocusWavefrontInput {\n /** Signed image-plane defocus, sensor minus image distance, in micrometres. */\n signedDefocusImagePlaneMicrometers: number;\n /** Image-side working f-number (image distance / pupil diameter). */\n workingFNumber: number;\n}\n\nexport interface DefocusWavefront {\n signedDefocusImagePlaneMicrometers: number;\n workingFNumber: number;\n /** Peak defocus coefficient W020 = dz / (8 N^2), micrometres. */\n w020Micrometers: number;\n /** Equivalent Noll Z4 coefficient W020 / (2 sqrt 3), micrometres (equals the RMS). */\n zernikeZ4Micrometers: number;\n}\n\nexport interface EstimateMarechalStrehlRatioInput {\n rmsWavefrontErrorMicrometers: number;\n wavelengthNm: number;\n}\n\nfunction requireFinite(name: string, value: unknown): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new InvalidScientificInputError(`${name} must be finite.`);\n }\n return value;\n}\n\nfunction requireNollIndex(value: unknown): number {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n value < 1 ||\n value > ZERNIKE_MAXIMUM_NOLL_INDEX\n ) {\n throw new InvalidScientificInputError(\n `nollIndex must be an integer from 1 through ${ZERNIKE_MAXIMUM_NOLL_INDEX}.`\n );\n }\n return value;\n}\n\n/** Converts a Noll index to radial order n and signed azimuthal frequency m (Noll 1976). */\nexport function resolveZernikeNollOrder(nollIndex: number): ZernikeOrder {\n const j = requireNollIndex(nollIndex);\n let n = 0;\n while (((n + 1) * (n + 2)) / 2 < j) {\n n += 1;\n }\n // Position within radial order n; |m| increases with it, two indices per non-zero |m|.\n const k = j - (n * (n + 1)) / 2 - 1;\n const absoluteM =\n n % 2 === 0 ? 2 * Math.floor((k + 1) / 2) : 2 * Math.floor(k / 2) + 1;\n return {\n nollIndex: j,\n radialOrder: n,\n azimuthalFrequency:\n absoluteM === 0 ? 0 : j % 2 === 0 ? absoluteM : -absoluteM\n };\n}\n\nfunction factorial(value: number): number {\n let result = 1;\n for (let k = 2; k <= value; k += 1) result *= k;\n return result;\n}\n\nfunction radialPolynomial(n: number, m: number, rho: number): number {\n let sum = 0;\n for (let k = 0; k <= (n - m) / 2; k += 1) {\n const coefficient =\n ((k % 2 === 0 ? 1 : -1) * factorial(n - k)) /\n (factorial(k) * factorial((n + m) / 2 - k) * factorial((n - m) / 2 - k));\n sum += coefficient * rho ** (n - 2 * k);\n }\n return sum;\n}\n\n/** Evaluates the unit-RMS Noll Zernike polynomial at normalised pupil polar coordinates. */\nexport function evaluateZernikePolynomial(\n nollIndex: number,\n normalizedRadius: number,\n azimuthRadians: number\n): number {\n const order = resolveZernikeNollOrder(nollIndex);\n const rho = requireFinite(\"normalizedRadius\", normalizedRadius);\n const theta = requireFinite(\"azimuthRadians\", azimuthRadians);\n if (rho < 0 || rho > 1 + 1e-12) {\n throw new InvalidScientificInputError(\n \"normalizedRadius must lie in [0, 1].\"\n );\n }\n const n = order.radialOrder;\n const m = Math.abs(order.azimuthalFrequency);\n const radial = radialPolynomial(n, m, Math.min(1, rho));\n if (m === 0) {\n return Math.sqrt(n + 1) * radial;\n }\n const angular =\n order.azimuthalFrequency > 0 ? Math.cos(m * theta) : Math.sin(m * theta);\n return Math.sqrt(2 * (n + 1)) * radial * angular;\n}\n\nfunction parseZernike(\n value: readonly ZernikeCoefficient[] | undefined\n): ZernikeCoefficient[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(\"zernikeCoefficients must be an array.\");\n }\n const seen = new Set<number>();\n return value.map((entry, index) => {\n if (typeof entry !== \"object\" || entry === null) {\n throw new InvalidConfigurationError(`zernikeCoefficients[${index}] must be an object.`);\n }\n const nollIndex = requireNollIndex(entry.nollIndex);\n if (seen.has(nollIndex)) {\n throw new InvalidScientificInputError(\"zernikeCoefficients must not repeat a nollIndex.\");\n }\n seen.add(nollIndex);\n return {\n nollIndex,\n coefficientMicrometers: requireFinite(\n `zernikeCoefficients[${index}].coefficientMicrometers`,\n entry.coefficientMicrometers\n )\n };\n });\n}\n\nconst SEIDEL_KEYS = [\n \"w020Micrometers\",\n \"w111Micrometers\",\n \"w040Micrometers\",\n \"w131Micrometers\",\n \"w222Micrometers\",\n \"w220Micrometers\",\n \"w311Micrometers\"\n] as const;\n\nfunction parseSeidel(\n value: SeidelWavefrontCoefficients | undefined\n): Required<SeidelWavefrontCoefficients> {\n const result = {\n w020Micrometers: 0,\n w111Micrometers: 0,\n w040Micrometers: 0,\n w131Micrometers: 0,\n w222Micrometers: 0,\n w220Micrometers: 0,\n w311Micrometers: 0\n };\n if (value === undefined) return result;\n if (typeof value !== \"object\" || value === null) {\n throw new InvalidConfigurationError(\"seidelCoefficients must be an object.\");\n }\n for (const key of Object.keys(value)) {\n if (!(SEIDEL_KEYS as readonly string[]).includes(key)) {\n throw new InvalidConfigurationError(`seidelCoefficients.${key} is not supported.`);\n }\n }\n for (const key of SEIDEL_KEYS) {\n if (value[key] !== undefined) {\n result[key] = requireFinite(`seidelCoefficients.${key}`, value[key]);\n }\n }\n return result;\n}\n\nfunction pointInPolygon(\n x: number,\n y: number,\n vertices: readonly { x: number; y: number }[]\n): boolean {\n let inside = false;\n for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i, i += 1) {\n const a = vertices[i]!;\n const b = vertices[j]!;\n if (\n a.y > y !== b.y > y &&\n x < ((b.x - a.x) * (y - a.y)) / (b.y - a.y) + a.x\n ) {\n inside = !inside;\n }\n }\n return inside;\n}\n\nfunction parseMask(\n value: readonly { x: number; y: number }[] | undefined\n): readonly { x: number; y: number }[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value) || value.length < 3 || value.length > 4096) {\n throw new InvalidScientificInputError(\n \"apertureMaskVerticesMm must contain 3 through 4096 vertices.\"\n );\n }\n return value.map((vertex, index) => {\n if (typeof vertex !== \"object\" || vertex === null) {\n throw new InvalidConfigurationError(`apertureMaskVerticesMm[${index}] must be an object.`);\n }\n return {\n x: requireFinite(`apertureMaskVerticesMm[${index}].x`, vertex.x),\n y: requireFinite(`apertureMaskVerticesMm[${index}].y`, vertex.y)\n };\n });\n}\n\n/**\n * Builds a complex-pupil grid: a circular pupil, an optional polygon mask, and an OPD from Zernike\n * coefficients, Seidel coefficients or both. If every coefficient is zero, the OPD is exactly zero,\n * so the PSF equals the existing aberration-free circular-pupil reference.\n */\nexport function createWavefrontPupilGrid(\n input: CreateWavefrontPupilGridInput\n): CalculationResult<WavefrontPupilGrid> {\n requireInputKeys(input, \"createWavefrontPupilGrid\", [\"pupilDiameterMm\", \"samplesAcross\", \"zernikeCoefficients\", \"seidelCoefficients\", \"seidelField\", \"apertureMaskVerticesMm\"]);\n requirePositiveFinite(\"pupilDiameterMm\", input.pupilDiameterMm);\n const n = input.samplesAcross;\n if (\n !Number.isSafeInteger(n) ||\n n < 3 ||\n n > ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS ||\n n % 2 === 0\n ) {\n throw new InvalidScientificInputError(\n `samplesAcross must be an odd integer from 3 through ${ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS}.`\n );\n }\n const zernike = parseZernike(input.zernikeCoefficients);\n const seidel = parseSeidel(input.seidelCoefficients);\n const mask = parseMask(input.apertureMaskVerticesMm);\n const fieldDependent =\n seidel.w111Micrometers !== 0 ||\n seidel.w131Micrometers !== 0 ||\n seidel.w222Micrometers !== 0 ||\n seidel.w220Micrometers !== 0 ||\n seidel.w311Micrometers !== 0;\n let fieldHeight = 0;\n let fieldAzimuth = 0;\n if (input.seidelField !== undefined) {\n if (typeof input.seidelField !== \"object\" || input.seidelField === null) {\n throw new InvalidConfigurationError(\"seidelField must be an object.\");\n }\n fieldHeight = requireFinite(\n \"seidelField.normalizedFieldHeight\",\n input.seidelField.normalizedFieldHeight\n );\n if (fieldHeight < 0 || fieldHeight > 1) {\n throw new InvalidScientificInputError(\n \"seidelField.normalizedFieldHeight must lie in [0, 1].\"\n );\n }\n fieldAzimuth =\n (requireFinite(\"seidelField.fieldAzimuthDegrees\", input.seidelField.fieldAzimuthDegrees) *\n Math.PI) /\n 180;\n } else if (fieldDependent) {\n throw new InvalidScientificInputError(\n \"seidelField is required when a field-dependent Seidel coefficient is non-zero.\"\n );\n }\n\n const radiusMm = input.pupilDiameterMm / 2;\n const pitch = input.pupilDiameterMm / (n - 1);\n const center = (n - 1) / 2;\n const amplitude: number[] = [];\n const opd: number[] = [];\n const open: number[] = [];\n for (let row = 0; row < n; row += 1) {\n for (let column = 0; column < n; column += 1) {\n const xMm = (column - center) * pitch;\n const yMm = (row - center) * pitch;\n const rho = Math.hypot(xMm, yMm) / radiusMm;\n const inside =\n rho <= 1 + 1e-12 && (mask === undefined || pointInPolygon(xMm, yMm, mask));\n if (!inside) {\n amplitude.push(0);\n opd.push(0);\n continue;\n }\n const r = Math.min(1, rho);\n const theta = Math.atan2(yMm, xMm);\n let w = 0;\n for (const term of zernike) {\n if (term.coefficientMicrometers !== 0) {\n w += term.coefficientMicrometers * evaluateZernikePolynomial(term.nollIndex, r, theta);\n }\n }\n const cosPhi = Math.cos(theta - fieldAzimuth);\n const r2 = r * r;\n w +=\n seidel.w020Micrometers * r2 +\n seidel.w040Micrometers * r2 * r2 +\n seidel.w111Micrometers * fieldHeight * r * cosPhi +\n seidel.w131Micrometers * fieldHeight * r2 * r * cosPhi +\n seidel.w222Micrometers * fieldHeight * fieldHeight * r2 * cosPhi * cosPhi +\n seidel.w220Micrometers * fieldHeight * fieldHeight * r2 +\n seidel.w311Micrometers * fieldHeight ** 3 * r * cosPhi;\n amplitude.push(1);\n opd.push(w);\n open.push(w);\n }\n }\n if (open.length === 0) {\n throw new InvalidScientificInputError(\n \"The aperture mask leaves no open pupil samples.\"\n );\n }\n const mean = open.reduce((sum, value) => sum + value, 0) / open.length;\n const variance =\n open.reduce((sum, value) => sum + (value - mean) ** 2, 0) / open.length;\n const zernikeRms = Math.sqrt(\n zernike\n .filter((term) => term.nollIndex >= 2)\n .reduce((sum, term) => sum + term.coefficientMicrometers ** 2, 0)\n );\n\n return approximationResult(\n {\n grid: {\n widthSamples: n,\n heightSamples: n,\n pupilSamplePitchMmX: pitch,\n pupilSamplePitchMmY: pitch,\n centerSampleX: center,\n centerSampleY: center,\n relativeAmplitude: amplitude,\n opticalPathDifferenceMicrometers: opd\n },\n pupilDiameterMm: input.pupilDiameterMm,\n openSampleCount: open.length,\n zernikeRmsMicrometers: zernikeRms,\n sampledRmsMicrometers: Math.sqrt(variance),\n sampledPeakToValleyMicrometers: Math.max(...open) - Math.min(...open)\n },\n \"zernike-seidel-wavefront-pupil-grid\",\n \"1.0.0\",\n [\n \"Uniform unit amplitude inside the circular pupil (and inside the optional polygon mask); zero outside\",\n \"Noll-indexed, unit-RMS Zernike polynomials over the unit disk; Seidel terms are peak wave-aberration coefficients\",\n \"Pupil coordinates are metric and aligned with the image plane (+X right, +Y up)\",\n \"Sampled RMS differs slightly from the continuous Zernike RMS because the disk is represented by discrete samples\",\n \"Coefficients are caller inputs; no named-lens calibration is implied\"\n ]\n );\n}\n\n/**\n * Converts a signed paraxial image-plane defocus into the defocus wave aberration\n * W020 = dz / (8 N^2) and its Noll Z4 coefficient W020 / (2 sqrt 3).\n *\n * Sign convention: dz = sensor distance minus image distance. Positive W020 means the image lies in\n * front of the sensor. With pure defocus, the PSF intensity does not depend on the sign.\n */\nexport function calculateDefocusWavefront(\n input: CalculateDefocusWavefrontInput\n): CalculationResult<DefocusWavefront> {\n requireInputKeys(input, \"calculateDefocusWavefront\", [\"signedDefocusImagePlaneMicrometers\", \"workingFNumber\"]);\n const dz = requireFinite(\n \"signedDefocusImagePlaneMicrometers\",\n input.signedDefocusImagePlaneMicrometers\n );\n requirePositiveFinite(\"workingFNumber\", input.workingFNumber);\n const w020 = dz / (8 * input.workingFNumber * input.workingFNumber);\n return calculatedResult(\n {\n signedDefocusImagePlaneMicrometers: dz,\n workingFNumber: input.workingFNumber,\n w020Micrometers: w020,\n zernikeZ4Micrometers: w020 / (2 * Math.sqrt(3))\n },\n \"paraxial-defocus-wavefront\",\n \"1.0.0\",\n [\n \"Paraxial (small-angle) relation between longitudinal image-plane defocus and the rho^2 wave aberration\",\n \"Sign convention: defocus is sensor minus image distance\"\n ]\n );\n}\n\n/**\n * Marechal/Mahajan approximation of the Strehl ratio: exp(-(2 pi sigma / lambda)^2). Valid only for a\n * small RMS wavefront error (Strehl roughly above 0.3). It is not an exact PSF calculation.\n */\nexport function estimateMarechalStrehlRatio(\n input: EstimateMarechalStrehlRatioInput\n): CalculationResult<{ strehlRatio: number; rmsWaves: number }> {\n requireInputKeys(input, \"estimateMarechalStrehlRatio\", [\"rmsWavefrontErrorMicrometers\", \"wavelengthNm\"]);\n const sigma = requireFinite(\n \"rmsWavefrontErrorMicrometers\",\n input.rmsWavefrontErrorMicrometers\n );\n if (sigma < 0) {\n throw new InvalidScientificInputError(\n \"rmsWavefrontErrorMicrometers must be non-negative.\"\n );\n }\n requirePositiveFinite(\"wavelengthNm\", input.wavelengthNm);\n const rmsWaves = sigma / (input.wavelengthNm / 1000);\n return approximationResult(\n {\n strehlRatio: Math.exp(-((2 * Math.PI * rmsWaves) ** 2)),\n rmsWaves\n },\n \"marechal-mahajan-strehl-approximation\",\n \"1.0.0\",\n [\n \"Strehl ratio approximated as exp(-(2 pi sigma / lambda)^2) (Marechal 1947; Mahajan 1982)\",\n \"Valid for small RMS wavefront error, roughly Strehl above 0.3; it is not an exact PSF evaluation\"\n ]\n );\n}\n"]}
|
|
@@ -6,12 +6,15 @@ import { calculateLensCorrectedCapture, type GenericLensCorrectionProfile, type
|
|
|
6
6
|
import { type GeometricResampler } from "./geometric-transforms.js";
|
|
7
7
|
import { type RasterRect } from "./capture-geometry.js";
|
|
8
8
|
export declare const CAPTURE_CORRECTED_SDR_SCHEMA_VERSION: "0.1.0";
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Input: a capture plus an explicit lens-correction choice in native optical coordinates. Camera
|
|
11
|
+
* body, lens and mode identities are taken as the capture producer declared them.
|
|
12
|
+
*/
|
|
10
13
|
export interface CaptureCorrectedSdrInput extends CaptureSdrInput {
|
|
11
14
|
correction: {
|
|
12
15
|
profile: GenericLensCorrectionProfile;
|
|
13
16
|
state: OpticalProfileState;
|
|
14
|
-
/** Native optical +X right
|
|
17
|
+
/** Native optical coordinates (+X right, +Y up), in the RGB space after the selected colour/WB step. */
|
|
15
18
|
coordinateFrame: "native-optical-linear-srgb-d65";
|
|
16
19
|
selections: Readonly<Record<string, "on" | "off" | "auto">>;
|
|
17
20
|
selectionKind: ResolvedLensCorrectionPlan["selectionKind"];
|
|
@@ -23,14 +26,14 @@ export interface CaptureCorrectedSdrInput extends CaptureSdrInput {
|
|
|
23
26
|
outputImageStateId: string;
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
|
-
/**
|
|
29
|
+
/** A derived output view. It never replaces the committed capture's physical geometry. */
|
|
27
30
|
export interface CaptureCorrectedSdrResult extends Omit<CaptureSdrResult, "schemaVersion"> {
|
|
28
31
|
schemaVersion: typeof CAPTURE_CORRECTED_SDR_SCHEMA_VERSION;
|
|
29
32
|
sceneTimeSeconds: number;
|
|
30
33
|
plan: CalculationResult<ResolvedLensCorrectionPlan>;
|
|
31
34
|
correction: ReturnType<typeof calculateLensCorrectedCapture>;
|
|
32
35
|
projection: ReturnType<typeof calculateFieldOfView>;
|
|
33
|
-
/**
|
|
36
|
+
/** Valid-source mask over the full oriented output. The nested correction plans still use native optical coordinates. */
|
|
34
37
|
validSourceMask: readonly boolean[];
|
|
35
38
|
outputView: {
|
|
36
39
|
imageStateId: string;
|
|
@@ -40,10 +43,15 @@ export interface CaptureCorrectedSdrResult extends Omit<CaptureSdrResult, "schem
|
|
|
40
43
|
samples: readonly number[];
|
|
41
44
|
};
|
|
42
45
|
}
|
|
43
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Strictly parses untrusted input. Running the calculation also checks the capture's optics,
|
|
48
|
+
* native pixel-grid binding and source history.
|
|
49
|
+
*/
|
|
44
50
|
export declare function parseCaptureCorrectedSdrInput(input: unknown): CaptureCorrectedSdrInput;
|
|
45
|
-
/** Internal
|
|
51
|
+
/** Internal: validates the correction choice for exporters that start from a capture. It neither creates nor checks pixel values. */
|
|
46
52
|
export declare function parseCaptureCorrectionChoice(input: unknown, capture: CaptureSdrInput["capture"], forbiddenImageStateIds?: readonly string[]): CaptureCorrectedSdrInput["correction"];
|
|
47
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Runs a bounded committed capture through colour/WB → native lens correction → oriented output
|
|
55
|
+
* view → SDR. No physical simulation stage is run.
|
|
56
|
+
*/
|
|
48
57
|
export declare function calculateCaptureCorrectedSdr(input: CaptureCorrectedSdrInput): CalculationResult<CaptureCorrectedSdrResult>;
|
|
49
|
-
//# sourceMappingURL=capture-corrected-sdr.d.ts.map
|