pub struct Simulator { /* private fields */ }Expand description
A DVS pixel array, driven one frame at a time.
Frames are pushed in time order and each call returns the events generated since the previous one, already sorted. Nothing accumulates across calls, so a recording of any length simulates in memory proportional to one frame interval rather than to the whole output.
§Parallelism
A frame pair is split into fixed-size blocks of pixels and simulated with rayon. Pixels are
independent — nothing in the model couples one to its neighbours — so the only shared thing was
the random number generator, and each block draws from its own stream instead (see
[block_seed]). Both the block size and the seed derivation are fixed constants, so the output
is a function of the configuration alone: the same seed gives the same events on one core or
thirty-two.
Implementations§
Source§impl Simulator
impl Simulator
pub fn new(width: usize, height: usize, config: SimulatorConfig) -> Self
Sourcepub fn on_device(self, device: Device) -> Self
pub fn on_device(self, device: Device) -> Self
Runs the pixel model on device.
§What is and is not the same as the CPU
The deterministic half is the same by construction. Threshold mismatch is drawn here, once
at new, and uploaded — the GPU never regenerates it — so two sensors built
from one seed are the same silicon whichever backend runs them. The sub-interval boundaries
are computed on the host in f64 and uploaded for the same reason. What is left is exp,
floor and the arithmetic between them, where WGSL and Rust agree to a few ULP.
The random half is not the same sample path. The CPU draws from a generator seeded per
block of pixels and consumed in order; a kernel with one invocation per pixel cannot replay a
sequential stream without serialising itself. The GPU uses a counter-based generator keyed on
(seed, frame, sub-step, pixel, polarity), which is reproducible from run to run and across
devices — every operation in it is integer — but draws different numbers from the CPU’s.
So, measured rather than hoped for (see this module’s gpu_tests):
| configuration | how the backends compare |
|---|---|
| no shot noise, no leak, no mismatch | identical, event for event |
| mismatch on, still noiseless | same events, same polarity; a couple of timestamps in ~25 000 land a microsecond apart, because the crossing fraction is f64 on the CPU and WGSL has no f64 |
| noise on | same event rate to within a few per cent, different events — and bit-reproducible from run to run for a given seed |
A run that needs to be compared against a stored CPU result should therefore either turn the random terms off or compare distributions. A run that just needs events does not care.
pub fn sensor_size(&self) -> (usize, usize)
Sourcepub fn push_frame(&mut self, frame: &[f32], t_us: i64) -> EventStream
pub fn push_frame(&mut self, frame: &[f32], t_us: i64) -> EventStream
Feeds one frame, returning every event generated since the previous frame.
t_us must not go backwards. The first frame only seeds the pixel state and returns an empty
stream — there is no interval to integrate over yet.
Auto Trait Implementations§
impl Freeze for Simulator
impl RefUnwindSafe for Simulator
impl Send for Simulator
impl Sync for Simulator
impl Unpin for Simulator
impl UnsafeUnpin for Simulator
impl UnwindSafe for Simulator
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more