Given messages with a value in the payload this limits the maximum rate of change of the output, generating intermediate messages so that the output slews at the specified rate between values passed in.
-
-
Save colinl/13c793620b6ec830ef610c13fd845bcb to your computer and use it in GitHub Desktop.
Slew rate limit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{"id":"95daacd1.0e09f8","type":"debug","z":"514a90a5.c7bae8","name":"","active":true,"console":"false","complete":"false","x":570,"y":530,"wires":[]},{"id":"c136d3fd.21da78","type":"inject","z":"514a90a5.c7bae8","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":99,"y":492,"wires":[["fc58524d.34f02"]]},{"id":"fc58524d.34f02","type":"function","z":"514a90a5.c7bae8","name":"Slew rate limit 1 unit/second","func":"// Limits the slew rate incoming payload values\n// optionally sending intermediate values at specified rate\nlet maxRate = 1; // max slew rate units/second\nlet sendIntermediates = true; // whether to send intermediate values\nlet period = 100; // period in millisecs to send new values (if sendIntermediates)\nlet jumpThreshold = 2; // if the step asked for is more that this then goes immediately to that value\n\nvar newValue = Number(msg.payload);\nvar timer = context.get('timer') || 0;\n// check the value is a number\nif (!isNaN(newValue) && isFinite(newValue)) {\n var target = msg.payload;\n context.set('target', target);\n // set last value to new one if first time through\n var lastValue = context.get('lastValue');\n if (typeof lastValue == \"undefined\" || lastValue === null) {\n lastValue = newValue;\n context.set('lastValue', newValue);\n }\n // calc new value\n msg.payload = calcOutput();\n // stop the timer\n if (timer) {\n clearTimeout(timer);\n context.set('timer', null);\n }\n // restart it if required to send intermediate values\n if (sendIntermediates) {\n timer = setInterval(function(){\n // the timer has run down calculate next value and send it\n var newValue = calcOutput();\n if (newValue != context.get('lastValueSent')) {\n context.set('lastValueSent', newValue);\n node.send({payload: newValue});\n }\n },period);\n context.set('timer', timer);\n }\n context.set('lastValueSent', msg.payload);\n} else {\n // payload is not a number so ignore it\n // also stop the timer as we don't know what to send any more\n if (timer) {\n clearTimeout(timer);\n context.set('timer', null);\n }\n msg = null;\n}\nreturn msg;\n\n// determines the required output value\nfunction calcOutput() {\n var lastValue = context.get('lastValue');\n var target = context.get('target');\n // set to current value if first time through or step > threshold\n if (typeof lastValue == \"undefined\" || lastValue === null) lastValue = target;\n var now = new Date();\n var lastTime = context.get('lastTime') || now;\n // limit value to last value +- rate * time\n var maxDelta = (now.getTime() - lastTime.getTime()) * maxRate/1000;\n if (Math.abs(target - lastValue) > jumpThreshold) {\n // step > threshold so go there imediately\n newValue = target;\n } else if (target > lastValue) {\n newValue = Math.min( lastValue + maxDelta, target);\n } else {\n newValue = Math.max( lastValue - maxDelta, target);\n }\n context.set('lastValue', newValue);\n context.set('lastTime', now); \n return newValue;\n}","outputs":1,"noerr":0,"x":351,"y":530,"wires":[["95daacd1.0e09f8"]]},{"id":"1501600b.8cd8d","type":"inject","z":"514a90a5.c7bae8","name":"","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":99,"y":569,"wires":[["fc58524d.34f02"]]}] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment