[SOLVED] Measuring average of a numeric value
-
-
that's the one. much more simple than i expected. (i haven't really explored the Float Counter yet, but i guessed it would be useful in this situation) :)
-
Yes but there is no easy solution inside Isadora for very long time or for exact time of average… If you need a very accurate solution to make an average with the last 3200 sample (as in the Lauri answer, 1 hour of second sample), it would be necessary to have the possibility to store a 3200 (or more) items list. For me it is doable easily in Max/Msp (item list) or TD (Python array) but I dont know an easy way to do it in Isadora. Javascript (in my knowledge) cannot because the lack of global variable, data array is limited in number of items and you cannot move all the sample as you can do it with array in Python or list in Max. I think it would be also easy in Processing with OSC in/out but I have to see the weather outside !
Another chalenge for json specialist.
-
-
Thank you ALL for your help! Yes, of course, that’s the solution, should have thought through it myself.
Anyway, here’s an image of my simple version, in this case, for measuring performance cycles. Seems to work well.
Thousand thanks again!
Lauri
-
it's easily done with javascript..
I will write some code later today that will allow you to very flexibly setup the storing of values and calculation of there average.
-
Ok, I believe this Javascript code will do what you are looking for. https://gist.github.com/rwebbe...
var dataSet = []; function debug(printString){ if (DebugMode){ print(printString + "\n"); } } function main(){ // DO setup here: ONCE ONLY ************************************************ DebugMode = true; //example usage: debug("string" + var + "\n"); MaxValues = arguments[0]; // no Var makes global debug("Start DataSet Length = " + dataSet.length + "\n\n");
// main function for LOOP **************************************************
main = function(){
if (dataSet.length >= MaxValues){
dataSet.splice(0, 1); // remove first value since buffer is at Max
}
dataSet.push(arguments[1]); // add last received value to end of array, increasing total.
debug("DataSet Length = " + dataSet.length + "\n");
//debug("DataSet = " + dataSet + "\n"); // gets big... but useful if you want to see all array values in smaller sets.
// reduce array using a function at add all values contained together.
var Sum = dataSet.reduce(function(accumulator, currentValue, currentIndex, array) {
return accumulator + currentValue;
});
debug("DataSet Sum = " + Sum + "\n");
var Average = Sum / dataSet.length;
debug("DataSet Avg = " + Average + "\n\n");
out = [Average] // set output array
return out; // return out array
};// RUN ONCE FOR INIT ONLY
var out = []; // declare out
return out; // return from INIT state
}This will create an array that expands with every new value that is received and output the Average of all the received values.
It takes 2 inputs. The first is the Max number of values you want to hold for creating a sum (I tested with 3600).
If you receive 1 value per second, setting this to 60 would make it so the code always gives you the average for the last minute (older values are dropped, and if there are less than 60 values... say its been running for 5 seconds... it will use the 5 values).
You can of course set this number very high so the buffer/array covers a longer period of time. (this will use more system memory, but it should be very minimal).
Currently, I have setDebugMode = true;
This will output some useful information to the 'Monitor' Window if you open it.
Once you have viewed this information, and are happy with the functioning of the code, change DebugMode to = false -
@jhoepffner
There is no lack of Globals in Javascript.
Declaring a variable without using the Var keyword makes it a global..
Using the Var keyword binds it to the scope of the current function.
In the case of the code I wrote, the array [] is set using the Var keyword, but its defined outside the Main functions scope, so it behaves as a global. -
Thanks Ryan for the JS lesson and for the brillant demo.
-
@DusX Thousand thanks for your help!!! This is a great solution!
However, I noticed one flaw with it: if the value does not change, then it is not registered as a new value, it registers a value when it differs from the previous one.
For example, if I measure the average of performance fps (see the attached image), the output value of fps tends to stay at the value set in the preferences. And in this case the JS actor registers only values deviating from that (and the set value, when it reaches that again). So, lets say the fps cannot keep the set value all the time, but instead goes (time to time) below more than above, then the received value is not really an average.
Another thing is that the JS actor cannot be reset, unless you exit the stage and return into it. But this is a minor thing, and I can manage without that feature.
I don't know Java, so I cannot really propose a solution. My apologies for that.
-
@lauri
You are absolutely correct, submitting the same value doesn't work.
Luckily there is a very easy fix.
Increase the number of Inputs from 2 to 3. Mutate the 3rd input to a trigger (connect a trigger to it.. maybe from a trigger delay)
And then connect your data value source to the 3rd input as well.
This will cause the JS actor to see a new trigger each time a value is entered, even when the value doesn't change. Running the code as expected.And a fast fix to add a reset, enter this code:
if (arguments[3]){
dataSet = [];
return;
}after
// main function for LOOP **************************************************
main = function(){So that it looks like:
// main function for LOOP **************************************************
main = function(){
if (arguments[3]){
dataSet = [];
return;
}
if (dataSet.length >= MaxValues){Then add another (4th) input, and mutate it to a trigger.
That trigger (input 4) will reset the array to empty. -
Thousand thanks! Works perfectly!
Mutating the 3rd input to a trigger was a bit difficult – in what order to connect the input – but in the end, yes, works flawlessly.
Thanks!!!
-
I wrote the attached user actor a few months ago to provide an ongoing average FPS calculated from the most recent 100 samples, but it can be used for any stream of numbers. You are welcome to use it.
Don