You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a software emulation of the Torpor variant of the Eurorack module
Sloth Chaos
by Andrew Fitch at
Nonlinear Circuits.
Sloth Torpor is a chaotic oscillator that emits two slowly
changing voltages designated $x$ and $y$.
The behavior of this circuit is unpredictable over time,
but more orderly than random. It is often used as a low
frequency control voltage in cases where an LFO would be
too predictable, but a random signal would be too erratic.
Sloth Torpor provides two inputs: a performer-controlled
potentiometer $R_9$ and a control voltage $U$.
This document explains how the hardware design was converted
into a software simulation. It requires some understanding of
electronics theory and single-variable differential calculus.
For a better understanding of the analysis below, I recommend
watching this video.
Circuit description and definitions
The circuit consists of resistors, capacitors, and a
TL074 quad op-amp chip.
Three of the op-amps on the chip, U2, U3, and U4,
use feedback to operate as linear amplifiers.
In other words, the node voltages
$w$, $x$, $y$, and $z$
change smoothly with time and stay within well-defined limits
away from op-amp saturation.
The inverting (−) inputs to U2, U3, and U4 can be assumed
to be fixed to a voltage very near that of their noninverting (+) inputs,
which are all 0 V. These inverting inputs are called virtual grounds.
In contrast, the remaining op-amp U1 acts as a comparator
that outputs a binary state voltage
I measured the voltages above using my own construction
of the circuit on a breadboard. These op-amp saturation voltages
are consistent with their ±12 V Eurorack supply rail.
Circuit analysis
The analysis is based on Kirchoff's Current Law (KCL). Like water, electrical current is highly incompressible. This means that the amount of current flowing into a node must be equal to the amount of current flowing back out. By defining currents as positive when they flow into a node or negative when they flow out, KCL can be stated as: the sum of all currents flowing into a node must be equal to zero.
We use Ohm's Law for resistors:
$$
I=V/R
$$
where $I$ is the current flowing through a resistor measured in amps, $V$ is the voltage difference across the resistor's terminals in volts, and $R$ is the resistor's resistance in ohms.
For capacitors, we use the formula
$$
I = C\frac{\mathrm{d}V}{\mathrm{d}t}
$$
where $C$ is the capacitance in farads. This tells us that the current flowing through a capacitor is proportional to how fast the voltage across its terminals is changing with respect to time.
Using KCL, the sum of currents into the node at the (−) input of U3 must be zero:
The simulation is implemented as the C++ class
SlothCircuit.
The method SlothCircuit::update is called once per
audio sample to calculate the next circuit state.
All calculations use 64-bit IEEE floating-point arithmetic
to ensure stability and convergence.
The capacitors $C_1$, $C_2$, and $C_3$ are like analog memories.
Their initial charge states are boundary values for the differential equations.
It is reasonable and practical to assume the circuit powers up with uncharged
capacitors, so we define the initial node voltages as
$$
x_0=w_0=y_0=0
$$
The control voltage $U$ and the variable resistance $K$ are sampled
once at the beginning of each time step $n$.
Although $U$ and $K$ are time-dependent inputs, inside the
time span $\Delta t$ of each sample they are treated as constants.
Rewrite equation (2) to find the infinitesimal change in $x$:
We know the values of everything on the right hand side of equation (6).
We can update the value of $x$ over a finite time step $\Delta t$
by approximating the infinitesimal quantities as finite differences:
We could evaluate steps (7) through (10) for each successive sample $n$
to generate the output signal. But this model is too simple for good accuracy.
Refined stability and precision
Approximating infinitesimals like $\mathrm{d}x$ with finite differences
like $\Delta x$ is risky for accuracy and numerical stability.
Therefore, it is better to refine the algorithm above by using iteration
to converge on mean values $\bar{x}$, $\bar{w}$, $\bar{y}$, and $\bar{z}$
over the continuous interval between samples $n$ and $n+1$.
We will do this wherever a capacitor is being charged/discharged
continuously during the time interval.
Use equations (7) through (10) to compute initial estimates of
$x_{n+1}$, $w_{n+1}$, $y_{n+1}$, and $z_{n+1}$,
as described in the previous section.
Then calculate estimated mean values over the time interval as
$$
\bar{x} = \frac{x_n + x_{n+1}}{2}
$$
$$
\bar{w} = \frac{w_n + w_{n+1}}{2}
$$
$$
\bar{y} = \frac{y_n + y_{n+1}}{2}
$$
$$
\bar{z} = \frac{z_n + z_{n+1}}{2}
$$
We also need a representative value $\bar{Q}$ for the time interval.
Usually $Q(z)$ will be a constant over the time interval,
because the values of $z_n$ and $z_{n+1}$ almost always have the same polarity.
But the mean value $\bar{Q}$ requires care when $z_n$ and $z_{n+1}$ have
opposite polarities, or more precisely, when $z_n z_{n+1} \lt 0$.
In this case, use a weighted mean value of $\bar{Q}$ over the time
interval. Assuming that $z(t)$ is approximately linear over the time
step, let $0 \lt \alpha \lt 1$ represent the fraction along the time step
at which $z(t) = 0$. Then
Unlike the other voltage variables, we can assume the op-amp U2
responds instanteously to its input, since there is no capacitor
to be charged or discharged. Therefore equation (10) remains valid.
We still have to re-evaluate (10) on each iteration because the
estimate of $y_{n+1}$ keeps changing. This yields an improved estimate
for the next value of $z$:
Iterate the above steps until the values
$x_{n+1}$, $w_{n+1}$, $y_{n+1}$, and $z_{n+1}$
converge within tolerance.
More precisely, we keep track of the values of the voltage deltas
$$
\Delta x = x_{n+1} - x_n
$$
$$
\Delta w = w_{n+1} - w_n
$$
$$
\Delta y = y_{n+1} - y_n
$$
and define the changes in successive estimates of the deltas as
$$
X = ( \Delta x ) _ {i+1} - ( \Delta x ) _ {i}
$$
$$
W = ( \Delta w ) _ {i+1} - ( \Delta w ) _ {i}
$$
$$
Y = ( \Delta y ) _ {i+1} - ( \Delta y ) _ {i}
$$
where $i$ is the convergence iteration counter.
Note that $i$ increases by one every time we update our estimates
of $\Delta x$, $\Delta y$, and $\Delta w$.
Keep iterating and incrementing $i$ until
$$
X^2 + W^2 + Y^2 \lt \epsilon^2
$$
where $\epsilon$ is a voltage error tolerance.
I use a tolerance of one picovolt ($\epsilon = 10^{-12} V$).
At a sample rate of 44100 Hz, convergence almost always happens in 3 iterations, but it never takes more than 4 iterations.
It is important in general to test at different sample rates and
input conditions to make sure convergence happens, and to provide
a failsafe iteration limit. In my implementation, I never allow
more than 5 iterations.
On a typical 64-bit processor, this algorithm generates one hour's
worth of output signal at 44100 Hz using only a few seconds
of CPU time. CPU overhead is thus less than 0.5% even on modest systems.
About
Circuit simulation of Sloth module by Nonlinear Circuits