Sine wave bar on Micro Dot Phat help

Hi,

I’ll admit up front that this is all down to my not listening in Maths lessons at school. ;)

What I want to do with my Micro Dot Phat is have a bar that repeatedly ‘bounces’ between the right and left ends of the matrix. So it will start of moving fast from the left hand side, slow down a bit in the middle and then speed up towards the right edge before repeating (but the other way obvs). I’m picturing the speed change (ie sleep time) as a sine wave being low at each edge and high in the middle.

This is where I’m stuck. I’ve looked at the sine wave code included in the microdotphat examples, but can’t see how to adjust that so that it gives one long wave over the entire width of the matrix.

Any assistance in this would be gratefully received.

All the best,

Dave

Looks like this is going to be one of my long-form forum posts again ;) Challenge accepted.

It wasn’t until recently that I saw visualizations of a Sine Wave that I fully understood what makes them tick. This was the image (ignore the bottom two, entrancing though they may be :D ):

I wont try to explain the mathematics, because my experience with using sin in code is almost entirely the result of trial and error. Let’s just get into the bare facts as they apply to programming:

  • math.sin returns a value between -1 and +1
  • math.sin expects an input value in radians = 180 degrees = PI radians
  • the difference in radians between an output value of -1 and +1 is PI

The easy way to see this is like to go to our repl and try it out:

import math

>>> math.sin(math.pi*0.5)
1.0
>>> math.sin(math.pi*1.5)
-1.0

If we feed sin an incremental number, either via a variable, or time.time() then it will oscillate between -1 and 1.

You can go back to the Python repl and see this like so:

import math
import time

while True:
    print(math.sin(time.time()))

This will also give you some feel for how quickly it changes. Want it to change faster? Simply multiply time.time(), slower? Simply divide time.time().

The result of math.sin(time.time() * SPEED) is therefore a number which goes from -1 to 1 over a duration of time which we control.

The next challenge is to scale that -1 to 1 range to the width of the matrix. Including hidden pixels Microdot pHAT is 45 pixels wide ( 56 for the matrix themselves, and 35 for the 5 spaces of 3 pixels each between them ).

First, let’s get out -1 to 1 to be 0 to 1:

>>> (-1 + 1) / 2
0
>>> (1 + 1) / 2
1

Adding 1 gives us 0 to 2, and dividing by 2 gives us 0 to 1

Now to get a number between 0 and 44 ( because the first pixel is at index 0 ) we just multiply the result by 44 and round it to a whole number, since there’s no such thing as half a pixel!

This leaves us with something like this:

speed = 1.0
delta = time.time()

scale = math.sin(delta * speed)

offset_y = round(44 * scale)

And that’s the y position for your scanning bar.

Your delta doesn’t have to be time.time(), it could be a number that you increment or some other external factor.

2 Likes

Wow. Just Wow. What a reply. This here, folks, is why pimoroni rules the waves. :)

Thanks for the info, I’ll enjoy hacking around with that and seeing what I can come up with. It certainly makes more sense now.

Cheers,

Dave

3 Likes