# Simulations - alternative ways to distribute ticks

**URL:** <https://discourse.nodered.org/t/simulations-alternative-ways-to-distribute-ticks/69304>\
**Category:** General\
**Created:** [20 October 2022 07:14 UTC](https://discourse.nodered.org/t/simulations-alternative-ways-to-distribute-ticks/69304 "2022-10-20T07:14:43Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![stefaanv](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/stefaanv/32/69387_2.png) [@stefaanv](https://discourse.nodered.org/u/stefaanv)\
**Post date:** [20 October 2022 07:14 UTC](https://discourse.nodered.org/t/simulations-alternative-ways-to-distribute-ticks/69304/1 "2022-10-20T07:14:43Z")

</div>

I'm using node-red 3 to simulate processes.  
I find myself distributing a `setup` and a `tick` signal to almost all nodes. That makes the flows visually cluttered.  
Are there alternatives to handle global signals that many nodes use ?  
Having events available (+ the possibility to handle events in function) nodes would be really nice. I've read the comments that this would break the `wiring paradigm` of node-red, but in this case that would actually be a relief. The wires would still be used for 'normal' information-carrying signals.  
I've been searching the docs for event-handling but without success so far.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [20 October 2022 14:01 UTC](https://discourse.nodered.org/t/simulations-alternative-ways-to-distribute-ticks/69304/2 "2022-10-20T14:01:06Z")

</div>

When I have done this in the past I have used the message itself to be the tick. So every second (or whatever the simulation period) a message is injected with the latest process values and it flows through the simulation and produces a new value at the output.  
Or even just let the messages flow round, with a delay in the loop to simulate the passing of time. For instance, here is a subflow that simulates a process delay and a couple of RC constants. The technique may not be appropriate for more complex processes though.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/8/0/802c8523324eff617279fbb69372ecf797fdda9b.png)

```auto
[{"id":"1156e9cbb379d09c","type":"subflow","name":"Process Simulation (2)","info":"","in":[{"x":37,"y":103,"wires":[{"id":"5f7bb53fd5e8503c"}]}],"out":[{"x":728.5,"y":294,"wires":[{"id":"f423d62b0901b0c3","port":0}]}]},{"id":"a78eda7549e10a97","type":"function","z":"1156e9cbb379d09c","name":"30 sec RC + 20","func":"// Applies a simple RC low pass filter to incoming payload values\nvar tc = 30*1000; // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n // first time through\n newValue = currentValue;\n} else {\n var dt = now - lastTime;\n var newValue;\n \n if (dt > 0) {\n var dtotc = dt / tc;\n newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n } else {\n // no time has elapsed leave output the same as last time\n newValue = lastValue;\n }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg.payload = newValue + 20;\nreturn msg;","outputs":1,"noerr":0,"x":626.5,"y":207,"wires":[["f423d62b0901b0c3"]]},{"id":"87d30eb526f1da83","type":"inject","z":"1156e9cbb379d09c","name":"Inject -0.2 at start","repeat":"","crontab":"","once":true,"topic":"","payload":"-0.2","payloadType":"num","x":134.5,"y":30,"wires":[["5f7bb53fd5e8503c"]]},{"id":"4d29fb5c58ae7a0d","type":"function","z":"1156e9cbb379d09c","name":"10 sec RC","func":"// Applies a simple RC low pass filter to incoming payload values\nvar tc = 10*1000; // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n // first time through\n newValue = currentValue;\n} else {\n var dt = now - lastTime;\n var newValue;\n \n if (dt > 0) {\n var dtotc = dt / tc;\n newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n } else {\n // no time has elapsed leave output the same as last time\n newValue = lastValue;\n }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg.payload = newValue;\nreturn msg;","outputs":1,"noerr":0,"x":451,"y":207,"wires":[["a78eda7549e10a97"]]},{"id":"5f7bb53fd5e8503c","type":"delay","z":"1156e9cbb379d09c","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":268,"y":104,"wires":[["1d73e8daa47ff9a2"]]},{"id":"e3afd7e9a2a0baa0","type":"function","z":"1156e9cbb379d09c","name":"2 msg transport delay","func":"// stores messages in a fifo until the specified number have been received, \n// then releases them as new messages are received.\n// during the filling phase the earliest message is passed on each time \n// a message is received, but it is also left in the fifo\nvar fifoMaxLength = 2;\nvar fifo = context.get('fifo') || [];\n// push the new message onto the top of the array, messages are shifted down and\n// drop off the front\nvar length = fifo.push(msg); // returns new length\nif (length > fifoMaxLength) {\n newMsg = fifo.shift();\n} else {\n // not full yet, make a copy of the msg and pass it on\n var newMsg = JSON.parse(JSON.stringify(fifo[0]));\n}\ncontext.set('fifo', fifo);\nreturn newMsg;","outputs":1,"noerr":0,"x":258,"y":208,"wires":[["4d29fb5c58ae7a0d"]]},{"id":"f423d62b0901b0c3","type":"function","z":"1156e9cbb379d09c","name":"Clear all except payload","func":"msg2 = {payload: msg.payload};\nreturn msg2;","outputs":1,"noerr":0,"x":545,"y":293,"wires":[[]]},{"id":"1d73e8daa47ff9a2","type":"range","z":"1156e9cbb379d09c","minin":"0","maxin":"1","minout":"0","maxout":"100","action":"scale","round":false,"name":"","x":87,"y":208,"wires":[["e3afd7e9a2a0baa0"]]}]

```

---

<div class="post-metadata">

**Author:** ![stefaanv](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/stefaanv/32/69387_2.png) [@stefaanv](https://discourse.nodered.org/u/stefaanv)\
**Post date:** [21 October 2022 13:31 UTC](https://discourse.nodered.org/t/simulations-alternative-ways-to-distribute-ticks/69304/3 "2022-10-21T13:31:39Z")

</div>

@Colin  
thank for the tip, I had actually tried that but it gives me two problems

- I still need to disperse the `tick` and `reset` `housekeeping signals` to all the first nodes in every chain which clutters the flows.
- In my energy management simulation, when linking two or more (let's say `n`) `consumer` nodes - which can have different power ratings - to a `storage` node, the energy consumption messages do arrive at `n` times the usual speed, but the `tick` signal itself also arrives at `n` times the normal rate so I lose the capability to discern how much total consumption is linked to the storage.

If you think about it, the global context is obviously a way to distribute information (variables) outside of the node-and-wires paradigm. So it is not that far fetched to have the same option for `events`

I found this work-around but it is not very pretty  
on `tick startup` function node with thisstartup code

```nohighlight
setInterval(() => {
    const timerArray = global.get('timer')
    timerArray.forEach(callback);
}, 1000)

```

This startup code in the regular function nodes (producers, consumers, storage, power meters, ...)

```nohighlight
const myCallback = () => { node.send({ topic: 'consumer', payload: 200 })}
global.set('timer', (global.get('timer') ?? []).push(myCallback))

```

---

<div class="post-metadata">

**Author:** ![EmilWesselink](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/emilwesselink/32/65829_2.png) [@EmilWesselink](https://discourse.nodered.org/u/EmilWesselink)\
**Post date:** [22 October 2022 10:02 UTC](https://discourse.nodered.org/t/simulations-alternative-ways-to-distribute-ticks/69304/4 "2022-10-22T10:02:16Z")

</div>

I don't have a clear idea of your problem but especially because it is an event you can use the link nodes to unclutter.

Your ticks and init node can go to a link in node. And you can distribute this with a link out node. 1- n is possible here.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [21 December 2022 10:02 UTC](https://discourse.nodered.org/t/simulations-alternative-ways-to-distribute-ticks/69304/5 "2022-12-21T10:02:25Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
