Ornstein-Uhlenbeck walk (Uhlenbeck & Ornstein, Phys. More...
#include <rng.hpp>
Public Member Functions | |
| void | prepare (double update_rate_hz) |
| void | set_theta (double theta_per_second) |
| void | set_sigma (double sigma) |
| void | set_mu (double mu) |
| void | seed (std::uint32_t s) |
| void | set_seed (std::uint32_t s) |
| void | set_correlation_time (double seconds, double sample_rate) |
| void | reset () |
| void | reset_value () |
| Reset to the mean without disturbing the stream position. | |
| SampleType | next () |
| SampleType | current () const |
| SampleType | value () const |
| double | theta () const |
| double | sigma () const |
| double | stationary_std () const |
| Closed-form stationary standard deviation, for tests and for callers sizing a modulation depth from a target excursion. | |
Static Public Attributes | |
| static constexpr SampleType | kClamp = SampleType{1.5} |
| A Gaussian walk has unbounded tails; downstream consumers (pitch ratios, delay lengths) do not. | |
| static constexpr double | kMinTheta = 1e-6 |
| static constexpr double | kMaxTheta = 1.0 |
| static constexpr double | kDefaultTheta = 0.05 |
Ornstein-Uhlenbeck walk (Uhlenbeck & Ornstein, Phys.
Rev. 36, 1930):
y[n+1] = mu + e^(-theta*dt) * (y[n] - mu)
+ sigma * sqrt(1 - e^(-2*theta*dt)) * g
This is the exact discrete transition, not Euler-Maruyama: both the decay and innovation scale are solved for the configured update interval.
A random walk with a restoring force. Unlike filtered white noise it has a defined mean it returns to, and unlike an LFO it never repeats. The stationary standard deviation is the caller-facing sigma, independent of update rate and theta.
RT contract: prepare() recomputes dt and the noise scale; next(), reset(), and accessors allocate nothing.
USE: the one primitive behind tape wow, filter-cutoff drift, and feedback-network delay-length walks. Anywhere the answer to "why does this sound static?" is "because nothing is moving that the listener did not ask for". theta is how hard it is pulled home (small = long slow excursions), sigma is how far it gets. Output is clamped to +/-kClamp so a large sigma cannot hand a downstream pitch or delay control an absurd value.
|
inline |
|
inline |
|
inline |
| update_rate_hz | Rate at which next() will be called — the audio sample rate for per-sample use, or the control rate for a decimated one. The walk's statistics are rate-independent. |
|
inline |
|
inline |
Reset to the mean without disturbing the stream position.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
Closed-form stationary standard deviation, for tests and for callers sizing a modulation depth from a target excursion.
|
inline |
|
inline |
|
staticconstexpr |
A Gaussian walk has unbounded tails; downstream consumers (pitch ratios, delay lengths) do not.
1.5 sits far enough out that clipping is rare at sane settings but the bound still exists.
|
staticconstexpr |
|
staticconstexpr |
|
staticconstexpr |