Skip to main content

Simulator

Struct Simulator 

Source
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

Source

pub fn new(width: usize, height: usize, config: SimulatorConfig) -> Self

Source

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):

configurationhow the backends compare
no shot noise, no leak, no mismatchidentical, event for event
mismatch on, still noiselesssame 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 onsame 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.

Source

pub fn sensor_size(&self) -> (usize, usize)

Source

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§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V