software algos - diglet48/restim GitHub Wiki
Mostly of interest to developers wanting to reproduce Restim signals in their own applications.
Continuous signal generator
Recall from Software basics that there exists a translation from the 3-phase position to electrode intensity. How do we generate waveforms with the desired signal intensity?
The basic idea is to project N points on a 2D plane, one for each electrode. The distance from the points to the origin is the signal intensity. The signal can then be generated by sweeping around the plane.
conditions:
$$\begin{align}
p_1, p_2, ... p_n &= \text{projected points} \
\text{electrode}\ n \ \text{amplitude} &= |p_n| \
p_1 + p_2 + ... p_n &= 0
\end{align}$$
For three-phase the audio channels can be calculated as follows:
$$\left[\begin{matrix} \text{left audio channel}\ \text{right audio channel}\ 0 \end{matrix}\right] = T_{P2C} * \left[\begin{matrix} p1_x & p1_y\ p2_x & p2_y\ p3_x & p3_y\ \end{matrix}\right] * \left[\begin{matrix} \cos(t * \pi * 2 * \text{frequency})\ \sin(t * \pi * 2 * \text{frequency}) \end{matrix}\right] $$
Where $T_{P2C}$ is the potential to channel matrix described here. These equations can be easily extended to arbitrary numbers of phases.
The hard part is: how do we find points $P_1, P_2, ...$ such that the magnitude of the points equal the desired signal intensity and all points sum to 0. Fortunately, there exists an exact algorithm for three-phase:
$$\begin{align}
\alpha, \beta &= \text{user input} \
\theta &= \text{atan}(\beta, \alpha) \
r &= \text{norm}(\alpha, \beta) \
\text{base} &=
\left[\begin{matrix}
\cos(0) & \sin(0) \
\cos(120) & \sin(120) \
\cos(-120) & \sin(-120) \
\end{matrix}\right] \
\text{offset} &=
\left[\begin{matrix}
\cos(\theta) & \sin(\theta) \
\cos(\theta - 120) & \sin(\theta - 120) \
\cos(\theta + 120) & \sin(\theta + 120) \
\end{matrix}\right] \
\text{projected points} &= \text{base} * (1 - \frac{r}{2}) + \text{offset} * \frac{r}{2}
\end{align}
$$
The following code is equivalent, but more optimized:
$$\text{projected points} = \ \left[\begin{matrix} 1 & 0 \ {-} \frac{1}{2} & \frac{\sqrt{3}}{2} \ {-} \frac{1}{2} & - \frac{\sqrt{3}}{2} \end{matrix}\right] * \left[\begin{matrix} 2 - r + \alpha & \beta \ \beta & 2 - r - \alpha \end{matrix}\right] * \frac{1}{2} $$
For more than three electrode, no exact algorithm is known. But a solution can be found iteratively.
The end result has to be multiplied by the calibration matrix before sending it to the box.
Pulse-based signal generator (version 1)
The pulse-based signal generator is an attempt to improve the energy-efficiency of the continuous generator. Nerves can only fire so many times per second, so it makes no sense to 'bombard' them with a 1000hz signal.
This is done by generating short bursts of signal, generally 4-10 carrier cycles wide, repeated at 20-80hz. To avoid transients and unbalanced waveforms, the start and end of the pulse are ramped. Additionally, the start angle and polarity are randomized.
The rest of the signal generation math is identical to the continuous signal generation algorithm.
Pulse-based signal generator (proposed version 2)
Similar to version 1. However, the projected points are not directly translated to the voltage or current. Rather, it is interpreted as the charge balance of the electrode. To get the waveform voltage or current, take the derivative of the charge. This modification guarantees charge-balanced pulses and reduces the minimum ramp time and pulse width.
Coming soon.
NeoDK signal generator
Todo.