Simple Sensor¶
-
template<IsSpectral TSpectral>
class SimpleSensor : public huira::SensorModel<TSpectral>¶ Simple sensor model with basic noise and ADC simulation.
Implements a basic sensor readout model, including shot noise, read noise, and quantization.
- Template Parameters:
TSpectral – The spectral type (e.g., RGB, Visible8)
Public Functions
-
~SimpleSensor() override = default¶
-
SimpleSensor(const SimpleSensor&) = default¶
A copy has the same settings and a noise seed of its own (see SensorModel).
-
SimpleSensor(SimpleSensor&&) noexcept = default¶
-
SimpleSensor &operator=(const SimpleSensor&) = default¶
-
SimpleSensor &operator=(SimpleSensor&&) noexcept = default¶
-
virtual void readout(FrameBuffer<TSpectral> &fb, units::Second exposure_time) const override¶
Simulates the sensor readout, from the received power to digital numbers (DN).
For each pixel (each channel, for RGB): the received energy becomes photons and, through the quantum efficiency, signal electrons, to which the dark current’s electrons are added. With noise simulated, the electrons collected are drawn from a Poisson distribution of that mean (shot noise); without, they are the mean. They are clamped to the full well, and the read noise is added (with noise simulated). The ADC divides by the gain, adds the bias, rounds to a whole number of DN and clamps to its range, [0, 2^bit_depth - 1]. The response holds DN / (2^bit_depth - 1), so its values are exact fractions of whole DN, and the image records the bit depth (Image::sensor_bit_depth()) for the image writers. See docs/design_overview/sensor_modeling.rst.
Turning noise off removes only what is random: shot noise and read noise. The dark current’s electrons and the bias are not noise, and are applied either way.
A pixel whose received power is not finite (NaN or infinite) has no meaningful response: it reads out as NaN, which the image writers record as missing data, and a warning gives the number of such pixels.
Rows are read out in parallel. The noise is reproducible: see set_noise_seed().
- Parameters:
fb – The frame buffer containing received power and where the sensor response will be written.
exposure_time – The exposure time in seconds.
-
void set_resolution(Resolution resolution)¶
Sets the sensor resolution.
- Parameters:
resolution – The new sensor resolution (width x height).
- Throws:
std::runtime_error – if the resolution is not at least 1x1.
-
inline Resolution resolution() const¶
-
void set_pixel_pitch(units::Micrometer pitch_x, units::Micrometer pitch_y)¶
Sets the pixel pitch of the sensor.
- Parameters:
pitch_x – The horizontal pixel pitch in micrometers.
pitch_y – The vertical pixel pitch in micrometers.
- Throws:
std::runtime_error – if either pitch is not positive and finite.
-
Vec2<float> pixel_pitch() const¶
Returns the pixel pitch of the sensor.
- Returns:
The pixel pitch as a 2D vector (x, y) in meters.
-
void set_sensor_size(units::Millimeter width, units::Millimeter height)¶
Sets the sensor size in millimeters.
Computes and sets the pixel pitch based on the given sensor size and current resolution.
- Parameters:
width – The sensor width in millimeters.
height – The sensor height in millimeters.
- Throws:
std::runtime_error – if either dimension is invalid.
-
Vec2<float> sensor_size() const¶
Returns the sensor size in meters.
- Returns:
The sensor size as a 2D vector (width, height) in meters.
-
void set_quantum_efficiency(const TSpectral &qe)¶
Sets the quantum efficiency of the sensor.
- Parameters:
qe – The quantum efficiency spectrum (values between 0 and 1).
- Throws:
std::runtime_error – if the values are invalid.
-
void set_full_well_capacity(float fwc)¶
Sets the full well capacity of the sensor.
- Parameters:
fwc – The full well capacity in electrons.
- Throws:
std::runtime_error – if the value is invalid.
-
inline float full_well_capacity() const¶
-
inline void enable_noise(bool noise = true)¶
Turn shot noise and read noise on (the default) or off. Off, a pixel collects the expected number of electrons; the dark current’s electrons and the bias are still added, since they are not noise.
-
inline bool noise_enabled() const¶
Whether shot noise and read noise are on (the default). See enable_noise().
-
void set_read_noise(float read_noise)¶
Sets the read noise of the sensor.
- Parameters:
read_noise – The read noise in electrons RMS.
- Throws:
std::runtime_error – if the value is invalid.
-
inline float read_noise() const¶
-
void set_dark_current(float dark_current)¶
Sets the dark current of the sensor.
- Parameters:
dark_current – The dark current in electrons per second.
- Throws:
std::runtime_error – if the value is invalid.
-
inline float dark_current() const¶
-
void set_bias_level_dn(float bias_level_dn)¶
Sets the bias level of the sensor in ADU.
- Parameters:
bias_level_dn – The bias level in ADU.
- Throws:
std::runtime_error – if the value is negative or not finite, or at or above the largest value the bit depth holds, where every pixel would read out saturated.
-
inline float bias_level_dn() const¶
-
void set_bit_depth(int bit_depth)¶
Sets the bit depth of the sensor.
- Parameters:
bit_depth – The bit depth (number of bits per pixel).
- Throws:
std::runtime_error – if the value is not between 1 and MAX_BIT_DEPTH (24): the sensor response is stored as a float, from which every DN is recovered exactly only up to 24 bits; or if the bias level is at or above the largest value it holds.
-
inline int bit_depth() const¶
-
void set_conversion_gain(float gain)¶
Sets the conversion gain of the sensor in e-/ADU.
- Parameters:
gain – The gain in electrons per ADU.
- Throws:
std::runtime_error – if the value is invalid.
-
inline float conversion_gain() const¶
-
void set_unity_db(float unity_db)¶
Sets the unity dB reference level for gain.
- Parameters:
unity_db – The unity dB reference level.
- Throws:
std::runtime_error – if the value is invalid.
-
inline float unity_db() const¶
-
void set_gain_db(float gain_db)¶
Sets the gain in dB for the sensor.
- Parameters:
gain_db – The gain in decibels.
- Throws:
std::runtime_error – if the value is not finite, or gives a conversion gain that is not a positive finite value.
-
inline float gain_db() const¶
-
void set_roll(units::Radian angle)¶
Sets the sensor’s roll: its rotation about the optical axis, relative to the camera.
The sensor’s x axis is turned by the angle toward its y axis, so the scene turns the other way in the image. See CameraModel::set_sensor_roll().
- Parameters:
angle – The roll angle (any angle unit).
- Throws:
std::runtime_error – if the angle is not finite.
-
inline units::Radian roll() const¶
The sensor’s roll about the optical axis. See set_roll().
-
void set_noise_seed(std::uint64_t seed)¶
Seed the sensor’s noise.
Each readout draws its noise from random numbers determined by the seed, by how many readouts the sensor has made since the seed was set, and by the row. So a frame’s noise does not depend on other cameras, threads or render order, successive frames differ, and setting the same seed again repeats the same sequence of frames.
Sensors get distinct seeds by default, in the order they are made, so that two cameras never share their noise unless given the same seed. A sensor set with CameraModel::set_sensor() is a new sensor, with a new seed, and so is a copy of a sensor (it has the same settings).
- Parameters:
seed – Any value.
-
inline std::uint64_t noise_seed() const¶
The seed of the sensor’s noise. See set_noise_seed().
Public Static Functions
-
static void check_resolution(const Resolution &resolution, const std::string &caller)¶
Checks that a resolution has at least one pixel in each direction, and no more pixels than an image can hold (INT_MAX, since pixels are indexed in int).
- Parameters:
resolution – The resolution to check.
caller – Name for the error message.
- Throws:
std::runtime_error – if it does not.
-
static void check_pixel_pitch(units::Micrometer pitch_x, units::Micrometer pitch_y, const std::string &caller)¶
Checks that pixel pitches are positive and finite.
- Parameters:
pitch_x – The horizontal pixel pitch.
pitch_y – The vertical pixel pitch.
caller – Name for the error message.
- Throws:
std::runtime_error – if either is not.
-
static void check_sensor_size(units::Millimeter width, units::Millimeter height, const std::string &caller)¶
Checks that sensor dimensions are positive and finite.
- Parameters:
width – The sensor width.
height – The sensor height.
caller – Name for the error message.
- Throws:
std::runtime_error – if either is not.
Protected Functions
-
inline std::uint64_t next_readout_number_() const¶
The number of a new readout, for keying its random numbers.
Protected Attributes
-
std::uint64_t noise_seed_ = detail::next_default_noise_seed()¶
The noise seed, and how many readouts have been made since it was set. Together with the row they key each row’s random numbers (see detail::SensorRandom).
-
mutable std::atomic<std::uint64_t> readout_count_ = {0}¶
Protected Static Functions
-
static void check_bias_(float bias_level_dn, int bit_depth, const char *caller)¶
Throws unless the bias is below the largest value the bit depth holds, where every pixel would read out saturated.
Protected Static Attributes
-
static constexpr int MAX_BIT_DEPTH = 24¶
Largest bit depth accepted. The sensor response holds DN / (2^bit_depth - 1) as a float, from which every DN is recovered exactly, by round(value * (2^bit_depth - 1)), up to 24 bits (a float’s significand). This limits how the response is stored, not the physics: the ADC clamps every DN to 2^bit_depth - 1. Real ADCs are narrower (scientific sensors reach 16 to 18 bits).