Skip to content

Sensor noise that scales with the sample rate (noise density) - #233

Open
patrickmckeen wants to merge 1 commit into
2_1/updatefrom
feat/sensor-noise-density
Open

patrickmckeen wants to merge 1 commit into
2_1/updatefrom
feat/sensor-noise-density

Conversation

@patrickmckeen

Copy link
Copy Markdown
Collaborator

The problem

A sensor's Noise has one number, std_noise: the standard deviation of a single reading. That number does not know how often the sensor is read. Real sensor noise is specified as a density, in reading units per root hertz (for a gyro the angle random walk, for a magnetometer the noise density on the data sheet), because the noise on a reading depends on how long it averages: ten readings a second are each noisier than one reading a second, by a factor of about three. With a fixed std_noise, changing the simulation step silently changes the effective noise level, and a data-sheet number cannot be entered as it is given.

The fix

Noise takes an optional density. A reading averaged over the sensor's sample_time then has standard deviation sqrt(std_noise² + density² / sample_time): the density part scales with the rate, std_noise stays the part that does not (quantisation, electronics). Noise.std(sample_time) returns that value, and cov, covariance and srcov take the same argument.

Every sensor passes its own sample_time both when it draws a reading and when the estimator asks for the measurement covariance, so what is drawn and what the filter assumes are the same number. The warm start uses it too. A model without a density behaves exactly as before, at every rate. A sensor given a density with a non-positive sample_time fails at construction with the sensor's name, rather than at its first reading.

One thing to know: the density is interpreted per sample_time, which is the sensor's configured rate. If the simulation reads the sensor more often than that (today simulate() reads every sensor every step), the readings are correlated in reality but independent here; that is the existing sample-time behaviour, not something this change alters.

Actuator noise and the anisotropic star-tracker noise are per reading and do not take a density; they accept and ignore the sample time.

Tests

testing/test_sensors/test_noise_density.py, 6 tests: the formula and its covariance forms; the spread of 4000 drawn gyro readings at two sample rates matches density / sqrt(sample_time); the estimator's measurement covariance, through the satellite's measurement stack, equals the drawn variance; a density without a rate, a negative density and a mismatched shape are refused with clear messages; the density survives sizing to a vector sensor and copies; the warm start's angular sigma uses the scaled value. The full suite passes.

🤖 Generated with Claude Code

… sample rate

Noise gains an optional density, in reading units per root hertz (the
angle random walk of a gyro, the noise density of a magnetometer data
sheet). A reading averaged over the sensor's sample_time then has standard
deviation sqrt(std_noise^2 + density^2 / sample_time), so the noise no
longer silently changes when the simulation step changes. The sensor
passes its sample time both when it draws and when the estimator asks for
the measurement covariance, so both sides agree; the warm start uses the
same standard deviation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Test Results

1 564 tests  +6   1 562 ✅ +6   3m 10s ⏱️ -36s
    1 suites ±0       2 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit 4398c06. ± Comparison against base commit 775652b.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant