Calculating rate of change or pulse rate, or evaluating previous n samples
I would like to calculate a rate of flow. The counter in my instrument increments each time a pulse is received.
I wrote a meta point script that updates whenever there is a "context update:"
return gallons.value - gallons.ago(MINUTE, 1) // gallons per minute, but lots of quantization noise and fixed time window return 1/((gallons.value.time - gallons.ago(SAMPLE, 1).time)/(1000*60)) // gallons per minute based on pulse interval rather than number of pulses, but SAMPLE is undefined
The problem with ago() is that the flow rate is low, so the returned value has a lot of quantization noise, and will falsely report 0 if no change occurred in the last minute. If I increase the time window, then the returned value changes too slowly. It would be better to evaluate when the previous change occurred, and divide by the elapsed time. StartsAndRuntimeList object does not work for analog points; only multi-state or binary point types. I could create a binary change event, then use the StartsAndRuntimeList object to get the time stamps. Where can I find more examples of StartsAndRuntimeList uses?
There are other applications for which I need values and time stamps for analog values record times based on sample number rather than a fixed time window, such as calculating derivatives, integrals, decimation, etc. However, all the analog functions seem to refer to a defined time window rather than x samples ago, and are not supported by StartsAndRuntimeList:
return pump.past(MINUTE, 2).get(true).proportion; // legal, but fixed time window returns 2 minute average duty cycle rather than the last cycle's exact duty cycle. return pump.past(SAMPLE, 2).get(true).proportion; // variable time window adjusts size to reflect only most recent events, but "SAMPLE" is illegal // Below is for derivatives (dV/dt) or integrals (V*dt) return volts.ago(SAMPLE, 1) - volts.ago(SAMPLE, 2) // delta V of the previous two samples (illegal) return volts.ago(SAMPLE, 1).time - volts.ago(SAMPLE, 2).time // delta t of the previous two samples (illegal)
How can I obtain the value of an analog point that occurred n samples ago?
How can I determine the time that analog sample was recorded?
... will falsely report 0 if no change occurred in the last minute
Use the "count" attribute of the analog stats to determine if there where any values in the time range for the calculation.
Are you using M2M, or MA (nee M2M2)? We could a "last(n)" function or something. Such changes are not being done in M2M anymore.
Thanks, Matthew. The count function would work, but to convert to a rate whenever the pulse is received, I would have to implement a function to perform a binary search that recursively calls count at each context update. Consequently, a last(n) function would be great. last(0).value would be the current point, last(1).value would be the previous point, etc. Then I could also use last(1).time - last(1).time to calculate the derivative or the integral, as I cannot assume that delta-t will be constant.
I purchased MA, but have not installed it yet due to time constraints and because I don't cherish losing my M2M historical data. I have too many datapoints to export/import them individually (over 300 now). My Derby DB is now 32GB. Clearly I need to convert to mysql and decrease the storage rate. At 28GB it took 14 minutes to restart. Curiously, "Hello World" (localhost:8080/sample) was also unavailable during that time.
I've implemented two new functions:
"last(limit)" will return a list of the latest point value/time objects up to the limit. The list will never be null, but could have a size from 0 to n depending on how many historical values there actually are. Values are sorted from most newest to oldest so that list.get(0) will return the most recent value. The list is a java.util.List object, and so has all of the methods available in that interface, including get(index) and size(). The get(index) method will throw an ArrayIndexOutOfBoundsException if you ask for an index that is >= the size, so be sure to check the list size before using get.
"lastValue(index)" will return a single point value/time object, or null if the index is invalid. lastValue(0) will return the most recent value, lastValue(1) will return the second-most recent value, etc.
Point value/time objects have "value" and "time" properties.
That's great, thanks!
What version will it be in?
When can I use it?
Did you add it to the context help?
You're welcome. It will be in MA core 2.0.4. When you download it. Context help was added to the meta module.