A photo of myself
Fathy

Table of contents

  1. Inanimate carbon rod
  2. Hip to be square
  3. Do the astral plane
  4. Shape of things to come
  5. Final thoughts
  6. Appendix

Every thing is a sin()

February 11, 2023 - Draft

What do heat transfer, music, JPEG, and Wi-Fi have in common? In 1807 Jean-Baptiste Fourier presented his paper "On the propagation of heat in solid bodies" to the Paris Institute and it made a lot nerds happy.

Inanimate carbon rod

We'll start by looking at this rod with an infrared camera:


If we graph the temperature we get a beautifiul sine wave:

Let's measure the rod temperature while it cools off:

Fourier found that for a perfect sine wave like ours, we can get the temperature over time using this formula:

cos⁡(ωx)e−kω2t\cos(\omega x)e^{-k\omega^2t}cos(ωx)e−kω2t

In the programming world we can translate this to the following code currently running on your graphic card:

float curve(float x, float t) {
    float o = 2.0 * pi; // omega: adjust frequency
    float k = 1.0; // conductivity: adjust how fast heat propagates

    return cos(o * x) * exp(-k * o * o * t);
}
ω: angle in radians
2 * π
k: how fast heat propagates
1

Now here is what happens when we make contact between a hot rod and a cold rod:

How can we compute the heat flow in this case? We have a formula for sine waves, but what we have here is a square wave.

Hip to be square

Let's pull some fairly standard electronic music production gear: an oscillator, an oscilloscope, and a spectrum analyzer with an harmonics indicator.

517

The numbers on the spectrum analyzer are called harmonics:

  • the first harmonic, also called the fundamental, equals frequency * 1
  • the second, also called the octave, equals frequency * 2
  • the third equals frequency * 3
  • and so on..

If you play with the oscillator a bit you will notice two important things:

  • a sine wave only has one harmonic: itself
  • a square wave only has odd harmonics decreasing exponentially

And that's all a square wave is, a sine wave with odd harmonics decreasing exponentially. So we have everything needed to decompose a square wave into sine waves and compute heat diffusion using them. Let's update our code:

float temperature(float x, float t) {
    float o = 2 * pi; // omega: adjust frequency
    float k = 1; // conductivity: adjust how fast heat propagates

    return cos(o * x) * exp(-k * o * o * t);
}

float curve(float x, float t) {
    float h = 3.0; // harmonics
    float c = 0.0; // sum of curves

    // Loop over odd harmonics: 1, 3, 5, 7, ...
    for (float i = 1.0; i <= h; i += 2.0) {
        // add the temperature for frequency * i and amplitude / i
        c += temperature(x * i, t) / i;
    }

    return c;
}
ω: angle in radians
1 * π
k: how fast heat propagates
4
h: how many harmonics
31

Do the astral plane

But how do you do a Fourier transform?

It's time to open our third eye and switch dimensions: instead of representing time as a plane we're going represent it in its true form, which as we all know is a circle repeating itself.

To help us visualize that, let's make the curve draw into a spinning disk:

Rotation speed

Tweaking the rotation speed gives us different shapes. Let's graph the average horizontal position based on the rotation speed:

horizontal positionrotation speed012345

Let's plug a square wave generate into this graph and see what happens:

horizontal positionrotation speed01234567891011121314151617181920

Input frequency

What we have here isn't exactly a Fourier transform, but it's close enough. It does what Fourier transforms does: represent signals as a function of frequency instead of a function time.

Shape of things to come

Every thing can be represented as signal, and every signal can be represented as an infinite sum of sine waves. So

Final thoughts

That's all for today folks, hope you enjoyed the ride.

All animations in this post are computed in real-time using WebGL and SVG, feel free to look at the souce code and even run it locally using the readme instructions!

Discuss on HN - Discuss on GitHub

Appendix

The center of mass visualization is based on work by Grant Sanderson from 3Blue1Brown, I recommend checking his videos out if you're interested in this topic.

If you're like me the formula might be hard to grasp:

g^(f)=∫t1t2g(t)e−2πiftdt\hat{g}(f)=\int_{t1}^{t2}g(t)e^{-2{\pi}ift}dtg^​(f)=∫t1t2​g(t)e−2πiftdt

Here is what I ended up with using JavaScript and simple math:

function kindaFFT({
    // Input signal
    g = (x) => Math.sin(x * Math.PI * 2),
    // Rotation frequency
    f = 1,
    // How many samples should we collect
    samples = 64,
} = {}) {
    // Store the graph data
    let x = []
    let y = []
    // Store weighted averages
    let centerX = 0
    let centerY = 0
    // Store averages weight
    let divider = 0

    // Loop over all the angles
    for (let i = 1; i <= samples; i++) {
        // Loop for each winding rotation
        for (let t = (i / samples) * f; t <= f; t++) {
            // Get the curve value for this angle and winding
            let value = g(t / f)

            // We now have a vector: an angle and an amplitude,
            // convert it vector into cartesian coordinates:
            centerX += value * Math.cos(t * Math.PI * 2)
            centerY += value * Math.sin(t * Math.PI * 2)
            // Add the value to the average weights
            divider += value
        }
    }

    // Compute the average position
    return {
        x: centerX / divider,
        y: centerY / divider,
    }
}