Timer with SystemClock question

hello!

I am trying to make a timer that keeps track of how long a signal is above a threshold. So I thought of using SystemClock:

h = SystemClock.seconds.asInt.value //start timer
b = (SystemClock.seconds).asInt-h //calculate elapsed time
v = b //store elapsed time
h = SystemClock.seconds.asInt.value //restart timer
b = (SystemClock.seconds).asInt-h //calculate elapsed time
x = v+b //total of elapsed times

Is there any good practice to make this kind of timer smarter?

Thank you! k

If you’re trying to measure a signal, it’s probably better to do it on the Server with the Timer UGen.

If you need to get this value back to the client, you might use the SendReply UGen on the Server and an OSCfunc in the client.

The helpfiles for Timer, SendReply, and OSCfunc would be a good place to start.

thanks. The ‘signal’ is on the client side, sorry, should have been clearer. It’s basically a float going up and down between 0.0 and 50.0. The threshold is around 10.0.

I’ll check your suggestions. Thanks! k

Ah, okay. My suggestions were specific to the Server. On the client side I’d suggest checking the value and managing the timer inside a Routine.

The specifics would depend on how the value itself is being generated.

1 Like

thanks!

I refined it as much as possible (see below). It works, but I feel perhaps the code should be simpler/smarter - could you/anyone have a look please?

cheers, k

(sorry, I don’t know how to paste the code below to make it look good here with blockcode or preformatted text)

(
a = 7; //signal
b = 10; //threshold
~switch = false;
~timer = [0,0,0];

r= Routine.run({inf.do{
if(a >= b,
// if higher;
{
“signal above threshold”.postln;
if(~switch == false,
{
~timer[0] = SystemClock.seconds.asInt.value; //start timer
~switch = true
},
{
//"~switch on (true)".postln;
}
)
},
// if lower
{
“signal under threshold”.postln;
if(~switch == true,
{
~timer[1] = (SystemClock.seconds).asInt-~timer[0]; //calculate elapsed time
“time spent above threshold”+~timer[1].postln;
~timer[2] = ~timer[2]+~timer[1];
“total time spent above threshold”+~timer[2].postln;
~switch = false;
},
{
//“switch off (false)”.postln;
//~switch.postln;
}
);
});

1.wait}});

)

a = 12 //signal
//wait a few seconds;
a = 9
//wait a few seconds;
a = 11
//wait a few seconds;
a = 9
//wait a few seconds;
a = 15
//wait a few seconds;
a = 7
~timer

To post formatted code inline, enclose the `code` in single backticks.

```
To post blocks of formatted code, use three backticks on a line by themselves at the start and end of the block.
```

Your code does work, and I don’t know exactly what you mean by “smarter”, but here are a few quick observations that might help you clean things up:

  • If ~switch is a boolean value there’s no need for if(~switch == true), just call ~switch.if.
  • There’s no need to call SystemClock.seconds.asInt.valueSystemClock.seconds.asInt is already an Integer.
  • You can just call a and b ~signal and ~threshold if you find yourself needing comments to remember that they refer to a signal and a threshold.
  • Similarly, it’s usually okay to use some type of IdentityDictionary instead of an Array to keep track of a group of related values. ~timer[\start] is easier for you and others to read than ~timer[0] etc.

As for your algorithm, because the resolution with which you can measure time is determined by how often the Routine yields, you don’t even need to use SystemClock, just an accumulator inside the Routine.

Here’s an example:

(
    // this Routine just creates a fluctuating "signal" to test
    // ~signal can be any Object that implements >=
    ~signal = 0;
    ~signalRoutine = Routine.new({
        var str = Pbrown.new(0, 20, 1, inf).asStream;

        inf.do({
            ~signal = str.next;
            ("Signal:" + ~signal).postln;
            0.1.yield
        })
    });

    // this Routine actually tests the value of ~signal over time
    ~testRoutine = Routine.new({
        var counter, threshold, resolution, switch, zSwitch;

        counter = 0;
        threshold = 10;
        resolution = 0.1;
        switch = false;
        zSwitch = false;

        inf.do({
            (~signal >= threshold).if {
                counter = counter + resolution;
                zSwitch.not.if { switch = true }
            } {
                zSwitch.if {
                    ("Above threshold for" + counter + "seconds").postln;
                    counter = 0;
                    switch = false
                }
            };

            zSwitch = switch;
            resolution.yield
        })
    })
)

(
    // start both Routines
    ~signalRoutine.play;
    ~testRoutine.play
)

(
    // stop both Routines
    ~signalRoutine.stop;
    ~testRoutine.stop
)

1 Like

this is very helpful, thank you for taking the time to reply!
I will experiment…

1 Like

thanks again!

I have used some ideas above and started tracking other behaviour in ~timer.

// after all there might not be any use for the switch, not sure yet;

(
~signal = 0;
~threshold = 10;
~timeThreshold = 10;
~signalRoutine = Routine.run({
	var str = Pbrown.new(0, 20, 1, inf).asStream;
	inf.do({
		~signal = str.next;
		("Signal:" + ~signal).postln;
		0.2.yield
	})
});

~timer = [0,0,0,0];
// 0: elapsed time since routine started
// 1: total time above ~threshold
// 2: current time spent above ~threshold
// 3: how often was ~timeThreshold met

r= Routine.run({inf.do{ |i|
	~timer[0] = ~timer[0]+1;
	(~signal >= ~threshold).if {
		~timer[1] = ~timer[1]+1;
		~timer[2] = ~timer[2]+1;

		(~timer[2]%~timeThreshold == 0).if {
			~timer[3] = ~timer[3]+1
		}
	} {
		~timer[2] = 0; //restart
	};
~timer.postln;
1.wait}});
)

you wrote: > If `~switch` is a boolean value there’s no need for `if(~switch == true)` , just call `~switch.if` .

is ~switch.if faster than if(~switch == true) or is it simply less code (characters)?

I will look into the IdentityDictionary as well.

cheers! k

Both! I wouldn’t worry too much about speed for its own sake at this scale, but it’s good practice to avoid the unnecessary comparison regardless. If you’re curious, you can benchmark the speed of a Function by calling bench on it. Results will vary depending on a lot of factors but this should give you a general idea of what is and isn’t good design.

For the results to be meaningful, you’ll want to benchmark a lot of iterations at once. For example:

{ 1000000.do({ true.if { nil }})}.bench (around 0.085 seconds for me)

{ 1000000.do({ (true == true).if { nil }})}.bench (around 0.25 seconds for me)

So yes, the difference is very significant!

1 Like

great! Many thanks for clarifying this. Similar results:

{ 1000000.do({ true.if { nil }})}.bench
time to run: 0.088045798 seconds.

{ 1000000.do({ (true == true).if { nil }})}.bench
time to run: 0.372762849 seconds.

1 Like