The Math behind DSF Synthesis

Created on 2024-10-08T10:32:54-05:00

Return to the Index

This card pertains to a resource available on the internet.

This card can also be read via Gemini.

DSF Synthesis

DSF synths come from the paper "The Synthesis of Complex Audio Spectra by Means of Discrete Summation Formulae" by James A. Moorer.

Samples are created by sum[k=0..N](a^k * sin(theta + k * beta)) which places sine waves at equidistant harmonics with exponential decays.

s(t) = ∑_k=0..N w^k sin(2p(f_c + k f_m) t / sampletime),

where

s(t) is the sample to be output at sample step t

fc is the fundamental frequency

fm is the "distance frequency" between the sine waves (hence called harmonics)

wk is the magnitude of the k-th harmonic (ie. for w<1, the magnitudes of the higher harmonics are getting smaller and smaller)

t is the number of the sample step (with." t / sampletime" being the time in seconds at which sample t is output)

N is the number of harmonics plus 1 (for the fundamental)

N must be chosen such that f_c + N * f_m is less than the nyquist frequency.

Phasors

Cosine and sine arcs can be stored and rotated uing a mathematical device called "phasors." This stores the position in a polar coordinate system.

Phasors can write their position as a complex number: A * cos(wt+delta) + i * sin(wt+delta), or in programmer notation .

You can create an angle as a phasor with .

Multiplying a phasor by another phasor adapts the size and rotation; since you can create an angle with an area of 1, this will only rotate the phasor without changing anything else.

Phasors may then be rotated using only a few multiply operations against the complex numbers--skipping trigonometry table lookups.

Multiplying phasors applies the rotations because: (A*[cos(w),sin(w)]) * (B* [cos(g),sin(g)]) = A*B * [cos(w+g),sin(w+g)]

# complex multiply
result.real = a.real * b.real - a.imaginary * b.imaginary
result.imaginary = a.real * b.imaginary + a.imaginary * b.real
# renormalize the phasor
let t = 1.0 / sqrt(self.real * self.real + self.imaginary * self.imaginary)
self.real *= t
self.imaginary *= t

Geometric series shenanigans

Geometric series convergence

Given a geometric series:

sum[k=0..N](a * b^k)

there exist two "closed form" convergence formulas:

when r=1: a(n+1)

otherwise: a(1-r^(n+1) / 1-r)

Which the original article describes as "wooshing" away the sum.

Complex numbers

The Verklage reformulates the synthesizer as sum[k=0..N](a * b^k), the geometric series with a known shortcut solution.

This is backed by replacing 'a' with the phasor (complex number) and 'b' with the phasor multiplied by w (the magnitude of harmonics.)

The exponent 'k' is distributed from the phase to the real and imaginary component of its complex number, thus: ^k becomes

When the two complex numbers are multiplied, the w^k is distributed to both components of the remaining complex number.

Result

All of these shenanigans justify why you can generate a sample with a * (1-b^(+1)/1-b) where 'a' and 'b' are phasors (complex numbers) and the result is a phasor with the cosine (real component) and sine (imaginary component) together. Which is more computationally efficient than having to generate each sine and decay it per-sample.

Normalization

Since signals are being summed it could get louder based on N. Burkhard uses a rule that sum[k=0..N](w^k) is the highest signal possible, which has a convergence of (1-w^(N+1))/(1-w), so the resultant signal can be divided by this amount to 'normalize' the output.