Got actual solar spectrum data and incorporated it. Plus radiometry

This commit is contained in:
connor committed 2026-10-14 15:38:23 -04:00
1 parent 3eb7ec4808
commit cefcfe7e4e
7 files changed
+1281 -20

No files matched your search

+76 -14
View File
@@ -95,7 +95,7 @@ far plane.
## Radiometric quantities
Code: `spectrum.rs` now; `radiometry.rs` in #4.
Code: `spectrum.rs`, `radiometry.rs`.
Light has a few distinct measures, and the camera measures a specific one.
@@ -171,22 +171,78 @@ energy h c / lambda (h is Planck's constant, c the speed of light). So one
watt of red light delivers more photons than one watt of blue. The
renderer converts power to photons per wavelength before applying QE.
### The solar spectrum
Code: `radiometry.rs` (`solar_spectrum`), generated into `solar_data.rs` by
`scripts/fetch-solar-spectrum.sh`.
The renderer uses a measured solar spectrum, the TSIS-1 Hybrid Solar
Reference Spectrum (Coddington et al. 2021). It is the current
international reference, built mainly from the TSIS-1 instruments on the
International Space Station and filled in with a high-resolution model of
the solar absorption lines. It gives the irradiance at 1 AU, outside the atmosphere,
every 1 nm from 202 to 2730 nm. Its uncertainty is 0.3 % from 460 to
2365 nm. Over that range it sums to 1325.8 W/m^2. The other 35 W/m^2 of the
1361 W/m^2 total is at wavelengths silicon detectors do not see.
The Sun is often approximated as a 5772 K blackbody: a smooth curve with
the right total power. The real spectrum has thousands of absorption lines
from the Sun's outer layers, and its shape differs from the smooth curve.
For the example camera's channels, the blackbody gives 4.6 % (red), 7.5 %
(green) and 9.7 % (blue) fewer electrons than the measured spectrum. That
is far outside what absolute radiometry can tolerate.
### Folding spectra into per-channel constants
Code: `radiometry.rs` (`Radiometry`).
Doing all of this wavelength by wavelength for every pixel would be slow.
Most factors do not depend on the pixel: the solar spectrum, the optics,
and the QE curves. The renderer multiplies and integrates those over
wavelength once, when the camera is set up. That yields a few numbers per
channel, and the GPU only multiplies by them.
The cost is a small error where two spectra both vary inside one channel's
band. An example is a surface whose reflectance changes steeply across
green. Rendering more, narrower channels reduces that error, and the code
keeps the channel count generic for that reason. (#4)
The central number is the solar flux of each channel k:
```text
S_k = integral of E_sun(lambda) * tau(lambda) * QE_k(lambda) * lambda / (h c) d lambda
```
It is the rate of electrons per square meter that sunlight at 1 AU would
produce if it fell straight onto the detector through the optics. For the
example camera, S_k is about 2.4e20 electrons per second per m^2 in red and
green, and 2.0e20 in blue.
The renderer then works in channel radiance: scene radiance weighted the
same way (transmission, QE, photons per joule), in electrons per second
per m^2 per steradian. A Lambertian surface with albedo rho, lit at angle i
from its normal, at distance d from the Sun in AU, has channel radiance:
```text
L_k = rho * cos(i) * S_k / (pi * d^2)
```
The solar disk has channel radiance S_k / Omega_sun, where Omega_sun is the
Sun's solid angle at 1 AU, 6.79e-5 sr (it is 0.53 degrees across). Seen
from anywhere, the Sun's surface has that same radiance, about 2.0e7
W/m^2/sr in total. Looked at directly, it puts about 5e8 electrons into a
pixel of the example camera's green channel in 0.1 ms, 26,000 times the
full well.
A surface whose reflectance varies with wavelength is reduced to an
effective albedo per channel. That is the albedo of a flat-spectrum surface
that would give the same signal under sunlight
(`Radiometry::effective_albedo`). This step is where the error of the
shortcut comes in. Two spectra that both vary inside one channel's band
interact in ways a single number per channel cannot capture. One example is
a surface whose reflectance changes steeply across green, lit partly by
sunlight and partly by bluish light scattered from Earth's atmosphere.
Rendering more, narrower channels reduces that error, and the code keeps
the channel count generic for that reason.
## From radiance to electrons: the camera equation
Code: the sensor pass, #9.
Code: `radiometry.rs` (`Radiometry::electrons`); the sensor pass, #9.
A lens with focal length f and aperture diameter D has f-number
N = f / D. The example camera is f/4: a 50 mm lens with a 12.5 mm aperture.
@@ -215,8 +271,14 @@ The electrons a pixel collects in one channel are then:
electrons = E_image * (pixel area) * (exposure time) * (photons per joule) * QE
```
The last two factors are wavelength-dependent and are folded together per
channel, as described above.
The last two factors are wavelength-dependent. In channel radiance they are
already folded in, so the camera equation reduces to
```text
electrons = L_k * pi * (pixel area) * (exposure time) / (4 N^2) * cos^4(theta)
```
For the example camera, pi * A * t / (4 N^2) is 1.48e-16 m^2 sr s.
## From electrons to DN: the detector
@@ -238,14 +300,14 @@ So DN = bias + electrons / gain, rounded and clipped to the ADC range.
Take a white Lambertian surface facing the Sun at 1 AU, seen by the example
camera's green channel. Integrating the solar spectrum through the green QE
curve, f/4 optics, 5.5 um pixels and a 0.1 ms exposure gives about 10,300
electrons. That figure came from a blackbody approximation of the Sun; #4
replaces it with the measured solar spectrum.
curve, f/4 optics, 5.5 um pixels and a 0.1 ms exposure gives 11,139
electrons. Red gets 11,408 and blue 9,626. (A test in `radiometry.rs`
checks the green figure.)
- DN = 64 + 10,300 / 5, about 2125, roughly half the 12-bit range.
- The full well is 20,000 electrons, so this surface is at about half of
- DN = 64 + 11,139 / 5, about 2292, a little over half the 12-bit range.
- The full well is 20,000 electrons, so this surface is at 56 % of
saturation.
- Earth, with albedo near 0.3, reads about 64 + 3,100 / 5, about 682 DN.
- Earth, with albedo near 0.3, reads about 64 + 3,342 / 5, about 732 DN.
Picking the exposure time is the same trade a photographer makes. A longer
exposure saturates the sunlit target. A shorter one leaves the side of the