Rem0o / FanControl.Releases

This is the release repository for Fan Control, a highly customizable fan controlling software for Windows.
Other
13.13k stars 419 forks source link

Fan Range Control Compression/Mapping? #2583

Open ForbiddenEra opened 1 week ago

ForbiddenEra commented 1 week ago

Describe the bug

Intuitively, I assumed that some combination of "Start %", "Stop %", "Offset" and "Minimum %" would have accomplished what I was expecting.

Say you have a fan that doesn't start spinning until a request for "40%" (Which most often/generally translates to PWM %age directly, though some controllers [can be configured to/do] use voltage control which maps this as a %age of volts between 0v and 12v, thus 40% being about 4.8v - I'm just clarifying for the purposes of clear communication, whether the controller uses PWM, voltage or another control method is irrelevant to the issue) is sent to the controller.

Thus the control being set to any %age between 0%-39% results in 0 RPM and so 40% is the minimum/threshold where the fan spins at all - and, of course, this is what you would expect to enter in the "Start %" field, along with 39% being our choice for the "Stop %" field as here we're assuming our fan always stops when descending to/through 39% and starts when ascending to/through 40% (as of course some fans may not start until a higher percentage than is required to keep them spinning when descending control while they're already spinning - our example fan doesn't exhibit this behavior in the interest of brevity).

We'll also say our example fan has a minimum speed of about 750 RPM (at 40%) at a maximum speed of 1750 RPM (at 100%), though we needn't really consider RPM here either other than using it to establish the minimum start/stop threshold.

Now we add a simple "Flat Curve" control and assign our fan to our newly created control.

Without setting "Offest" or "Minimum %", we get this behavior:

-----------------------------------
| Control % | Output % |  Fan RPM |
+---------------------------------+
|        0% |       0% |    0 RPM |
|        5% |       0% |    0 RPM |
|       25% |       0% |    0 RPM |
|       39% |       0% |    0 RPM |
|       40% |      40% |  750 RPM |
|       50% |      50% | 1000 RPM |
|       75% |      75% | 1420 RPM |
|      100% |     100% | 1750 RPM |
-----------------------------------

And, that's about what I would expect with both "Offset" and "Minimum %" set to 0; if anything, the current behavior seems as if "Minimum %" is almost redundant as the fans output doesn't match the control until the control %age exceeds "Stop %" anyhow.

I intuitively figured that perhaps setting "Minimum %" to around the "Start %"/"Stop %", that it would result in sort of compressing/re-mapping the input to the output, meaning when our "Control %" is set to 50% the fan output is NOT directly 50% but 50% of it's available range/what it can do - thus when the control is set to 50% for a fan that only works between 40% and 100% then the actual output % for that fan would be 70% - half-way between 40% and 100%.

This would be based on the inputs on the fans themselves - and as I said, intuitively I figured that's how "Minimum %" would work, or perhaps somehow combined with "Offset %" (which simply seems to add the %age to the commanded %age, so a 10% offset on a fan with a 40% minimum results in 20% but is under the minimum so actually is 0% until the control is set to 30% where 30% commanded+10% offest=40%, so setting an offset of 40% does make our fan start as soon as the control is above 0% but now the fan is maxed at 100% when the control is only set to 60%)

When working as I expected, our table should look like this:

-----------------------------------
| Control % | Output % |  Fan RPM |
+---------------------------------+
|        0% |       0% |    0 RPM |
|        1% |    40.6% |  750 RPM |
|        5% |      43% |  850 RPM |
|       10% |      46% |  910 RPM |
|       25% |      55% | 1075 RPM |
|       50% |      70% | 1337 RPM |
|       75% |      85% | 1575 RPM |
|      100% |     100% | 1750 RPM |
-----------------------------------

Basically just calculate the range (100 - "Minimum %", which equals 60 in this case) and apply the control %age to that range adding the minimum.

So for a 50% control ::

100 (max) - 40 (min) = 60 (range)
60 (range) * 0.5 (50%) = 30 (adj)
40 (min) + 30 (adj) = 70% (final commanded %age)
---
/* JS-ish Pseudocode
   minPct = "Minimum %" field, perhaps (clamped between 0-100)
   reqPct = Control's Requested %age (clamped between 0-100)
   return value = Actual fan %age (clamped between 0-100)
*/

const rangeMap = (minPct, reqPct) => Math.min(Math.max( ( Math.min(Math.max(minPct, 0), 100) + (100 - Math.min(Math.max(minPct, 0), 100)) * (Math.min(Math.max(reqPct, 0), 100)/100) ), 0), 100);
Rem0o commented 1 week ago

Hi, I thought about it, but I feel it would bring more confusion than benefit in the sea of already available settings. Having a consistent % "definition" throughout the software has a benefit.

At you level, I would simply go straight to RPM mode for all my fans using fan calibration, so that % doesn't matter anymore in your fan curves, as you simply input RPM values.

ForbiddenEra commented 1 week ago

Thanks for the quick reply. Read on for quoted responses.

Hi, I thought about it, but I feel it would bring more confusion than benefit in the sea of already available settings.

I can understand that perspective; however, as I mentioned - this is how I intuitively thought the settings might work. Beyond that, it's not actually completely clear why you would have all 4 inputs ("Start %", "Stop %", "Offset", "Minimum %") as how they seem to behave now (to me at least when I was testing) is a bit confusing and redundant. When a control is set to say, 20% and the fans "Start %" is 40%, the output on the fan is 0%, this seems to be the same as if I set "Minimum %" to 40% instead. To be fair, I'm only going off memory from testing last night but I spent a good 20 min modifying the numbers to see how the output % correlated to the input % depending on the settings of each.

I should also mention that this is from the perspective of a user who's far from inexperienced - I've been coding, working with and building computers for over 30 years at this point - along with having a strong EE and industrial control systems background.

Understanding your perspective - eg. Avoiding confusion and keeping it simple - I would hazard a guess that your goal would be that anyone reasonably aware of how PC fan control works should be able to read and immediately intuitively understand what all the values do and how they affect things. This is indeed true for most of the values but how they affect each other, especially the "Minimum %" value isn't entirely clear - I actually thought setting "Minimum %" was going to achieve the behavior I've described and was expecting.

Having a consistent % "definition" throughout the software has a benefit.

As a developer, I agree consistency is important. Perhaps this is something that could be toggled on/off per fan or control.

The biggest issue with consistency, in my opinion - is when attempting to control multiple different fans from a single control/curve that have different values. In my case, most of these fans are my case fans attached to my motherboard headers - some fans start at 10% while others start at 40% - this makes controlling all of them with a single control/curve rather difficult, creates scenarios where some fans are running and others aren't and impossible without losing resolution on any fans with a greater range than the fan with the lowest range in the group.

If there was an option to limit the range, you could have any assortment of fans in a group and know confidently that setting 50% on the control (or having your curve ask for 50%) would mean that all fans in the group are running at 50% of their capable RPM - exactly half-way between their minimum RPM and maximum RPM and you would know setting 10% wouldn't stall any fans and again, all fans would be 10% above their minimum RPM toward their maximum.

At you level, I would simply go straight to RPM mode for all my fans using fan calibration, so that % doesn't matter anymore in your fan curves, as you simply input RPM values.

I appreciate this suggestion and I did explore this, however the issue noted in my previous paragraph remains - as mentioned, I have several different fans for my case on my motherboard - just like setting 20% with two fans that start at 10% and 40% would result in only one of them running, setting 750 RPM with two fans whose minimum RPM is 500 RPM, 1000 RPM would also result in only one spinning.

I mostly use manual control (flat curve) and have controls for the fans grouped by purpose, eg. CPU has 2, CaseFront has 2, etc.

Fortunately in my environment the fans are quiet enough at a %age that exceeds the Start % of all in the group, but I would definitely have issues if the environment were quieter, mainly the stalling issues with vastly different Start %s; perhaps this is partly what your "Minimum %" tries to solve? I'd have to evaluate the behavior again to be 100% sure instead of relying on memory from the other night but as I mentioned I didn't get a clear sense of it's purpose. I know you could set an "Offset %" to around about the "Start %" and then that fan would start spinning as expected - but then the offset clips the upper range of the fan, again losing control resolution (which also means potentially bigger steps between speed changes, even if Step Up/Step Down were set to like 0.1%) - if your "Start %" and "Offset %" is 40% then when you command 60% the fan will already at 100% - which really seems to make grouping curve control unsuitable for disparate fans as a fan without an offset would be at 60% where the fan with the offset would be at 100% - a potentially major difference in RPM and, well mainly - dB - after all, if sound wasn't part of the problem we'd just have jet-engine server fans in everything.

Regardless, thanks for developing the application and contributing to the community; again I'm a dev myself and always appreciate free or open SW and the weight of the decision for a dev to go that route.

I truly hope you'll consider working this in. Again, I'm a developer so I 100% totally understand wanting to achieve the best UX and most approachable, easiest and intuitive settings and UI while also keeping things consistent to avoid confusion but I'm sure there's a way to avoid the resolution loss and/or low and high level clipping or other mentioned issues when grouping multiple fans that don't quite match up.

PS: I actually just tested again to remind my self, I guess it seems like setting "Minimum %" doesn't quite act the same as "Start %" but actually keeps the fan from going under that % even if a lower value is commanded; I suppose this makes sense, though it prevents stopping the fan which makes the "Start %" and "Stop %" settings redundant/confusing if "Minimum %" is set, although it does potentially solve the issue of some fans not spinning but the range is still clipped with reduced resolution.

Cheers!