Underwater Voltmeter - high performance diagrams on Arduino
Published: 2023-07-03 17:39:52

When you're developing for the web and mobile, you don't need to worry much about the performance of your display. This article covers the case when your device is offline, has limited resources and on top of it all... gets thrown into the water.

# Video intro
{% embed https://www.youtube.com/embed/HD4bUMoowLA %}

It's a bit like coding in the early days of User Interfaces. This interface works like an oscilloscope that can measure the voltage of an analog input pin and display it as a waveform on the screen.  But we need to treat data, time, and updates in other UIs as well. So I hope this article helps you with whatever you want to optimize.

[Here's the link to the Arduino code](https://github.com/shnydercom/tutorials/blob/main/underwater-voltmeter/VoltMeterGraph.ino#L65)


# Challenges
One of the challenges of this project is to make the display as smooth and responsive as possible, without flickering or lagging. To achieve this, **only updated, individual pixels are drawn** in each loop, instead of clearing and redrawing the whole screen. This way, I can save a lot of time and resources, and make the display more efficient.

Calculating diagonal lines between data points would take time and resources. Especially because we would need to re-calculate them when we overdraw the previous pixels, so we're constrained to using pixels or horizontal bars.

It can cause some artifacts or glitches if the pixels are not updated correctly or in sync. So we need to keep track of time to make the display independent of the processor speed.


# How the algorithm is faster
The algorithm does ***not*** redraw all of the pixels on each frame. Actually, it is pretty picky and benefits from the fact that we only show one value on the Y-Axis, and not multiple lines.

Here's how it works:
- It reads the voltage from an analog pin and adds it to a buffer array.
- It calculates and displays the max, average, and current voltage on the screen as text.
- It draws a waveform on the screen that shows the voltage over time using iterative pixel drawing.
- Iterative pixel drawing means that it only updates the pixels that change in each loop, instead of clearing and redrawing the whole screen.
- To do this, it uses another array called yBuf that stores the height of each pixel on the waveform.
- It shifts the values in yBuf to the left by a number of pixels that depends on the time difference between loops.
- It loops through each pixel on the waveform and updates its color and height according to the values in yBuf and the buffer array.

# The narrower the use case, the easier it is to improve performance
"Drawing the text actually competes for processor time with drawing the diagram, so this could be optimized"

But.... When we talk about "performance", these kinds of arguments are often brought up. Even if the diagram was quicker, would I actually use the 1 second diagram that often, or are the 5 seconds better? Is the accurate measurement or the moving average more important? Do I need a second value on the y-Axis, or is a single one just fine? All of these questions are more reasons to open-source the code, so your individual code can solve your individual problem. Are your problem and mine then similar enough to be solved with the same code?

These are the types of questions that developers of libraries, APIs and standards often face, and why custom solutions might have higher, "local" performance.

Why "local"? It's because it depends on the context, the resource limits at the time of writing the code, the device(s) available, what environment they'll be used in and the person who is implementing it. So it's not just about knowing the Tech, it's about knowing the User(s), the facilitators and people's Needs and Skills as well.

And someone who is doing this for many people... wow! My deep appreciation for all the API/library/standards-creators out there!