AcresLidarModel.h#
Acres/Source/Acres/AcresLidarModel.h Generated
Radiometric and multi-return LiDAR model shared by the CPU-proxy and GPU ray-tracing paths.
Pure maths: no Unreal objects. A beam is sampled by a small bundle of sub-rays inside its divergence footprint; each sub-ray reports the surfaces it met in range order (foliage is partially transmissive, solids stop the ray). ProcessBeam turns those surface hits into contributions (weight x two-way transmission x backscatter), clusters them into echoes by range, detects each echo against a shot-noise threshold, adds range noise and applies the configured return mode to pick which echoes become points.
Geometry comes from AcresSensors.cpp (collision traces and proxies) or AcresLidarGpu.cpp (inline ray tracing). FinishScan in AcresSensors.cpp calls ProcessBeam once per beam on the game thread, in ring-major beam order, so the random draws are reproducible.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
MaterialNames |
extern const TCHAR* |
Lower-case material names, used as sensors.json "materials" keys and in episode.json. |
SubRayPattern#
Sub-ray angular offsets and energy weights for one beam.
One sub-ray: the beam centre with weight 1. Seven: the centre (weight 0.25) plus six rays on a hexagon at 0.35 x DivergenceMrad (weight 0.125 each).
| Argument | Description |
|---|---|
C |
Model settings (SubRays, DivergenceMrad). |
Offsets |
Receives the offsets, radians, in the beam's perpendicular plane. |
Weights |
Receives the weights (sum 1). |
Backscatter#
Lambertian-equivalent backscatter of a surface.
rho_bs = rho (1 - a w) cos(theta)^k + s exp(-(theta / width)^2), with rho the diffuse reflectance, a the wet darkening, w the wetness, theta the incidence angle, k the material's Minnaert exponent (1 = Lambertian) and s, width the specular peak and lobe width.
| Argument | Description |
|---|---|
C |
Model settings (material table). |
Material |
AcresLidar::EMaterial index (out of range falls back to MatOther). |
Cos |
Cosine of the incidence angle; the absolute value is used. |
Wetness |
Surface wetness 0-1. |
Returns: Apparent reflectance (dimensionless, can exceed 1 for specular surfaces).
SignalCounts#
Mean received signal for an apparent reflectance at a range.
S = S10 (rho / 0.1) (R10 / R)^2 (1 - exp(-(R / Rov)^2)), where the last factor models the near-field overlap of transmitter and receiver.
| Argument | Description |
|---|---|
C |
Model settings (SignalAt10PctCounts, RangeAt10PctM or RingRangeAt10PctM, OverlapRangeM). |
Rho |
Apparent reflectance. |
RangeM |
Range, m (floored at 1 mm). |
Ring |
Ring index for a per-ring R10 (out of range or -1: RangeAt10PctM). |
Returns: Mean signal, counts.
IntensityByte#
Calibrated 8-bit reflectivity, as Ouster sensors report it.
0-100 is linear in diffuse percent (round(100 rho)); 101-255 is logarithmic for specular or retro-reflective returns: 100 + 155 min(1, ln(rho) / ln(64)).
| Argument | Description |
|---|---|
Rho |
Reflectivity estimate (1 = 100 % Lambertian). |
Returns: Intensity byte 0-255 (0 for rho <= 0 or NaN).
RainExtinction#
Rain extinction coefficient at the laser wavelength.
alpha = RainDbPerKm x R^RainExponent dB/km, converted to 1/m (divide by 10 log10(e) = 4.343 and by 1000).
| Argument | Description |
|---|---|
C |
Model settings (RainDbPerKm, RainExponent). |
RainMmH |
Rain rate, mm/h (<= 0 gives 0). |
Returns: Extinction coefficient, 1/m.
FogExtinction#
Fog and haze extinction coefficient at the laser wavelength, from the meteorological visibility.
Koschmieder: sigma_550 = 3.912 / V. The environment's visibility already contains rain (AcresEnvironmentModel: V_rain = 11.1 km x R^-0.63), so that part is removed first to avoid counting rain twice. The remaining fog/haze extinction is scaled to the laser wavelength with Kim, McArthur & Korevaar (2001): alpha = sigma_550 (lambda / 550 nm)^-q, q = 1.6 (V > 50 km), 1.3 (6-50 km), 0.16 V + 0.34 (1-6 km), V - 0.5 (0.5-1 km), 0 (< 0.5 km: fog droplets are large, extinction is wavelength-neutral), V in km.
| Argument | Description |
|---|---|
C |
Model settings (WavelengthNm). |
VisibilityM |
Meteorological visibility including rain, m. |
RainMmH |
Rain rate that visibility includes, mm/h. |
Returns: Extinction coefficient, 1/m (0 for infinite visibility).
Atmosphere#
Builds the per-scan atmosphere from the weather.
| Argument | Description |
|---|---|
C |
Model settings. With C.Weather false the result is clear air (Active() false). |
RainMmH |
Rain rate, mm/h. |
VisibilityM |
Meteorological visibility including rain, m. |
ClutterClass |
Class id written for clutter points. |
Returns: The extinction and backscatter coefficients and the drop density.
ColumnTimeOffset#
Firing time of a column within the sweep, relative to the scan stamp (the end of the sweep).
The sensor spins at 1 / PeriodS turns per second starting at ScanStartAzimuthDeg; a column at azimuth Az has turned phi = (Az - start) (ccw) or (start - Az) (cw), wrapped to [0, 2 pi), and fires at phi / (2 pi) x PeriodS - PeriodS. All rings of a column fire together.
| Argument | Description |
|---|---|
C |
Model settings (SpinDirection, ScanStartAzimuthDeg). MotionDistortion false returns 0 (instantaneous). |
AzimuthRad |
Column azimuth, radians counter-clockwise from forward (FLU). |
PeriodS |
Sweep period, s (1 / lidar.hz). |
Returns: Time offset, s, in [-PeriodS, 0).
ProcessBeam#
Echo formation, detection and return selection for one beam.
With an active atmosphere every contribution is scaled by the two-way transmission exp(-2 alpha R) (the calibrated reflectivity is not corrected for it, as on a real sensor), so weak or distant echoes drop below the threshold and their range noise grows with the lower SNR. Before echo formation, clutter contributions are added for slabs of length min_return_separation_m from min_range_m out to ClutterMaxRangeM (or the beam's nearest solid hit): fog is a continuous medium with equivalent reflectance pi beta_fog dR; rain is granular, with N ~ Poisson(n A(r) dR) drops in the slab (A = beam area from the exit diameter and divergence) whose brightness X = E^2 / 2 (E ~ Exp(1): a Marshall-Palmer diameter, backscatter ~ D^2, mean 1), giving pi beta_rain dR x sum(X) / (n A dR). Slabs whose mean signal is 5 sigma below the threshold are skipped. Clutter echoes carry Atm->ClutterClass and material "other".
| Argument | Description |
|---|---|
C |
Model settings. |
Weights |
Sub-ray weights from SubRayPattern. |
Hits |
All sub-ray hits of the beam, any order. |
StdFloorM |
Range-noise floor (lidar.std_m), m. |
MaxRangeM |
Configured maximum range, m; echoes beyond it are not detected. |
Rng |
The LiDAR noise stream. Exactly two Gaussian draws per echo, echoes visited in range order. |
Out |
Detected, selected returns are appended here in range order. |
Atm |
Atmosphere for this scan; null or inactive = clear air (identical to the model without weather). |
ClutterRng |
Separate stream for the raindrop draws, so the noise stream is untouched by the rain sampling. Null disables clutter. |
Ring |
The beam's ring, for a per-ring R10 (-1: RangeAt10PctM). With PulseLengthM > 0 each contribution's peak is scaled by its pulse-stretch factor (from BetaRad, its range and incidence); an echo's peak factor is the power-weighted mean of its contributions'. Detection and range noise use the peak signal; the reported reflectivity is rho_app x S' / S_peak (an energy measure: no loss from stretching). |
Returns: The number of echoes formed (before detection).
int ProcessBeam(const FAcresLidarModelConfig& C, const TArray<double>& Weights, TArrayView<const FAcresLidarSubHit> Hits, double StdFloorM, double MaxRangeM, FAcresPcg32& Rng, TArray<FAcresLidarReturn>& Out, const FAcresLidarAtmosphere* Atm = nullptr, FAcresPcg32* ClutterRng = nullptr, int Ring = -1);
EMaterial#
Surface material at the laser wavelength. The value is the index into FAcresLidarModelConfig::Materials and the "material" byte of each PLY point.
| Value | Description |
|---|---|
MatOther |
|
MatSoil |
|
MatGrass |
|
MatGravel |
|
MatAsphalt |
|
MatConcrete |
|
MatWater |
|
MatCornLeaf |
|
MatSoybeanLeaf |
|
MatTreeFoliage |
|
MatBark |
|
MatShrub |
|
MatBuilding |
|
MatMetalBin |
|
MatVehicle |
|
MatMud |
|
MatPotatoLeaf |
|
MaterialCount |
EReturnFlag#
Bits of the PLY "return_flags" byte: which role(s) a point plays among the beam's detected echoes.
| Value | Description |
|---|---|
ReturnFirst |
|
ReturnStrongest |
|
ReturnLast |
|
ReturnSecondStrongest |
FAcresLidarMaterial#
Optical properties of one material at the laser wavelength (905 nm by default).
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
Reflectivity |
double |
.3 |
Diffuse (Lambertian) reflectance at the laser wavelength, 0-1. | |
Specular |
double |
0 |
Peak specular backscatter at normal incidence, as a Lambertian-equivalent reflectance (0-100; can exceed 1). | |
SpecularWidthDeg |
double |
° | 8 |
Width of the Gaussian specular lobe in incidence angle, degrees. |
Transmission |
double |
0 |
Per-layer gap fraction when the surface is a pass-through (foliage) hit, 0-1. Solid hits ignore it. | |
WetDarkening |
double |
0 |
Wet darkening: reflectance is multiplied by (1 - WetDarkening x wetness), wetness 0-1. | |
IncidenceExponent |
double |
1 |
Minnaert exponent k of the diffuse term rho cos^k(theta) (AcresLidarPhysics::MinnaertBackscatter): 1 is Lambertian, 0 an apparent reflectance that does not change with incidence (the Polaris' Helios on asphalt, concrete, gravel and grass). | |
MicroSlopeDeg |
double |
° | 0 |
Standard deviation of the footprint-scale surface slope in the plane of incidence, deg (ground hits only). Each 0.25 m cell of ground has a fixed tilt (AcresLidarPhysics::PlaceNormal), which spreads the grazing-incidence loss of ground returns over range as real surface relief does. 0 = the mesh's own normal. |
ReflectivitySd |
double |
0 |
Footprint-scale albedo texture of ground: the reflectance of each 0.1 m cell is multiplied by exp(sd z - sd^2 / 2), z a fixed N(0, 1) per cell (lognormal, mean 1). Within a run the Helios reports asphalt within +/-7 %, grass +/-24 %, bare soil +/-29 % (sd of ln intensity at 4-8 m). 0 = uniform. | |
RoughnessM |
double |
m | 0 |
Rms height of the ground's small-scale relief (stones, clods, grass blades) seen at normal incidence, m: a ground return's range moves by RoughnessM |cos theta|^-1.5 z (AcresLidarPhysics::RoughRangeSigmaM), z ~ N(0, 1) per beam and scan, so rough ground looks noisier at grazing incidence (gravel 0.7 mm, soil 1.7 mm, grass 2.6 mm for the Helios data). 0 = smooth. |
FAcresLidarModelConfig#
LiDAR beam, radiometry and return-selection settings (sensors.json "lidar" block, minus the scan geometry, which lives in FAcresSensorConfig).
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
WavelengthNm |
double |
N·m | 905 |
Laser wavelength, nm. The material table encodes the wavelength for surfaces; the fog/haze extinction uses it for the Kim et al. (2001) wavelength scaling. |
DivergenceMrad |
double |
3 |
Full-angle 1/e^2 beam divergence, milliradians (0-20): the horizontal one when DivergenceVMrad is set. | |
DivergenceVMrad |
double |
0 |
Vertical full-angle divergence, mrad (0 = DivergenceMrad, a round beam). The Helios' is 6.9 against 1.6 mrad horizontal. Only the pulse-stretching term uses the ellipse; the sub-ray pattern stays round (DivergenceMrad). | |
PulseLengthM |
double |
m | 0 |
Pulse length in range, m (emitted pulse FWHM x c / 2). > 0 turns on echo stretching: a hit's peak signal is multiplied by L / sqrt(L^2 + dR^2), dR = R tan(theta) beta the footprint's range extent (AcresLidarPhysics), which loses grazing ground at range while the reported reflectivity (an energy measure) stays. 0 = off. |
SubRays |
int |
7 |
Sub-rays per beam: 1 (ideal pencil beam) or 7 (centre + hexagonal ring at 0.35 x divergence). | |
MaxHitsPerSubRay |
int |
4 |
Surfaces recorded along one sub-ray (1-8); foliage lets the ray continue, solids stop it. | |
ContinueStepM |
double |
m | .25 |
Skip distance after a foliage hit before the next surface is searched, m. |
MinSeparationM |
double |
m | .75 |
Echo separation, m (roughly the pulse length): contributions closer than this merge into one echo. |
ReturnMode |
FString |
TEXT("dual_strongest_last") |
"strongest", "first", "last", "dual_strongest_last", "dual_first_last" or "triple_first_strongest_last". | |
MinRangeM |
double |
m | .5 |
Echoes nearer than this are not detected, m. |
RangeAt10PctM |
double |
m | 60 |
Range at which a 10 % Lambertian target at normal incidence is detected with probability DetectionAtSpec, m. |
RingRangeAt10PctM |
TArray<double> |
m | Per-ring RangeAt10PctM (radiometry.ring_range_at_10pct_m), in ring order; empty = RangeAt10PctM for all. The Helios' lower channels are specified at 40, 20 and 10 m against 90 m for the upper ones. | |
SignalAt10PctCounts |
double |
100 |
Mean signal of that reference target at RangeAt10PctM, counts. | |
AmbientCounts |
double |
20 |
Background counts added to the shot-noise variance. | |
DetectionAtSpec |
double |
.9 |
Detection probability at the spec point (0.5-0.9999). | |
OverlapRangeM |
double |
m | 1.0 |
Near-field transmitter/receiver overlap scale, m. |
SaturationCounts |
double |
65535 |
Clip for the reported signal, counts. | |
RangeStdLowSnrM |
double |
m | .03 |
Extra range noise at the spec SNR, m; scales with 1/SNR. The floor is lidar.std_m. |
PondThresholdM |
double |
m | .003 |
Standing water deeper than this turns a ground hit into a specular water surface, m. |
Noise |
bool |
true |
False (-SensorNoNoise) removes signal and range noise; the Gaussian draws still happen so streams stay aligned. | |
MotionDistortion |
bool |
true |
Rolling scan ("motion_distortion"): each column is fired at its own time within the sweep and traced from the sensor pose interpolated at that time, so the cloud shows the skew of a spinning sensor on a moving vehicle. False (or -SensorLidarIdeal / -SensorLidarNoMotion) traces every beam from the pose at the scan stamp. | |
SpinDirection |
FString |
TEXT("cw") |
Spin sense seen from above: "cw" (clockwise, Velodyne-style) or "ccw". | |
ScanStartAzimuthDeg |
double |
° | 180 |
Azimuth where a sweep starts (and the previous one ends), degrees counter-clockwise from forward (FLU). 180 puts the seam behind the sensor. |
Weather |
bool |
true |
Rain and fog along the beam ("weather.enabled"): two-way extinction, detection loss and backscatter clutter. False (or -SensorLidarIdeal / -SensorLidarNoWeather) gives clear-air scans whatever the weather. | |
RainDbPerKm, RainExponent |
double |
Rain extinction at the laser wavelength, alpha [dB/km] = RainDbPerKm x R^RainExponent with R in mm/h (Carbonneau 1998 / ITU-R free-space-optics rain law; raindrops are large, so near-IR ~ visible). | ||
FogLidarRatioSr, HazeLidarRatioSr, RainLidarRatioSr |
double |
Extinction-to-backscatter (lidar) ratios, sr: fog droplets (~18.8 sr for liquid water droplets, O'Connor et al. 2004), haze aerosol (~50-70 sr for continental aerosol, Mueller et al. 2007) and rain (large drops backscatter weakly; engineering estimate, see sensors.json provenance). The fog/haze ratio is blended by the fog/haze visibility: droplets below 0.5 km, aerosol above 1 km, 1/ratio linear in between (the regimes of Kim et al.). | ||
RainDropsPerM3, RainDropsExponent |
double |
Raindrop number density N = RainDropsPerM3 x R^RainDropsExponent, m^-3 (Marshall & Palmer 1948: N0 / Lambda = 8000 / (4.1 R^-0.21)). | ||
ExitDiameterM |
double |
m | .01 |
Beam diameter at the exit window, m (the footprint then grows with the divergence). |
ClutterMaxRangeM |
double |
m | 10 |
Backscatter clutter (false returns from droplets) is only simulated up to this range, m. |
RainOverrideMmH, VisibilityOverrideM |
double |
Command-line weather overrides (-SensorLidarRain=<mm/h>, -SensorLidarVisibility=<m>); negative = use the environment. | ||
Materials |
FAcresLidarMaterial |
Optical table indexed by AcresLidar::EMaterial. | ||
DetectionThresholdCounts |
double |
0 |
Cached DetectionThreshold(), counts; read by ProcessBeam for every beam. |
FAcresLidarModelConfig::FAcresLidarModelConfig#
Fills the material table with approximate 905 nm defaults (sensors.json normally overrides them).
FAcresLidarModelConfig::Parse#
Reads the model keys of the sensors.json "lidar" block, including "radiometry" and "materials".
| Argument | Description |
|---|---|
Lidar |
The "lidar" JSON object. Missing keys keep their defaults. |
FAcresLidarModelConfig::ApplyCommandLine#
Applies -SensorLidarReturnMode=, -SensorLidarSubRays=, -SensorLidarDivergence=, -SensorNoNoise, -SensorLidarIdeal (instantaneous clear-air scan: no motion distortion, no weather), -SensorLidarNoMotion, -SensorLidarNoWeather, -SensorLidarRain= (mm/h) and -SensorLidarVisibility= (m).
| Argument | Description |
|---|---|
CommandLine |
The command line to read (null: the process's; "" gives the file settings with the derived values updated, as the sensor profile's reference needs). |
FAcresLidarModelConfig::Validate#
Checks every parameter against its supported range; stops the game with a checkf message if not.
FAcresLidarModelConfig::DetectionThreshold#
Computes the detection threshold T in counts from the current settings.
Chosen so that the reference target (S10 = SignalAt10PctCounts at RangeAt10PctM) is detected with probability DetectionAtSpec: T = S10 - z sqrt(S10 + AmbientCounts), z = inverse normal CDF of DetectionAtSpec (found by bisection). Use the cached DetectionThresholdCounts in hot code.
Returns: The threshold, counts (must be positive).
FAcresLidarModelConfig::UpdateDerived#
Recomputes the cached derived values (DetectionThresholdCounts). Called by the constructor, Parse and ApplyCommandLine; call it again after changing fields by hand (Validate checks the cache is current).
FAcresLidarModelConfig::ToJson#
Serialises the settings (and the derived detection threshold) as compact JSON.
FAcresLidarModelConfig::Manifest#
ToJson plus plain-text descriptions of the beam, echo, signal, return-selection, intensity, wetness and material-provenance models, for episode.json "lidar.model".
FAcresLidarAtmosphere#
Rain and fog along the beams of one scan, at the laser wavelength. Built by AcresLidar::Atmosphere.
Two-way Beer-Lambert extinction exp(-2 alpha R) scales every contribution; the volume backscatter coefficients (beta = alpha / lidar ratio) and the raindrop density drive the near-range clutter returns in ProcessBeam.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
RainMmH, VisibilityM |
double |
Inputs: rain rate, mm/h, and meteorological (550 nm, 2 % contrast) visibility including rain, m. | ||
AlphaRainPerM, AlphaFogPerM |
double |
Extinction coefficients at the laser wavelength, 1/m: rain, and fog + haze (visibility minus its rain part). | ||
BetaRainPerMSr, BetaFogPerMSr |
double |
Volume backscatter coefficients, 1/(m sr). | ||
DropsPerM3 |
double |
0 |
Raindrop number density, m^-3. | |
ClutterClass |
uint8 |
0 |
Semantic class written for clutter points (the recorder's "precipitation" class). |
FAcresLidarAtmosphere::Alpha#
Total extinction coefficient, 1/m.
FAcresLidarAtmosphere::Active#
True when there is anything to simulate (weather on and some rain or fog/haze).
FAcresLidarSubHit#
One surface met by one sub-ray.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
RangeM |
float |
m | 0 |
Distance from the sensor, m. |
Cos |
float |
1 |
|cos| of the incidence angle (0.5 when the normal is unknown). | |
Wetness |
float |
0 |
Surface wetness 0-1. | |
BetaRad |
float |
rad | 0 |
Full-angle beam divergence in the plane of incidence, rad, for the pulse-stretching term (0 = none; foliage leaves none). |
Albedo |
float |
1 |
Reflectance multiplier of this spot (ground texture; 1 = the material's own). | |
SubRay |
uint8 |
0 |
Index into the sub-ray pattern. | |
Class |
uint8 |
0 |
Semantic class id. | |
Material |
uint8 |
0 |
AcresLidar::EMaterial. | |
bFoliage |
bool |
false |
True for partially transmissive surfaces (tree crowns, shrubs, crops, ground cover). |
FAcresLidarReturn#
One point produced from one echo; mirrors a PLY vertex.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
RangeM |
float |
m | 0 |
Measured range with noise, m. |
Reflectivity |
float |
0 |
Range-compensated reflectivity estimate (1 = 100 % Lambertian). | |
Signal |
uint16 |
0 |
Raw signal including 1/R^2 and near-field overlap, counts (clipped at SaturationCounts). | |
Intensity |
uint8 |
0 |
Calibrated reflectivity byte 0-255. Class, | |
Class |
uint8 |
0 |
See above. | |
Material |
uint8 |
0 |
From the echo's largest contributor. | |
Index |
uint8 |
1 |
1-based return index in range order. | |
Count |
uint8 |
1 |
Points emitted for this beam. | |
Flags |
uint8 |
0 |
EReturnFlag bits. |