Skip to content

Instantly share code, notes, and snippets.

@colinl

colinl/README.md Secret

Last active July 19, 2019 12:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save colinl/13c793620b6ec830ef610c13fd845bcb to your computer and use it in GitHub Desktop.
Save colinl/13c793620b6ec830ef610c13fd845bcb to your computer and use it in GitHub Desktop.
Slew rate limit

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.

[{"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