# Maximum current - Feature

**URL:** <https://forum.electromage.com/t/maximum-current-feature/2793>\
**Category:** Feature Ideas + Requests\
**Created:** [February 12, 2023, 4:02pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793 "2023-02-12T16:02:43Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![mephisto](https://forum.electromage.com/letter_avatar_proxy/v4/letter/m/48db29/32.png) [@mephisto](https://forum.electromage.com/u/mephisto)\
**Post date:** [February 12, 2023, 4:02pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793/1 "2023-02-12T16:02:43Z")

</div>

Hi,

some of you maybe know about the software WLED you can run on ESP32s.  
they have a feature i find very useful. it is “Maximum current”:with it i can have a 5m strip but only power it with a 2A power supply and configure 2A max current.  
This way i never need to worry about having a too weak power supply for my projects.

---

<div class="post-metadata">

**Author:** ![jeff](https://forum.electromage.com/user_avatar/forum.electromage.com/jeff/32/3473_2.png) [@jeff](https://forum.electromage.com/u/jeff)\
**Post date:** [February 15, 2023, 8:15pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793/2 "2023-02-15T20:15:07Z")

</div>

Hey @mephisto! Thanks for bringing this up.

I think there was a community discussion about this once before, and I think the main issue preventing this from being easy on Pixelblaze is an internal architecture decision.

Pixelblaze doesn’t buffer it’s computation internally. That means that as soon as the first pixel in a frame is computed, it can be sent out to the strip. This pipelining has some speed and architectural advantages. Unfortunately it also prevents you from knowing how to scale the first pixel’s intensity to satisfy power consumption constraints, because you need to know the planned intensity of all pixels in the frame before selecting a scale factor for them all.

It might be also feasible to always scale the next frame based on the prior frame’s values and a short term moving average. I wonder if a larger capacitor across the rails would help for this situation too.

A second and more minor challenge was that different models of pixels have slightly different maximum current draws. But that’s something we could allow people to measure themselves, or apply a conservative estimate, like 60 mA for 5 V pixels.

Thanks for the suggestion and telling us what you find useful in other controllers!

---

<div class="post-metadata">

**Author:** ![mephisto](https://forum.electromage.com/letter_avatar_proxy/v4/letter/m/48db29/32.png) [@mephisto](https://forum.electromage.com/u/mephisto)\
**Post date:** [February 15, 2023, 11:00pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793/3 "2023-02-15T23:00:58Z")

</div>

thank you for explaining this in so much detail.

this makes sense. how do you go about calculating power using for your projects. using the full 60mA seems excessive.

---

<div class="post-metadata">

**Author:** ![sorceror](https://forum.electromage.com/user_avatar/forum.electromage.com/sorceror/32/735_2.png) [@sorceror](https://forum.electromage.com/u/sorceror)\
**Post date:** [February 16, 2023, 7:15pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793/4 "2023-02-16T19:15:52Z")

</div>

In my patterns that use a framebuffer (i.e. an array of pixel values that I populate, and stream out in the render() function) and are on an amperage-limited power supply, if the total T of all values is above some maximum M, I multiply all of the values by M/T.

I don’t calculate the amps or anything, and I don’t scale it differently for R/G/B. I just lower M until the power supply stops popping its breaker. 😃

---

<div class="post-metadata">

**Author:** ![mephisto](https://forum.electromage.com/letter_avatar_proxy/v4/letter/m/48db29/32.png) [@mephisto](https://forum.electromage.com/u/mephisto)\
**Post date:** [February 18, 2023, 1:35pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793/5 "2023-02-18T13:35:21Z")

</div>

i think i understand what you mean, but i have no idea about how to do this.  
could you share a example?  
i am not good at programming (yet) but i am working on it 😅

---

<div class="post-metadata">

**Author:** ![sorceror](https://forum.electromage.com/user_avatar/forum.electromage.com/sorceror/32/735_2.png) [@sorceror](https://forum.electromage.com/u/sorceror)\
**Post date:** [February 18, 2023, 4:09pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793/6 "2023-02-18T16:09:22Z")

</div>

This isn’t a simple example, but … well … you just have to pay attention to how the fb\_ arrays are treated and the code commented with “Calculate the sum of all pixels in the framebuffer … and scale them all down if necessary!”

There are language features that would make a lot of this more concise … you are fortunate that I haven’t used them so you’ll have a better chance of understanding the code. 😉

> **Code**
>
> ```javascript
> // This pattern is designed for a "sword" with an LED strip folded in half
> // and demonstrates:
> // - non-render-ending HSVtoRGB function
> // - RGB framebuffer accumulation of HSVtoRGB results
> // - Framebuffer attenuation to avoid pulling too many amps from the battery
> 
> export var accelerometer
> 
> export var x = 0
> export var y = 0
> export var z = 0
> 
> export var total
> 
> // configuration
> var max_total = 12 // maximum total value to prevent overload
> var streak_count = 20 // streak count
> 
> // tuning
> var scale_acceleration = 50.0 // acceleration scale to ~ [-1,1]
> var scale_speed = 12.0 // speed scale to ~10x
> var scale_brightness = 8.0 // scale rgb by 1/scale_brightness before summing
> 
> // streak state storage
> var s_age = array(streak_count)
> var s_hue = array(streak_count)
> var s_spd = array(streak_count)
> var s_len = array(streak_count)
> 
> var hPc = pixelCount/2 // half pixelCount
> 
> // output framebuffer
> var fb_Red = array(hPc)
> var fb_Green = array(hPc)
> var fb_Blue = array(hPc)
> 
> // other stuff I was hacking on
> // export var angle = 0
> // export var max_spd = 0
> 
> var r, g, b // filled by HSVtoRGB
> 
> function HSVtoRGB(h, s, v) {
> var i, f, p, q, t;
> i = floor(h * 6);
> f = h * 6 - i;
> p = v * (1 - s);
> q = v * (1 - f * s);
> t = v * (1 - (1 - f) * s);
> im6 = i % 6
> if (im6 == 0) {
> r = v; g = t; b = p;
> } else { if (im6 == 1) {
> r = q; g = v; b = p;
> } else { if (im6 == 2) {
> r = p; g = v; b = t;
> } else { if (im6 == 3) {
> r = p; g = q; b = v;
> } else { if (im6 == 4) {
> r = t; g = p; b = v;
> } else {if (im6 == 5) {
> r = v; g = p; b = q;
> }}}}}}
> }
> 
> export function beforeRender(delta) {
> // current acceleration, with a 1-sample smoothing window
> var nx = clamp((x + (accelerometer[2]*scale_acceleration))/2.0,-1,1)
> var ny = clamp((y + (accelerometer[0]*scale_acceleration))/2.0,-1,1)
> var nz = clamp((z + (accelerometer[1]*scale_acceleration))/2.0,-1,1)
> 
> // angle = acos(((x*nx)+(y*ny)+(z*nz))/(sqrt(x*x+y*y+z*z)*sqrt(nx*nx+ny*ny+nz*nz)))
> 
> // clear framebuffer
> for (n = 0; n < hPc; n++) {
> fb_Red[n] = 0
> fb_Green[n] = 0
> fb_Blue[n] = 0
> }
> 
> // create a new streak if change in acceleration is low
> if (abs(sqrt(x*x+y*y+z*z) - sqrt(nx*nx+ny*ny+nz*nz)) < 0.25) {
> s_new = 1
> }
> 
> // render streaks
> for (n = 0; n < streak_count; n++) {
> // if we are creating a new streak, and this slot is empty, fill it
> if (s_new && s_age[n] == 0) {
> s_age[n] = 1/1024
> s_hue[n] = random(1) // or angle/PI // or (abs(nx-ny))
> s_spd[n] = 1 + scale_speed * sqrt(abs(nz * nx * ny) * (1 + random(2)))
> s_len[n] = max(12 - s_spd[n] + random(3), 3)
> // max_spd = max(max_spd, s_spd[n])
> s_new = 0
> }
> 
> if (s_age[n] > 0) {
> len = s_len[n]
> pix = s_spd[n] / scale_speed * s_age[n] / 6
> if ((pix-len) >= hPc) {
> s_age[n] = 0
> if (s_new) { n-- } // render this streak
> } else {
> s_age[n] += delta
> hue = s_hue[n]
> remaining = len
> for (pn = ceil(pix); remaining > 0 && pn >= 0; remaining--) {
> if (pn < hPc) {
> fade = remaining/len
> HSVtoRGB(hue, sqrt(clamp(1.5 - fade,0,1)), pow(clamp((1-pn/hPc) * fade * fade,0,1),1.5) )
> fb_Red[pn] += r/scale_brightness
> fb_Green[pn] += g/scale_brightness
> fb_Blue[pn] += b/scale_brightness
> }
> pn--
> }
> }
> }
> }
> 
> // Calculate the sum of all pixels in the framebuffer ...
> total = 0
> for (n = 0; n < hPc; n++) {
> fb_Red[n] = min(1,fb_Red[n])
> fb_Green[n] = min(1,fb_Green[n])
> fb_Blue[n] = min(1,fb_Blue[n])
> total += fb_Red[n] + fb_Green[n] + fb_Blue[n]
> }
> // ... and scale them all down if necessary!
> if (total > max_total) {
> adjust = total / max_total
> for (n = 0; n < hPc; n++) {
> fb_Red[n] *= adjust
> fb_Green[n] *= adjust
> fb_Blue[n] *= adjust
> }
> }
> 
> // Store current values for smoothing on next frame
> x = nx
> y = ny
> z = nz
> }
> 
> export function render(index) {
> // The PB is at one end of the strip, and the strip is folded in half
> // Use "^hPc - [...]" instead of "[...] - 1$" if PB is at the other end
> pindex = ( (index < hPc) ? (hPc - index) : (index - hPc + 1) ) - 1
> 
> rgb(fb_Red[pindex], fb_Green[pindex], fb_Blue[pindex])
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![jeff](https://forum.electromage.com/user_avatar/forum.electromage.com/jeff/32/3473_2.png) [@jeff](https://forum.electromage.com/u/jeff)\
**Post date:** [February 18, 2023, 6:47pm UTC](https://forum.electromage.com/t/maximum-current-feature/2793/7 "2023-02-18T18:47:56Z")

</div>

Sorceror’s example is great example because it does it correctly with R, G, and B components. To try to simplify it even more and show the essential idea, I wrote this slightly more minimal example.

```javascript
/*
  Limiting current using a framebuffer.
  
  Imagine the original pattern was:
  
  export function render(index) {
    pct = index / pixelCount
    v = perlinTurbulence(pct * 8, time(.1), 0, 4, 1, 2)
    hsv(0, 0, v) // Literal white noise
  }
  
  Instead, we'll calculate it all in beforeRender(), sum it up, and scale output
  such that very intense output above 20% of all-white is scaled down.
  
  This example is simplified to ignore how non-white RGB colors 
  draw different amounts.
*/

values = array(pixelCount)
export var currentLimitingFactor = 1 // Value to scale final output. Should be in 0..1.
var intensityLimit = .2 * pixelCount // 20% of max current limit

export function beforeRender(delta) {
  frameIntensitySum = 0
  
  for (i = 0; i < pixelCount; i++) {
    pct = i / pixelCount
    var thisValue = perlinTurbulence(pct * 8, time(.1), 0, 4, 1, 2)
    thisValue = clamp(thisValue, 0, 1) // limit outliers to their real current draw
    
    values[i] = thisValue
    frameIntensitySum = frameIntensitySum + thisValue
  }

  currentLimitingFactor = 1
  
  if (frameIntensitySum > intensityLimit) { // Over intensityLimit currrent draw
    currentLimitingFactor = intensityLimit / frameIntensitySum
  }
}

export function render(index) {
  v = values[index]

  hsv(0, 0, v * currentLimitingFactor) 
}

```

---

<div class="post-metadata">

**Author:** ![haro](https://forum.electromage.com/user_avatar/forum.electromage.com/haro/32/402_2.png) [@haro](https://forum.electromage.com/u/haro)\
**Post date:** [March 5, 2023, 10:44am UTC](https://forum.electromage.com/t/maximum-current-feature/2793/8 "2023-03-05T10:44:22Z")

</div>

What I do is set the Global Brightness to a low value, sometimes as low as 15 or 20% otherwise will trip the thermal breaker i use to limit overdriving the Power source. for example, i use 2048 led matrix that will suck way more than 100A and burn into a puff of smoke if you would let it. (Manufacturer says limit a panel of 256 to 7A, but the LEDs will consume a lot more) it’s powered by a 12A supply. with a 7A thermal limiter (circuit breaker) and an old school meter (for power consumption observation) and find running through most patterns works great at about 15-20%. If i set it higher, eventually i will find its tripped the breaker and need to reset it. i wrote a power test pattern and found the consumption is not quite linear and be careful if you set it to run all of the lights and the pattern locks up, it can be hard to reset, and need to get the board to crash and crash a few times to recover.
