Skip to content
Oakfield Operator Calculus Function Reference Site

Stimulus: Wave Drivers

These operators share the coordinate mapping and timing controls documented on Stimulus Operators. Most entries use add_stimulus_operator(ctx, field, opts) with the operator-specific type shown below.

add_stimulus_operator(ctx, field, opts)

Generate a travelling sinusoidal wave. Fundamental building block for wave propagation, oscillating forcing, and harmonic analysis.

add_stimulus_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

Note: Requires type = "stimulus_sine".

u(x,t)=Asin(kxωt+ϕ)u(x, t) = A \cdot \sin(k \cdot x - \omega \cdot t + \phi)

where:

  • AA is the amplitude
  • kk is the wavenumber
  • ω\omega is the angular frequency
  • ϕ\phi is the phase offset

Phase velocity: vp=ω/kv_p = \omega / k

ParameterTypeDefaultRangeDescription
typestring Must be "stimulus_sine"
amplitudedouble unboundedPeak amplitude (required)
wavenumberdouble unboundedSpatial wavenumber k (required)
omegadouble unboundedAngular frequency (required)
phasedouble 0.0unboundedPhase offset (radians)
time_offsetdouble 0.0unboundedTemporal shift
rotationdouble 0.0unboundedComplex phase rotation
nominal_dtdouble 0.0≥0Fixed timestep
fixed_clockboolean falseUse nominal_dt
scale_by_dtboolean trueScale by dt

Plus all shared coordinate mapping parameters.

-- Basic travelling wave
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_sine",
amplitude = 0.3,
wavenumber = 1.0,
omega = 0.6
})
-- Standing-like behavior (omega = 0)
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_sine",
amplitude = 0.5,
wavenumber = 2.0,
omega = 0.0,
phase = math.pi / 4
})
-- 2D wavevector specification
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_sine",
amplitude = 0.4,
use_wavevector = true,
kx = 0.5,
ky = 0.5,
omega = 1.0
})

add_stimulus_operator(ctx, field, opts)

Generate a standing-wave sinusoid with fixed nodes and antinodes. Models resonant cavity modes and stationary vibration patterns.

add_stimulus_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

Note: Requires type = "stimulus_standing".

u(x,t)=Asin(kx+ϕ)cos(ωt)u(x, t) = A \cdot \sin(k \cdot x + \phi) \cdot \cos(\omega \cdot t)

Equivalently, this is the superposition of two counter-propagating waves:

u=A2[sin(kxωt)+sin(kx+ωt)]u = \frac{A}{2}[\sin(kx - \omega t) + \sin(kx + \omega t)]
  • Nodes: Points where sin(kx+ϕ)=0\sin(kx + \phi) = 0 (always zero)
  • Antinodes: Points where sin(kx+ϕ)=1|\sin(kx + \phi)| = 1 (maximum oscillation)

Same as stimulus_sine:

ParameterTypeDefaultDescription
typestring Must be "stimulus_standing"
amplitudedouble Peak amplitude (required)
wavenumberdouble Spatial wavenumber (required)
omegadouble Angular frequency (required)
phasedouble 0.0Controls node/antinode placement

Plus timing and coordinate parameters.

-- Basic standing wave
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_standing",
amplitude = 0.4,
wavenumber = 0.8,
omega = 0.8,
phase = 0.25
})
-- Half-wavelength shifted nodes
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_standing",
amplitude = 0.5,
wavenumber = 1.0,
omega = 1.0,
phase = math.pi / 2
})

add_stimulus_operator(ctx, field, opts)

Generate a sinusoid with time-varying frequency and/or wavenumber. Models frequency sweeps, dispersive waves, and time-frequency analysis signals.

add_stimulus_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

Note: Requires type = "stimulus_chirp".

u(x,t)=Asin((k0+k˙t)x(ω0+ω˙t)t+ϕ)u(x, t) = A \cdot \sin\left((k_0 + \dot{k}t) \cdot x - (\omega_0 + \dot{\omega}t) \cdot t + \phi\right)

where:

  • k0k_0 is the initial wavenumber
  • k˙\dot{k} is kdot (wavenumber rate)
  • ω0\omega_0 is the initial angular frequency
  • ω˙\dot{\omega} is wdot (frequency rate)

Instantaneous frequency: f(t)=ω0+ω˙t2πf(t) = \frac{\omega_0 + \dot{\omega}t}{2\pi}

ParameterTypeDefaultRangeDescription
typestring Must be "stimulus_chirp"
amplitudedouble unboundedPeak amplitude (required)
wavenumberdouble unboundedInitial wavenumber (required)
omegadouble unboundedInitial angular frequency (required)
kdotdouble 0.0unboundedWavenumber rate (rad/unit/s)
wdotdouble 0.0unboundedFrequency rate (rad/s²)
phasedouble 0.0unboundedPhase offset
rotationdouble 0.0unboundedComplex phase rotation
time_offsetdouble 0.0unboundedTemporal shift

Plus timing and coordinate parameters.

-- Linear frequency chirp
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_chirp",
amplitude = 0.5,
wavenumber = 1.0,
omega = 0.3,
kdot = 0.1,
wdot = 0.2
})
-- Spatial chirp only
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_chirp",
amplitude = 0.4,
wavenumber = 0.5,
omega = 1.0,
kdot = 0.5,
wdot = 0.0
})

add_stimulus_operator(ctx, field, opts)

Adds one or more spatial–temporal plane waves with discrete harmonic spectra to the field.

add_stimulus_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

Note: Requires type = "stimulus_spectral_lines".

u(x,t)=An=1Nnpsin(nkxnωt+ϕ)u(x, t) = A \sum_{n=1}^{N} n^{-p} \cdot \sin(n \cdot k \cdot x - n \cdot \omega \cdot t + \phi)

where:

  • NN is harmonic_count
  • pp is harmonic_power
  • Higher pp reduces high-frequency content

Special cases:

  • p=0p = 0: Equal amplitude harmonics
  • p=1p = 1: 1/n1/n amplitude decay (approaching square wave)
  • p=2p = 2: 1/n21/n² amplitude decay (faster rolloff)
ParameterTypeDefaultRangeDescription
typestring Must be "stimulus_spectral_lines"
amplitudedouble unboundedPeak amplitude (required)
wavenumberdouble unboundedFundamental wavenumber
omegadouble unboundedFundamental frequency
phasedouble 0.0unboundedPhase offset
harmonic_countinteger 1≥1Number of harmonics
harmonic_powerdouble 0.0≥0Power weighting exponent

Plus timing and coordinate parameters.

-- Single fundamental
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_spectral_lines",
amplitude = 1.0,
wavenumber = 0.5,
harmonic_count = 1
})
-- Rich harmonic content
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_spectral_lines",
amplitude = 0.2,
harmonic_count = 4,
harmonic_power = 0.9,
fixed_clock = true
})
-- Square-wave approximation (odd harmonics with 1/n decay)
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_spectral_lines",
amplitude = 0.5,
wavenumber = 1.0,
omega = 1.0,
harmonic_count = 8,
harmonic_power = 1.0
})

add_stimulus_operator(ctx, field, opts)

Generate bandlimited waveforms using BLIT, PolyBLEP, or miniBLEP synthesis. Produces alias-free sawtooth, square, and triangle waves.

add_stimulus_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

Note: Requires type = "stimulus_fourier".

Sawtooth (ideal):

u(t)=A(tτmod10.5)u(t) = A \cdot \left(\frac{t}{\tau} \mod 1 - 0.5\right)

Square (ideal):

u(t)=Asign(sin(2πtτ))u(t) = A \cdot \text{sign}\left(\sin\left(\frac{2\pi t}{\tau}\right)\right)

Triangle (ideal):

u(t)=A(4tτmod10.51)u(t) = A \cdot \left(4 \left|\frac{t}{\tau} \mod 1 - 0.5\right| - 1\right)

The method parameter selects the anti-aliasing technique:

  • blit: Band-Limited Impulse Train
  • polyblep: Polynomial BLEP correction
  • miniblep: Minimum-phase BLEP
ParameterTypeDefaultRangeDescription
typestring Must be "stimulus_fourier"
amplitudedouble unboundedWaveform amplitude (required)
frequencydouble >0Fundamental frequency in Hz (required)
shapeenum "saw"see belowWaveform shape
methodenum "polyblep"see belowAnti-aliasing method
dutydouble 0.5[0, 1]Duty cycle for square/triangle
phasedouble 0.0[0, 1)Initial phase in cycles
rotationdouble 0.0unboundedComplex phase rotation

Shape options: saw, square, triangle

Method options: blit, polyblep, miniblep

Plus timing parameters.

-- Bandlimited sawtooth at 440 Hz
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_fourier",
amplitude = 0.8,
frequency = 440.0,
shape = "saw",
method = "polyblep"
})
-- Square wave with 25% duty cycle
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_fourier",
amplitude = 0.5,
frequency = 220.0,
shape = "square",
duty = 0.25
})
-- Triangle wave
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_fourier",
amplitude = 0.6,
frequency = 110.0,
shape = "triangle"
})

add_digamma_square_operator(ctx, field, opts)

Generate a deformable digamma waveform driver. Uses the digamma function to produce bandlimited square-like waves with controllable harmonics, optional field-driven warp modulation, and a tunable deformation shift.

add_digamma_square_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

Note: Former add_digamma_square_warp_operator(...) behavior now lives on this operator through warp_field, warp_mix, warp_bias, and warp_mode.

Let

D(φ;Hmix,a)=1+(cos ⁣(2πHmixcosφ)cos(2πa))[ψ(0) ⁣(a+Hmixcosφ)ψ(0) ⁣(1a+Hmixcosφ)]/πD(\varphi; H_{\text{mix}}, a) = 1 + \left(\cos\!\left(2\pi H_{\text{mix}}\cos\varphi\right) - \cos(2\pi a)\right) \left[ \psi^{(0)}\!\left(a + H_{\text{mix}}\cos\varphi\right) - \psi^{(0)}\!\left(1 - a + H_{\text{mix}}\cos\varphi\right) \right] \bigg/ \pi

where ψ(0)\psi^{(0)} is the digamma function.

The phase is evaluated on the shared stimulus coordinate mapping:

φ(x,t)=kξ(x,t)+ω(t+t0)+ϕ\varphi(x, t) = k \cdot \xi(x, t) + \omega \cdot (t + t_0) + \phi

with base harmonic control H=H = harmonics.

Without a warp field:

Hmix=HH_{\text{mix}} = H

With warp sample w(x)w(x) from warp_field, the mix becomes:

Hmix={H+m(w+b),sumHm(w+b),multiply(1m)H+m(w+b),crossfadeH_{\text{mix}} = \begin{cases} H + m\,(w + b), & \text{sum} \\ H \cdot m\,(w + b), & \text{multiply} \\ (1-m)\,H + m\,(w + b), & \text{crossfade} \end{cases}

where mm is warp_mix, bb is warp_bias, and a is the deformation shift controlling the digamma pair offsets.

The output variants are:

udefault(x,t)=AD(φ;Hmix,a)u_{\text{default}}(x, t) = A \, D(\varphi; H_{\text{mix}}, a) usawtooth(x,t)=AD(φ;Hmix,a)sinφu_{\text{sawtooth}}(x, t) = A \, D(\varphi; H_{\text{mix}}, a)\,\sin\varphi utriangle(x,t)=A(D(φ;Hmix,a))2sinφu_{\text{triangle}}(x, t) = A \, \left(D(\varphi; H_{\text{mix}}, a)\right)^2 \sin\varphi

Shape variants:

  • default: Base digamma waveform
  • sawtooth: Base waveform multiplied by sinφ\sin\varphi
  • triangle: Squared base waveform multiplied by sinφ\sin\varphi
ParameterTypeDefaultRangeDescription
amplitudedouble 0.5≥0Peak amplitude of the digamma-square driver
wavenumberdouble 1.0unboundedBase spatial wavenumber
omegadouble 1.0unboundedBase angular frequency
phasedouble 0.0[0, 2π]Phase offset
time_offsetdouble 0.0unboundedAdditional time shift
nominal_dtdouble 0.0≥0Nominal timestep when fixed_clock = true
fixed_clockboolean falseLock the driver to nominal_dt
harmonicsdouble 4.0[0.25, 24]Base harmonic mix factor
adouble 0.25[0, 0.5]Deformation shift controlling the digamma pair offsets
warp_fieldfield handlenilOptional field handle supplying per-sample warp modulation
warp_mixdouble 1.0unboundedWarp gain, or crossfade weight when warp_mode = "crossfade"
warp_biasdouble 0.0unboundedBias added to the warp-field sample before mixing
warp_modeenum "sum"see belowHarmonic/warp combine rule
shapeenum "default"see belowWaveform shape
backendenum "12_tail"see belowDigamma computation method
tolerancedouble 1e-12≥0Tolerance for adaptive backend
rotationdouble 0.0unboundedComplex phase rotation
scale_by_dtboolean falseScale writes by dt instead of injecting dt-independently
use_wavevectorboolean falseUse (kx, ky) instead of wavenumber + coordinate mapping
kx, kydouble 0.0unboundedWavevector components used when use_wavevector = true

Shape options: default, sawtooth, triangle

Warp mode options: sum, multiply, crossfade

Backend options: 5_tail, 7_tail, 12_tail, adaptive, mortici

When warp_field is complex, the operator uses its real component for warp mixing. The a parameter is folded and clamped slightly away from 0 and 0.5 internally to avoid digamma poles and degenerate differences.

Plus shared coordinate mapping parameters.

Migration note: Former add_digamma_square_warp_operator(ctx, field, warp, opts) calls now become add_digamma_square_operator(ctx, field, { warp_field = warp, ... }).

-- Basic digamma square wave with deformation shift
ooc.add_digamma_square_operator(ctx, field, {
amplitude = 0.3,
wavenumber = 1.0,
omega = 0.6,
harmonics = 6.0,
a = 0.28
})
-- Field-driven crossfade warping
ooc.add_digamma_square_operator(ctx, field, {
amplitude = 0.4,
wavenumber = 0.8,
omega = 1.0,
warp_field = warp,
warp_mode = "crossfade",
warp_mix = 0.5,
harmonics = 8.0
})
-- Sawtooth variant with additive warp bias
ooc.add_digamma_square_operator(ctx, field, {
amplitude = 0.5,
wavenumber = 0.8,
omega = 1.0,
shape = "sawtooth",
warp_field = warp,
warp_mode = "sum",
warp_mix = 0.3,
warp_bias = 0.1
})
-- High-precision adaptive backend
ooc.add_digamma_square_operator(ctx, field, {
amplitude = 0.35,
wavenumber = 1.0,
omega = 0.5,
backend = "adaptive",
tolerance = 1e-14
})

add_stimulus_operator(ctx, field, opts)

Generate a Gaussian ridge around a coupled Lissajous curve. This is useful for tracing multi-frequency trajectories, resonant loops, and implicit oscillatory masks.

add_stimulus_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

Note: Requires type = "stimulus_lissajous".

The operator forms two oscillators

θx=kxxωxt+ϕx,θy=kyyωyt+ϕy\theta_x = k_x x - \omega_x t + \phi_x, \qquad \theta_y = k_y y - \omega_y t + \phi_y

and injects a Gaussian band around the implicit relation

sin(θx)=csin(θy)+b\sin(\theta_x) = c\,\sin(\theta_y) + b

with width controlled by line_width.

ParameterTypeDefaultDescription
typestring Must be "stimulus_lissajous"
wavenumber_xdouble 3.0X oscillator wavenumber
wavenumber_ydouble 2.0Y oscillator wavenumber
omega_xdouble 0.0X oscillator angular frequency
omega_ydouble 0.0Y oscillator angular frequency
phase_xdouble 0.0X oscillator phase offset
phase_ydouble 0.0Y oscillator phase offset
couplingdouble 1.0Multiplier applied to the Y oscillator relation
biasdouble 0.0Additive offset in the implicit-curve relation
line_widthdouble 0.25Gaussian ridge width

Plus shared coordinate mapping and timing parameters (amplitude, time_offset, rotation, scale_by_dt).

ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_lissajous",
amplitude = 0.8,
wavenumber_x = 3.0,
wavenumber_y = 2.0,
line_width = 0.18
})
ooc.add_stimulus_operator(ctx, field, {
type = "stimulus_lissajous",
amplitude = 0.5,
omega_x = 0.2,
omega_y = 0.3,
coupling = 0.75
})