how to write PWM output variable dependant?

How best to approach writing a variable dependant PWM output?

Issue: the PWM output need to vary from 0 to 254 as a function of a temperature measurement.

Up to for example 70C PWM output needs to be 0. Starting at 70C the PWM kicks in at for example analogWrite(x,50).

Linear increase of analogWrite(x,y) required for temperatures between 70C and 120C, from value 50 to value 254. So: straight linear function.

Temperatures higher than 120C, keep analogWrite(x,254).

Optionally, if possible: on a downward temperature trend the analogWrite may only revert to value 0 when the temperature drops back to its initial value minus 10C (in this example: 60C).

It sounds like you need to use the map() function to take the input range 70 to 120 and map it to an output range of 50 to 254.

edit: double identical post, sorry

UKHeliBob: It sounds like you need to use the map() function to take the input range 70 to 120 and map it to an output range of 50 to 254.

ok, thank you. I will get some research done in that direction.

However in the map I can set a linear function but no hysteresis. Getting the pwm output to vary between 50 and 254 as a function of temperatures 70C to 120C is fine; but:

..how do I go about during a downward trend of temperature where (while kicking in at 70C to value 50) I need to "kick out" (from value 50 to value 0) when the temperature goes below 70C - 10C = 60C (the hysteresis)?

Maybe a second map to be used when pwm output is not 0?

Simply use a different map when you detect it going down...

But how will you match the two curves? For example (please fill in the behavior, it's a chronological sequence of events) 1) starting at 60 2) goes up to 90 3) goes up to 100 4) goes down to 80 5) goes up to 110 6) goes down to 70 7) goes down to 60

septillion:
Simply use a different map when you detect it going down…

But how will you match the two curves?
For example (please fill in the behavior, it’s a chronological sequence of events)

  1. starting at 60
  2. goes up to 90
  3. goes up to 100
  4. goes down to 80
  5. goes up to 110
  6. goes down to 70
  7. goes down to 60

In your example the fan starts at 70, keeps running 2 (fan kicks in at 70)…3…4…5…6 (70)… …stops at 60.

Purpose of the hysteresis is to get the fan kick in at a higher temp then when it is kicked out.

Yes, I know it keeps running, but at what speed? Just make it start at 70 and stop at 60 is easy, no PWM involved.

So try again :wink:

Is something like this what you want?;

  if(temp <= 70)
  output = map(output,temp - 60, temp - 70, 0,50);
  else
  output = map(output,temp - 70, temp - 120,50, 254);

Does this:
60 0
62 10
64 20
66 30
68 40
70 50
75 70
85 111
95 152
105 192
115 233
119 249
120 254

Uhm, huh... You're mapping output with output as input? ??? That's going to give you interesting stuff depending on what value output you start...

if(temp <= 70)
  output = map(output,temp - 60, temp - 70, 0,50);
  else
  output = map(output,temp - 70, temp - 120,50, 254);
  output = constrain(output,0,254);

Show me the right way? :frowning:

septillion:
Yes, I know it keeps running, but at what speed? Just make it start at 70 and stop at 60 is easy, no PWM involved.

So try again :wink:

aahhhh (great light turning on :grinning: )

When it kicks in at 70, speed is for example 50, goes up linear to 254 in function of temp between (say) 70 and (say) 120. When it goes down, temp needs to go below 70-hysteresis (say 10) = 60 for the fan to go from 50 to 0.

Now here it comes: as soon as the fan kicks in, say start at temp=70C, speed is 50 (map number 1).
But I make a condition: as soon as the fan runs, i change the map: map number 2. New map, speed from 70-10 = 60C to (say) 120C.

And when fan kicks in at 70, this will be a new map, and fan goes straight not to speed 50 but to speed 50+(a bit more).

Now here comes the kicker: no map needed. I used some high school maths to find the linear equation for this function. As soon as temp=70C I use (" * " equals multiplication) y = 3.4 * x - 154 where y = PWM output and x = temperature. But with the condition that this function only kicks in when temp rises >70C and that the PWM becomes 0 as soon as temp < 60C

And when temp > 120C PWM remains 254.

For those in need of math update: http://www.coolmath.com/algebra/08-lines/12-finding-equation-two-points-01

Edit: formula clarification: “PWM output” = 3.4 times “temperature” minus 154

Thanks for that but I need a memory transplant. :grin:

Now to write the whole function fully variable dependant:

  1. the slope of the function = (max pwm - min pwm) / (max temp - min temp)

...= (254 - 50) / (120 - 60)

  1. y - "minimum speed" = slope * (x - "minimum temp")

... y - 50 = 3.4 * (x - 60)

.. y = 3.4 * x - 154

Now I can write this whole calculation in C and make the formule dependent on min temp, max temp, min speed and max speed

756E6C: Thanks for that but I need a memory transplant. :grin:

I had mine :grin:

To write this function in C:

to recap:

slope = (254 - 50) / (120 - 60)
y = 3.4 * x - (3.4 * 60) - 50 = 3.4 * x - 154

if:

pwm output = y
actual temp = x

then:

pwm output = (max pwm - min pwm) / (max temp - min temp) x (actual temp) - (max pwm - min pwm) / (max temp - min temp) x (min temp) - min speed

Now just fill in these variables:
min pwm
max pwm
min temp
max temp

…and use the condition to kick this formula in that “actual temp” > 70C

As soon as this conditions is true, the fan will not yet stop running when “actual temp” is < 60: there a second condition is needed:

when actual temp < 60 jump out of the loop and stop the fan.

Condition sequence for fan control based on temperature measurement and using hysteresis to exit:

if (actual temp > min temp or flag1 is set) start loop

  1. set flag1
  2. perform formula calcualtion, start pwm
  3. if temp < (min temp minus hysteresis) clear flag1

Clearing of flag1 will prevent loop execution next time

Correct?

brice3010:
When it kicks in at 70, speed is for example 50, goes up linear to 254 in function of temp between (say) 70 and (say) 120. When it goes down, temp needs to go below 70-hysteresis (say 10) = 60 for the fan to go from 50 to 0.

No that’s what I wanted to see :smiley: So it’s fully mapped between 70°-120° to 50-254 (what’s wrong with 255??) and once then fan is on it will remain at 50 between 60° and 70°.

brice3010:
But I make a condition: as soon as the fan runs, i change the map: map number 2. New map, speed from 70-10 = 60C to (say) 120C.

That will not work (nice) because that will simply cause a weird jump. If you map 50 to 60° then 70° no longer maps to 50 but to 84…

brice3010:
And when fan kicks in at 70, this will be a new map, and fan goes straight not to speed 50 but to speed 50+(a bit more).

But it seems like you want this. But you don’t need to maps for that. Simply start mapping when temperatur goes above 70 and stop when it’s below 60.

brice3010:
Now here comes the kicker: no map needed. I used some high school maths to find the linear equation for this function.

map() is nothing more then the math already done for you ::slight_smile: And it’s a hell of a lot quicker for the Arduino because that doesn’t unnecessary use floats. (Note the 3.4 in your formula :wink: )

To do what you want:

bool fanOn = false;
if(temp > 120){
  temp = 120; //then it's already at max speed...
}
if(temp > 70){
  fanOn = true;
}
else if(temp < 60){
  fanOn = false;
}

if(fanOn){
  pwm = map(temp, 60, 120, 50, 254);
}

Done!

Although I think I would like the stay at 50 aproach

bool fanOn = false;
if(temp > 120){
  temp = 120; //then it's already at max speed...
}
if(temp > 70){
  fanOn = true;
}
else if(temp < 60){
  fanOn = false;
}

if(fanOn){
  if(temp > 70){
    pwm = map(temp, 70, 120, 50, 254);
  }
  else{
    pwm = 50;
  }
}

And of course, even better with const variables in it :slight_smile:

septillion:
No that’s what I wanted to see :smiley: So it’s fully mapped between 70°-120° to 50-254 (what’s wrong with 255??) and once then fan is on it will remain at 50 between 60° and 70°.

Correct: 255

…“it will remain at 50 between 60° and 70°”… I was rather thinking of linear increase between 60° and 120°C. But constant 50 between 60° and 70° is also ok; I have no preference.

septillion:
That will not work (nice) because that will simply cause a weird jump. If you map 50 to 60° then 70° no longer maps to 50 but to 84…

Indeed not elegant, but I still think it will work: just use another map on condition of having started: map1 right at first pass of loop, second and subsequent passes: map2

septillion:
But it seems like you want this. But you don’t need to maps for that. Simply start mapping when temperatur goes above 70 and stop when it’s below 60.

How can you make map work with different start and stop minima?

septillion:
map() is nothing more then the math already done for you ::slight_smile: And it’s a hell of a lot quicker for the Arduino because that doesn’t unnecessary use floats. (Note the 3.4 in your formula :wink: )

Are you sure of that? The compiler needs to translate this function in assembler so finally maybe even longer execution time then when breaking it down in C and have the compiler an easier task to do when translating?

septillion:
To do what you want:

bool fanOn = false;

if(temp > 120){
  temp = 120; //then it’s already at max speed…
}
if(temp > 70){
  fanOn = true;
}
else if(temp < 60){
  fanOn = false;
}

if(fanOn){
  pwm = map(temp, 60, 120, 50, 254);
}



Done!

Nice.

septillion:
Although I think I would like the stay at 50 aproach

bool fanOn = false;

if(temp > 120){
  temp = 120; //then it’s already at max speed…
}
if(temp > 70){
  fanOn = true;
}
else if(temp < 60){
  fanOn = false;
}

if(fanOn){
  if(temp > 70){
    pwm = map(temp, 70, 120, 50, 254);
  }
  else{
    pwm = 50;
  }
}



And of course, even better with const variables in it :)

Elegant solution!

Now just before your post here I made another proposal: will you please have a look at it?
Thks!!

How I know? Because I read the map reference ;) Map is simply defined as

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

And yes, you could speed it up a bit by pre-calculating the subtractions but it's all int math so pretty fast so not worth the fuss. It's a helllll lot faster and a hell lot smaller then you're implementation using floats ;)

And to come back to your post, you don't need two ranges/maps. It's just 1 map but with state base start and stop conditions around it ;)

And what you called flag1 (which is of course a very stupid name ;) ) I called fanOn :) Rest it's pretty much what I put into code :)

Thanks a lot!! I will print this thread and stack it in my Great Very Usefull Programming Information Book; I appreciate your input very much!