current control algorithm

Hi There,

I have two strings of 5 LEDs and a I need to control them with a pwm to reach a certain intensity (I can measure the current). Now due to lack of time , I didn't go with a PI controller (which I think would be the right way) instead, I just calculate a hysteresis of x counts (10bit adc) and the measured current has to be within this hysteresis. Now I unfortunately got a high jitter on my LED current (that's controlled by the duty cycle) - I assume this is because of a time delay from the time i set the duty cycle until i measure the current rise/fall. How do I best go about this? Is there a quick method to resolve this or do i actually need to take the time to study and implement a PI controller?

Thank you for hints & suggestions! Ron

Reply to
cerr
Loading thread data ...

Let me try and rephrase this. You have a way of measuring the current and use an ADC to do that. And you just set up two thresholds as your hysteresis bounds. When the measured value rises upwards, you use one threshold to control the LED ON/OFF state. When the measured value falls downwards, you use the other threshold. (You use finite differentials to determine direction and perhaps some smoothing on that?) And your "pwm" is really just bang-bang control driven by a fixed ADC sampling period?

Well, if all you are doing is turning the LED on and off and there is no serious RC in the way, then yeah... you will get a lot of jitter. Did you really expect to control the current to within some small value with bang-bang on an LED?

Think more closely about your goals. And let us know more about what they are.

Nothing is ever quick. I no longer ever consider anything taking less than half a day -- communication alone can eat that much up. Even brushing your teeth can wind up taking half a day if an unexpected complication arises. :)

But I'm still wondering if you are seriously trying to control the LED current in an analog fashion or if you really are willing to use PWM to control 'apparent' intensity, as seen my human perceptions. A lot depends on your goals. And I've no idea what they are, right now.

PI isn't even the question for me, right now. I'd need to know what you are trying to achieve and why.

Jon

Reply to
Jon Kirwan

Why do you think that would solve your problems? :>

What does the filter on your PWM output look like wrt the frequency at which you are operating the PWM?

How much "time jitter" do you have in your A/DC read routine? Can you drive the A/DC from the same PWM signal (so you are always sampling the sense signal at the same point in the PWM cycle)?

How are you measuring the current -- across a series resistor in the LED circuit? Try putting a small filter on the input to the A/DC (decoupling it from the actual "current signal" suitably) so your read timing isn't as critical.

Note that this will affect how quickly you can *change* the control as well. So, look at the entire system response.

Reply to
Don Y

You just need integral control, which is dead easy.

If I tried to count the number of times I've wasted far more time on a "time saving simplification" than I ended up spending finally doing a control loop right, I'd run out of fingers and toes before I even finished accounting for the first few years of my career.

--
www.wescottdesign.com
Reply to
Tim Wescott

One of the first big engineering projects I worked on had a blackboard that acquired anonymous one liners. One of these gems has stuck with me for more than 30 years.

"If you have enough time to do it over how come you didn't have a enough time to do it right?"

-- Walter Banks

formatting link

Reply to
Walter Banks

Every time you measure your current with the ADC, do something like this:

PWM += gain * (setpoint - current);

Calculations in floating point, or fixed point with sufficient bits, depending on your parameters, and clip PWM at min/max to avoid wrap around.

Experiment with different gain settings to see which one works best.

Reply to
Arlet Ottens

Cash flow.

Jon

Reply to
Jon Kirwan

Not every textbook solution is RIGHT.

Reply to
hamilton

To make it simple, you have just to slow down the rate at which you change the PWM factor. Slow enough so the loop becomes stable.

Dimiter

------------------------------------------------------ Dimiter Popoff Transgalactic Instruments

formatting link

------------------------------------------------------

formatting link

Reply to
dp

Or if a multiplication is just too high-tech:

if (setpoint > current) { PWM += increment; } else if (setpoint < current) { PWM -= increment; }

But multiplications are so cheap these days...

--
www.wescottdesign.com
Reply to
Tim Wescott

Or pick a gain that is a constant power of 2, so the multiplication can be done with a shift.

Reply to
Arlet Ottens

Thanks everyone for all the replies! The clarify my application: I control a buck generator with the pwm that will drive 5 LEDs per channel with a 300uS pulse at 3.5A. To reach 3.5A, I'm reading the current that is decoupled from the actual power circuit with an opamp. There's a bunch of filter caps there too. I have an IIR filter in my adc function and i take X samples (currently set to 100) before I adjust the pwm just to have some decent low pass filter there. How I adjust the pwm is just like this:

if (LEDcurrent[0] > HiLEDHys) if (CtrlIntens[0] > 0) set_pwm1_duty(--CtrlIntens[0]);

if (LEDcurrent[0] < LoLEDHys) if (CtrlIntens[0] < 100) set_pwm1_duty(++CtrlIntens[0]);

if (LEDcurrent[1] > HiLEDHys) if (CtrlIntens[1] > 0) set_pwm2_duty(--CtrlIntens[1]);

if (LEDcurrent[1] < LoLEDHys) if (CtrlIntens[1] < 100) set_pwm2_duty(++CtrlIntens[1]);

and i have an "emergency off that bypasses the "control filter". If the measured current is higher than the allowed current, immediately lower the duty cycle. The hysteresis is set to 50 counts and simply gets calculated like this: HiLEDHys =3D ((float)MAXLEDCURR / 100 * SetIntens); LoLEDHys =3D ((float)MAXLEDCURR / 100 * SetIntens) - HYSSZ; Where MAXLEDCURR is the maximum allowed LED current.

Reply to
cerr

That also ran through my mind. You can run into complications with bit depth: you're often much better off with something like

long integrator;

...

integrator += (setpoint - current); (check and fix integrator overflow) PWM = integrator >> INT_SHIFT;

than with doing the shift on the error signal.

--
www.wescottdesign.com
Reply to
Tim Wescott

What you have done is made an integrating controller with some nasty nonlinearities (the hysteresis, and the simple increment/decrement instead of adding a scaled version of the error).

If you change this to an integrating controller then all you have to do is get your gain low enough and you'll have stable control. I suspect that you don't have to worry much about disturbances, so you may be able to just stop as soon as you have something stable.

I wouldn't use an IIR filter in the acquisition: if you just sum up 100 ADC samples and use that for your current estimate then you'll more or less maximize the ratio of useful signal to delay, and you'll do less math than your IIR filter. This will let you increase your integrator gain for faster response.

--
www.wescottdesign.com
Reply to
Tim Wescott

That's basically what Tim was saying, with an increment of 1. It should work okay.

Make sure your ADC measurements are accurate. You could be experiencing some bad feedback from the 3.5A switching to the opamp power supply, for instance.

Some tests you could do:

- keep PWM output constant, and measure ADC noise. Also observe brightness.

- slowly ramp PWM from minimum to maximum, and measure current. Plot a graph between PWM duty cycle, and measured current. The plot should be a nice straight line. Any kind of irregularities could indicate a flaw in the circuit or the code.

Waiting 100 samples shouldn't be necessary. Perhaps if you modified the PWM every single sample, the flicker would be too fast to notice ?

Reply to
Arlet Ottens

s.

Just on the side, it's not about noticeable flickers as i's IR light - the intensity however should be stable at all times...

Reply to
cerr

o
y
o
c
e
m

How do you mean "get your gain low enough". And no, i don't need to worry about disturbances, when i'm there, i'm there until a new set point (intensity) gets set.

The IIR filter isn't all that intensive i thought, I have something like (MyVal * FILTERval + NewVal)/(FILTERval + 1), not sure if that really takes more operations than shifting 100 (99) elements in a loop to add the latest to the end/beginning and then add this all together and divide it by 100....

Reply to
cerr

The basic integrating controller is:

integrator_state += error * gain; output(integrator_state);

or

integrator_state += error; output(integrator_state * gain);

By gain I mean the variable called 'gain' in the above pseudo code.

Who said anything about storing past values? Every ADC cycle add the reading to an accumulator. Then at the end of 100 readings put the accumulator value into a variable, call your control loop (which uses that variable), and zero out the accumulator.

--
www.wescottdesign.com
Reply to
Tim Wescott

I'm lost here. You have a multi-channel PWM, and fractional control of the PWM value (to 8 bits or better ?) Thus you are in total control, and know what your ideal current is ?. Throw away the whole idea of Hysteresis bands, and simply converge on the target value. This is the simplest integral controller. and it has an implicit LPF and a slow step response.

IF LedCurrent > AlarmPoint THEN

IF LedCurrent < SetPoint THEN IF PwmValue < SafeCeiling THEN INC(PwmValue) ELSIF LedCurrent > SetPoint THEN DEC(PwmValue) // LEDCurrent =3D=3D Setpoint, holds the PWM value

You read the _average_ led current and update this at some low rate, maybe 5ms-50ms

Reply to
Jim Granville

Grrr, bumped the wrong key and there is no edit button... I was expanding it a little

PwmValue =3D SafeFloor // Some value that gives open loop non zero output IF LedCurrent > AlarmPoint THEN // Over current panic PwmValue =3D MinValue ELSIF LedCurrent > SetPoint THEN IF PwmValue > SafeFloor THEN DEC(PwmValue) ELSIF LedCurrent < SetPoint THEN IF PwmValue < SafeCeiling THEN INC(PwmValue) // LEDCurrent =3D=3D Setpoint, holds the PWM value

Your PWM LSB should be below the tolerable light variation. In operation, this will home on a value, and tick up or down from that, as needed.

If you have cheap, higher ripple power, (can be common in lighting) then you have two choices : a) Update fast enough to track the ripple or b) Slow the loop, so it averages the ripple. This can involve sampling the Control current at a known mains-phase

Measure your hardware to set the SafeFloor & SafeCeiling values & some designs use a separate path for the PanicCurrent sense.

You _can_ write more complex algebra and algorithms to converge faster, but in this sort of application, simplest is best... & lighting usually does not want fast steps.

Reply to
Jim Granville

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.