I recently posted a few ideas about how to improve the framerate of an ambilight driven using the Adalight protocol. Before trying to implement some of those options, I thought it would be worthwhile to actually calculate the theoretical framerate limitations.

This post is part of a series on creating a DIY ambilight using Adalight and WS2812B LEDs. Check out the project page here.

Assumptions and Goals

Before jumping into the math, I need to make one thing clear: these are the absolute, theoretical limits for the given data throughput settings only. I’m ignoring processing speed entirely from both ends and only focusing on the serial rate and the LED speed. The processing speed, combined with the inconsistency of the grab software and dropped frames due to the LED latching, means that you’ll likely never reach these limits in practice.

The monitor my ambilight is attached to runs at 60 hz, which makes my target framerate 60 frames per second (fps). Anything above 60 fps is considered excessive, because the ambilight will be repeating frames.

There is another advantage to higher baud rates, which is that even at the same framerate a higher data throughput (higher baud rate or fewer LEDs) will reduce the delay between frame generation and when the frame appears on the LEDs. In other words, the ambilight stays in “sync” with the monitor better at higher data rates.

My setup uses an Arduino Nano to drive 80 WS2812B LEDs using the Adalight protocol through Prismatik. At the moment it’s running at 115200 baud, the highest rate selectable in Prismatik.

Function Graphs

A picture is worth a thousand words, so let’s start with the visual representations and then talk about the math behind them.

Frame Limit vs. LED Number

This is a graph of the overall theoretical frame limit per second for WS2812B LEDs as a function of number of LEDs, shown at multiple baud rates.

Right away it should be clear how critical data throughput is to achieving an acceptable framerate.

At 9600 baud, an ambilight is nigh-unfeasible. A target framerate of 60, matching most common desktop monitors, is only possible if the number of LEDs is 3 or fewer. An “acceptable” framerate of 30 is only possible at 8 or fewer LEDs. By 30 LEDs the framerate is in the single digits.

Sextupling the baud rate to 57600 makes things much more reasonable. Hitting the target of 60 fps is theoretically possible for 27 or fewer LEDs, almost a 10-fold increase. As data throughput increases, that LED limit for 60 fps is continuously upped. At a baud rate of 921600, a framerate of 60 is theoretically possible at even 256 LEDs.

For my 80 LED setup, 230400 is the slowest standard baud rate that would allow me to achieve 60 frames per second (theoretical max: 76.47).

Frame Limit vs. Baud Rate

For another perspective, here is a graph of the overall framerate limit at various baud rates for 20, 40, 60, 80, 100, and 120 LEDs.

This graph covers the range for all three baud rates available in Prismatik: 9600, 57600, and 115200. You can see that achieving 60 fps is only possible for small-numbered LED setups.

Expanding the graph for baud rates up to 1M paints a more optimistic picture:

You can see that LED lengths up to ~100 can theoretically reach 60 fps at a baud rate as low as 230400.

Equations

Luckily for us, the equations to calculate these limits are all fairly simple (assuming I didn’t overlook anything in my calculations).

I apologize in advance if some of the notation is wonky. It’s been a long time since I’ve taken a proper math class. It’s also my first time writing anything in \LaTeX.

Combined Framerate Limit

Here is the total frame limit equation in its entirety:

F_{Total} = {({10{(3N + 6)} \over {b}} + 0.00003N)}^{-1}

Where:

  • FTotal is the combined framerate limit from the serial connection and WS2812B latch time
  • b is the baud rate
  • N is the number of LEDs

I think it’s easier to think about when we break the equation into its components, so I’m going to talk about each one in turn.

SERIAL FRAME TIME

The first half of the equation is the serial frame time, or the amount of time it takes to send a single frame over serial.

T_{Serial} = {10{(3N + 6)} \over {b}}

The numerator (10{(3N + 6)} ) is the amount of data required, in bits, per frame: 3 bytes per LED for the color data (1 each for Red, Green, and Blue) plus an additional 6 for the header (magic word “Ada” and a 3 byte checksum). This is multiplied by 10 to get the number of bits (baud) required for each byte (8 data bits + 1 start bit + 1 stop bit).

Dividing the baud required per frame by the baud rate (baud per second) gives us the frame time.

Solving the equation for my setup at 115200 baud and 80 LEDs gives us a frame time of 0.0214 seconds each, or 21.4 milliseconds each, for the serial data.

The reciprocal of this is the framerate limit for the serial connection:

F_{Serial} = {{b} \over {10{(3N + 6)}}}

With the same parameters, we would have a serial framerate limit of 46.8 frames per second.

While this is useful for thinking about the serial data, it doesn’t take into account the data time for the WS2812B LEDs.

LED Data Time

This is where the second half of the equation comes into play. After it successfully receives and parses the serial color data, the microcontroller disables interrupts in order to send the color data to the WS2812B LEDs.

T_{LED} = {0.00003N}

Each WS2812B LED takes approximately 30µs per LED for the color data transfer. Solving (0.00003 seconds * the number of LEDs) gives us the time, in seconds, that the microcontroller is sending the color data to the LEDs and cannot receive any new serial data.

Once again, for my setup of 80 WS2812B LEDs we can solve the equation:

0.0024 s = {0.00003 s * 80}

2400{\mu}s = {30 {\mu}s * 80}

Which gives us 2400 microseconds, which is 2.4 milliseconds or 0.0024 seconds of LED time per frame.

The reciprocal of this is the framerate limit for the LED data. That is to say – if we assume the serial data is always available instantaneously, what is the frame cap imposed by the time required to send the data to the LEDs?

F_{LED} = {1 \over {0.00003N}}

For my 80 LED setup, that is {1 \over 0.0024} 416.7 frames per second,which is high enough not to cause any issues with the target framerate of 60.

Combined Frame Time

Adding the serial frame time of 0.0214 seconds and the led frame time of 0.0024 seconds gives us our combined frame time of 0.0238 seconds, or 23.8 milliseconds per frame. The reciprocal of this (all^{-1} or {1 \over all} ) is our combined framerate limit – the equation at the top.

For my 80 WS2812B LED setup at 115200 baud, our theoretical framerate limit is therefore 42 frames per second. Punching this equation into a spreadsheet allowed me to generate the graph above.

Equation in Plain Text

In case it’s useful to anyone, here is the equation in both LaTeX and plain text:

F_{Total} = {({10{(3N + 6)} \over {b}} + 0.00003N)}^{-1}
Ftotal = ((10 (3N + 6)) / b + 0.00003N)^-1

Conclusion

Figuring-out the formula for these limits was quite fun, and it gives me some insight into how everything relates mathematically, not only conceptually. Hopefully it will also help others who are trying to plan their own Adalight system to see the framerate limits of their design.

In the next post, I’m going to expand on this by measuring the actual frame times and framerate produced by my own ambilight setup using a logic analyzer.


6 Comments

Merlijn · September 17, 2018 at 3:19 am

Hi. I’m interested in creating the same DIY ambilight system as you made. Many thanks for the guide! I do have a question about the number of LEDs. You used 60 led/m for a total of 80 leds. I have a rather large (‘ultrawide’ 21:9) screen and if I would use 60 led/m I would end up with about 140 leds (for 4 sides of the monitor). Would that be too much? Should I go with 30 led/m instead or would that ‘resolution’ be too low (your example videos look great)?

Thanks!

    Dave · September 17, 2018 at 3:47 am

    Don’t sweat too much about the “resolution”, the colors will blend a lot before they hit the wall behind the monitor. 140 LEDs is pushing it a bit so I would up the baudrate, but it won’t be too bad. You can get 30/m if you want to be safe, but it’ll probably be fine.

    On the other hand I wouldn’t use WS2812B LEDs again, though it was a good learning experience. If you spend a little more money to get something like APA102 you’ll get significantly better framerates.

      Merlijn · September 18, 2018 at 3:04 am

      Thanks for the tip about the APA102. I never heard of it but did some Googling and it sure seems like the general concensus is that it’s better than WS2812. Though, did you really have framerate problems with the WS2812 or is it more if a ‘theoretical better’?

      In any case, I know very little about DIY electronics so this is all new to me (I’m certainly open to learning though). Small question before I buy a LED strip: I saw that the APA102 leds have 4 connections instead of 3 with the WS2812. One of those is for the clock I believe. I assume those APA102 leds can still be controlled by a standard Arduino (Nano) and is compatible with the software you used?

        Dave · September 18, 2018 at 4:37 am

        It’s both really. I don’t personally have framerate problems with the WS LEDs, but if I had a few more it would be an issue. The slow speed is less of an issue than the lost bytes due to disabled interrupts, which cause you to lose entire frames. The only time I notice it is when turning off the LEDs – I have to make sure nothing fast is happening onscreen otherwise it often drops the single “off” frame.

        Exactly right, one pin is for the serial data and one is for the clock. The WS2812B chipset uses a precisely timed protocol which allows them to get away with only the one data pin. You can use the same Arduino and the same code, you’ll just need to change the chipset variable to use APA102 rather than WS2812B and you need to add the clock pin to the “addLeds” function call. You should be able to find plenty of FastLED examples with APA102, I promise you it’ll be easy.

Taras Johannis · June 11, 2024 at 8:16 am

Mr. Madison, thank you for sharing you knowledge.
How would the equation change, if you had an SK6812 RGBW-SPI-strip with a 800 kHz baud rate?
Would the serial frame time change to T = 10(4N+6)/b or would something else change (too)?
Thank you in advance.

    Dave · June 11, 2024 at 5:07 pm

    Hi Taras. As far as I know the SK6812 timing is identical to WS2812B, so you are correct that the only change would be from 3 to 4 for the additional white byte.

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Would you like to know more?