Alternative methods of computing real-time event frequency - algorithm
I'm working in an application where there is a lot of reporting of external events. One of the metrics that is used often is the event rate as a function of time. For example, measuring the sample-rate of some external asynchronous sensor.
Currently the way I'm calculating the frequency of events like this is to keep a queue of event timestamps. When the event occurs we push a current timestamp onto the queue, then pop until the oldest timestamp is less than a predefined age. Then, the event frequency is proportional to the size of the queue. In pseudo-code the method usually looks something like this:
def on_event():
var now = current_time()
time_queue.push(now)
while((now - time_queue.front()) > QUEUE_DEPTH_SECONDS):
time_queue.pop()
frequency = time_queue.size() / QUEUE_DEPTH_SECONDS
Now this approach is obviously not optimal:
Memory requirement and computation time is proportional to event rate.
The queue duration has to be manually adjusted based on the expected data rate in order to tune low-frequency performance vs memory requirements.
The response-time of the frequency measurement is also dependent on the queue duration. Longer durations lower the response time of the calculation.
The frequency is only updated when a new event occurs. If the events stop occurring, then the frequency measurement will remain at the value calculated when the last event was received.
I'm curious if there are any alternative algorithms that can be used to calculate the rate of an event, and what trade-offs they have in relation to computational complexity, space requirements, response-time, etc.
https://en.wikipedia.org/wiki/Exponential_smoothing is very efficient and uses only a small and bounded amount of memory. You could try exponential smoothing of the inter-arrival times. When retrieving the smoothed inter-arrival time you could look at the time to the last event, and mix that in if it is larger than the smoothed inter-arrival time.
This is different enough that I would in fact start by collecting a sample of timestamps in current use, so that I could use it to test the result of this or other schemes off-line.
One alternative is a local timer that fires at a constant rate (e.g. once per second):
When an external event occurs, it increments a counter.
When the local timer fires, the counter value is added to a queue, and the count is reset to zero.
Here's how the method compares to yours:
Memory requirement and computation time is independent of the external event rate. It is determined by the local timer rate, which you control.
The queue size depends on how much averaging you want to do. A queue size of 1 (i.e. no queue) with a timer rate of once per second results in a raw events-per-second reading, with no averaging. The larger the queue, the more averaging you get.
The response time is determined by the amount of averaging desired. More averaging results in slower response times.
The frequency is updated at the rate that the local timer fires, regardless of whether external events occur.
I've implemented something similar to calculate the rate/concentration of particles in an air stream. They come at random events (probably poisson distributed) and I want to know the average rate in particles per time. My approach is as follows (taken from the docstring of my code):
Event timestamps are placed in a buffer of a fixed maximum size.
Whenever a concentration estimate is requested, all timestamps up to
a set maximum age are filtered out. If the remaining number of
recent timestamps is below some threshold, the reported
concentration is zero. Otherwise, the concentration is calculated
as the number of remaining events divided by the time difference
between the oldest timestamp in the buffer and now.
I'll attach the Python implementation below for reference. It is a part of a much larger project, so I had to slightly modify it to get rid of references to external code:
particle_concentration_estimator_params.py
#!/usr/bin/env python3
"""This module implements a definition of parameters for the particle
concentration estimator.
"""
__author__ = "bup"
__email__ = "bup#swisens.ch"
__copyright__ = "Copyright 2021, Swisens AG"
__license__ = "GNU General Public License Version 3 (GPLv3)"
__all__ = ['ParticleConcentrationEstimatorParams']
import dataclasses
#dataclasses.dataclass
class ParticleConcentrationEstimatorParams:
"""This provides storage for the parameters used for the particle
concentration estimator.
"""
timestamp_buffer_max_size: int
"""Maximum size of the buffer that is used to keep track of event
timestamps. The size of this buffer mainly affects the filtering
of the reported data.
Unit: - (count)
"""
timestamp_buffer_max_age: float
"""Maximum age of events in the timestamp buffer which are
considered for the concentration calculation. This value is a
tradeoff between a smooth filtered value and the dynamic response
to a changed concentration.
Unit: s
"""
min_number_of_timestamps: int
"""Minimum number of timestamps to use for the concentration
estimation. If less timestamps are available, the concentration is
reported as zero.
Unit: - (count)
"""
particle_concentration_estimator.py
#!/usr/bin/env python3
"""This module implements the particle concentration estimation.
"""
__author__ = "bup"
__email__ = "bup#swisens.ch"
__copyright__ = "Copyright 2021, Swisens AG"
__license__ = "GNU General Public License Version 3 (GPLv3)"
__all__ = ['ParticleConcentrationEstimator']
import logging
import time
from typing import Optional
import numpy as np
from .particle_concentration_estimator_params import ParticleConcentrationEstimatorParams
logger = logging.getLogger(__name__)
class ParticleConcentrationEstimator:
"""An object of this class implements the Poleno particle
concentration estimator. Particle concentration is basically just
a number of particles per time unit. But since the particle events
arrive irregularly, there are various ways to filter the result, to
avoid too much noise especially when the concentration is low. This
class implements the following approach:
Event timestamps are placed in a buffer of a fixed maximum size.
Whenever a concentration estimate is requested, all timestamps up to
a set maximum age are filtered out. If the remaining number of
recent timestamps is below some threshold, the reported
concentration is zero. Otherwise, the concentration is calculated
as the number of remaining events divided by the time difference
between the oldest timestamp in the buffer and now.
"""
def __init__(self, params: ParticleConcentrationEstimatorParams):
"""Initializes the object with no events.
Args:
est_params: Initialized PolenoParams object which includes
information describing the estimator's behaviour.
"""
self.params = params
"""Stored params for the object."""
n_rows = self.params.timestamp_buffer_max_size
self._rb = np.full((n_rows, 2), -1e12)
self._rb_wp = 0
self._num_timestamps = 0
self._concentration_value = 0.0
self._concentration_value_no_mult = 0.0
def tick(self, now: float) -> float:
"""Recalculates the current concentration value.
Args:
now: Current timestamp to use to filter out old entries
in the buffer.
Returns:
The updated concentration value, which is also returned
using the concentration attribute.
"""
min_ts = now - self.params.timestamp_buffer_max_age
min_num = self.params.min_number_of_timestamps
used_rows = self._rb[:, 0] >= min_ts
filt_ts = self._rb[used_rows]
num_ts = round(np.sum(filt_ts[:, 1]))
self._num_timestamps = num_ts
num_ts_no_mult = round(np.sum(used_rows))
if num_ts < min_num:
self._concentration_value = 0.0
self._concentration_value_no_mult = 0.0
else:
t_diff = now - np.min(filt_ts[:, 0])
if t_diff >= 1e-3:
# Do not change the reported value if all events in the
# buffer have the same timestamp.
self._concentration_value = num_ts / t_diff
self._concentration_value_no_mult = num_ts_no_mult / t_diff
return self._concentration_value
def got_timestamp(self,
ts: Optional[float] = None,
multiplier: float = 1.0) -> None:
"""Passes in the most recent event timestamp. Timestamps need
not be ordered.
Calling this method does not immediately update the
concentration value, this is deferred to the tick() method.
Args:
ts: Event timestamp to use. If None, the current time is
used.
multiplier: Optional multiplier, which makes ts to be
counted that many times.
"""
if ts is None:
ts = time.time()
self._rb[self._rb_wp] = (ts, float(multiplier))
self._rb_wp = (self._rb_wp + 1) % self._rb.shape[0]
self._num_timestamps += round(multiplier)
#property
def concentration(self) -> float:
"""The calculated concentration value.
Unit: 1/s
"""
return self._concentration_value
#property
def concentration_no_mult(self) -> float:
"""The calculated concentration value without taking into
account the timestamp multipliers, i.e. as if all timestamps
were given with the default multiplier of 1.
Unit: 1/s
"""
return self._concentration_value_no_mult
#property
def num_timestamps(self) -> int:
"""Returns the number of timestamps which currently are in
the internal buffer.
"""
return self._num_timestamps
Related
THREE.Audio filter not ramping up with linearRampToValueAtTime
I'm having a little trouble working with the linearRampToValueAtTime on a BiQuadFilter applied to a WebAudio. The audio works ok, and the initial lowpass filter is applied. Problem is, as soon as I use the linearRamp method to bring up the frequency, it seems to ignore the endTime parameter (or better, it's not time correctly). Some code to explain it better. Here's the instancing: this.audioLoader.load( 'public/media/soundtrack-es_cobwebs_in_the_sky.mp3', buffer => { this.sounds.soundtrack = new THREE.Audio(this.listener); const audioContext = this.sounds.soundtrack.context; this.biquadFilter = audioContext.createBiquadFilter(); this.biquadFilter.type = "lowpass"; // Low pass filter this.biquadFilter.frequency.setValueAtTime(200, audioContext.currentTime); this.sounds.soundtrack.setBuffer(buffer); this.sounds.soundtrack.setFilter(this.biquadFilter); this.sounds.soundtrack.setVolume(0.5); this.sounds.soundtrack.play(); }) Until here, everything looks ok. The sound plays muffled as needed. Then, after a certain event, there's a camera transition, where I want the sound to gradually open up. As a endTime parameter, I'm passing 2 seconds + the internal context delta. this.sounds.soundtrack.filters[0].frequency.linearRampToValueAtTime(2400, 2 + this.sounds.soundtrack.context.currentTime); Expecting to hear the ramp in two seconds, but the sound opens up immediately. What am I missing?
The linear ramp will be applied using the previous event as the startTime. In your case that will be audioContext.currentTime at the point in time when you created the filter. If that is sufficiently long ago it will sound as if the ramp jumps right to the end value. You can fix that by inserting a new event right before the ramp. const currentTime = this.sounds.soundtrack.context.currentTime; const filter = this.sounds.soundtrack.filters[0]; filter.frequency.setValueAtTime(200, currentTime); filter.frequency.linearRampToValueAtTime(2400, currentTime + 2);
av_seek_frame() Can't seek to the place I want
I want to intercept a frame of my video file, so I used the av_seek_frame function, the timestamp value I tried using timestamp*AV_TIME_BASE and timestamp/(av_q2d(videostream->time_base)*av_TIME_BASE), but no matter what I use Which one, the obtained frame is always not what I want, and it is observed that the frame time that I want is very different (so the accuracy problem of AVSEEK_FLAG_BACKWARD is excluded here). My code is as follows: double tmp0 = timeStamp/(av_q2d(inputVideoStream->time_base)*AV_TIME_BASE); // double tmp0 = timeStamp * AV_TIME_BASE; code = av_seek_frame(inputAVFormatContext, videoStreamIndex, tmp0, AVSEEK_FLAG_BACKWARD);
Scala: Iterate over 20k images once, crop 100 ways to make 100 Iterators
requirement I need to iterate over images, splitting each into 100 blocks (ROIs) and calculating something independently per block. I can't store anything other than the file paths in a list in memory, and I can't perform disk IO more than once. Performance is more important than simplicity here. How do I build 100 iterators while iterating over images? code I've written this a few ways but always get a StackOverflowError after ~5 hours (should finish in under 20 minutes). The following is the way that made the most sense to me: Iterate over an in-memory list of paths and build a map of iterators. def calcAll(run: ImageBase, rois: Traversable[Roi]): Map[Roi, TraversableOnce[T]] = { val results: mutable.Map[Roi, Iterator[T]] = emptyMutableMap(rois) // calculate feature between every two frames var prevImage: RichImage = null // it'll be ok, I promise for (frame <- ImageStore.walk(run) { // iterates over nio Path objects val image = RichImages.of(frame) if (prevImage != null) for (roi <- rois) { val next: Iterator[T] = calc(Iterator(prevImage.crop(roi), image.crop(roi))) results(roi) = results(roi) ++ next // StackOverflowError!! } prevImage = image } results.toMap // immutable } background I have a directory of 20k grayscale frames from a video. The video has a set of 100 Regions of Interest (ROIs), non-overlapping rectangles that we care about. I need to calculate features between consecutive images, but independently for each ROI. The amount of data and number of ROIs prohibits reading an image more than once.
I believe you need something similar to this: def calcAll(run: ImageBase, rois: Seq[Roi]): Traversable[Map[Roi, T]] = { ImageStore.walk(run).map(RichImages.of).sliding(2).map { case Seq(image1, image2) => rois.map(roi => roi -> calc(image1.crop(roi), image2.crop(roi)).toMap } } Given that ImageStore.walk returns an Iterator or Traversable, this code will load each image only once and won't have to store more than two images in memory at a time. This gives you a single iterator though. Having 100 iterators will require either storing all images in memory, or traversing them 100 times. So, unfortunately, I believe you'd have to do with a Traversable[Map[Roi, T]].
psychopy polygon on top of image
using psychopy ver 1.81.03 on a mac I want to draw a polygon (e.g. a triangle) on top of an image. So far, my image stays always on top and thus hides the polygon, no matter the order I put them in. This also stays true if I have the polygon start a frame later than the image. e.g. see inn the code below (created with the Builder before compiling) how both a blue square and a red triangle are supposed to start at frame 0, but when you run it the blue square always covers the red triangle!? Is there a way to have the polygon on top? Do I somehow need to merge the image and polygon before drawing them? Thank you so much for your help!! Sebastian #!/usr/bin/env python2 # -*- coding: utf-8 -*- """ This experiment was created using PsychoPy2 Experiment Builder (v1.81.03), Sun Jan 18 20:44:26 2015 If you publish work using this script please cite the relevant PsychoPy publications Peirce, JW (2007) PsychoPy - Psychophysics software in Python. Journal of Neuroscience Methods, 162(1-2), 8-13. Peirce, JW (2009) Generating stimuli for neuroscience using PsychoPy. Frontiers in Neuroinformatics, 2:10. doi: 10.3389/neuro.11.010.2008 """ from __future__ import division # so that 1/3=0.333 instead of 1/3=0 from psychopy import visual, core, data, event, logging, sound, gui from psychopy.constants import * # things like STARTED, FINISHED import numpy as np # whole numpy lib is available, prepend 'np.' from numpy import sin, cos, tan, log, log10, pi, average, sqrt, std, deg2rad, rad2deg, linspace, asarray from numpy.random import random, randint, normal, shuffle import os # handy system and path functions # Ensure that relative paths start from the same directory as this script _thisDir = os.path.dirname(os.path.abspath(__file__)) os.chdir(_thisDir) # Store info about the experiment session expName = u'test_triangle_over_square' # from the Builder filename that created this script expInfo = {'participant':'', 'session':'001'} dlg = gui.DlgFromDict(dictionary=expInfo, title=expName) if dlg.OK == False: core.quit() # user pressed cancel expInfo['date'] = data.getDateStr() # add a simple timestamp expInfo['expName'] = expName # Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc filename = _thisDir + os.sep + 'data/%s_%s_%s' %(expInfo['participant'], expName, expInfo['date']) # An ExperimentHandler isn't essential but helps with data saving thisExp = data.ExperimentHandler(name=expName, version='', extraInfo=expInfo, runtimeInfo=None, originPath=None, savePickle=True, saveWideText=True, dataFileName=filename) #save a log file for detail verbose info logFile = logging.LogFile(filename+'.log', level=logging.EXP) logging.console.setLevel(logging.WARNING) # this outputs to the screen, not a file endExpNow = False # flag for 'escape' or other condition => quit the exp # Start Code - component code to be run before the window creation # Setup the Window win = visual.Window(size=(1280, 800), fullscr=True, screen=0, allowGUI=False, allowStencil=False, monitor='testMonitor', color=[0,0,0], colorSpace='rgb', blendMode='avg', useFBO=True, ) # store frame rate of monitor if we can measure it successfully expInfo['frameRate']=win.getActualFrameRate() if expInfo['frameRate']!=None: frameDur = 1.0/round(expInfo['frameRate']) else: frameDur = 1.0/60.0 # couldn't get a reliable measure so guess # Initialize components for Routine "trial" trialClock = core.Clock() ISI = core.StaticPeriod(win=win, screenHz=expInfo['frameRate'], name='ISI') square = visual.ImageStim(win=win, name='square',units='pix', image=None, mask=None, ori=0, pos=[0, 0], size=[200, 200], color=u'blue', colorSpace='rgb', opacity=1, flipHoriz=False, flipVert=False, texRes=128, interpolate=True, depth=-1.0) polygon = visual.ShapeStim(win=win, name='polygon',units='pix', vertices = [[-[200, 300][0]/2.0,-[200, 300][1]/2.0], [+[200, 300][0]/2.0,-[200, 300][1]/2.0], [0,[200, 300][1]/2.0]], ori=0, pos=[0, 0], lineWidth=1, lineColor=[1,1,1], lineColorSpace='rgb', fillColor=u'red', fillColorSpace='rgb', opacity=1,interpolate=True) # Create some handy timers globalClock = core.Clock() # to track the time since experiment started routineTimer = core.CountdownTimer() # to track time remaining of each (non-slip) routine #------Prepare to start Routine "trial"------- t = 0 trialClock.reset() # clock frameN = -1 # update component parameters for each repeat # keep track of which components have finished trialComponents = [] trialComponents.append(ISI) trialComponents.append(square) trialComponents.append(polygon) for thisComponent in trialComponents: if hasattr(thisComponent, 'status'): thisComponent.status = NOT_STARTED #-------Start Routine "trial"------- continueRoutine = True while continueRoutine: # get current time t = trialClock.getTime() frameN = frameN + 1 # number of completed frames (so 0 is the first frame) # update/draw components on each frame # *square* updates if frameN >= 0 and square.status == NOT_STARTED: # keep track of start time/frame for later square.tStart = t # underestimates by a little under one frame square.frameNStart = frameN # exact frame index square.setAutoDraw(True) # *polygon* updates if frameN >= 0 and polygon.status == NOT_STARTED: # keep track of start time/frame for later polygon.tStart = t # underestimates by a little under one frame polygon.frameNStart = frameN # exact frame index polygon.setAutoDraw(True) # *ISI* period if t >= 0.0 and ISI.status == NOT_STARTED: # keep track of start time/frame for later ISI.tStart = t # underestimates by a little under one frame ISI.frameNStart = frameN # exact frame index ISI.start(0.5) elif ISI.status == STARTED: #one frame should pass before updating params and completing ISI.complete() #finish the static period # check if all components have finished if not continueRoutine: # a component has requested a forced-end of Routine routineTimer.reset() # if we abort early the non-slip timer needs reset break continueRoutine = False # will revert to True if at least one component still running for thisComponent in trialComponents: if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: continueRoutine = True break # at least one component has not yet finished # check for quit (the Esc key) if endExpNow or event.getKeys(keyList=["escape"]): core.quit() # refresh the screen if continueRoutine: # don't flip if this routine is over or we'll get a blank screen win.flip() else: # this Routine was not non-slip safe so reset non-slip timer routineTimer.reset() #-------Ending Routine "trial"------- for thisComponent in trialComponents: if hasattr(thisComponent, "setAutoDraw"): thisComponent.setAutoDraw(False) win.close() core.quit()
As per Jonas' comment above, PsychoPy uses a layering system in which subsequent stimuli are drawn on top of previous stimuli (as in his code examples). In the graphical Builder environment, drawing order is represented by the vertical order of stimulus components: stimuli at the top are drawn first, and ones lower down are progressively layered upon them. You can change the order of stimulus components by right-clicking on them and selecting "Move up", "move down", etc as required. Sebastian, has, however, identified a bug here, in that the intended drawing order is not honoured between ImageStim and ShapeStim components. As a work-around, you might be able to replace your ShapeStim with a bitmap representation, displayed using an ImageStim. Multiple ImageStims should draw correctly (as do multiple ShapeStims). To get it to draw correctly on top of another image, be sure to save it as a .png file, which supports transparency. That way, only the actual shape will be drawn on top, as its background pixels can be set to be transparent and will not mask the the underlying image. For a long-term solution, I've added your issue as a bug report to the PsychoPy GitHub project here: https://github.com/psychopy/psychopy/issues/795
It turned out to be a bug in the Polygon component in Builder. This is fixed in the upcoming release (1.82.00). The changes needed to make the fix can be seen at https://github.com/psychopy/psychopy/commit/af1af9a7a85cee9b4ec8ad5e2ff1f03140bd1a36 which you can add to your own installation if you like. cheers, Jon
Write code to make CPU usage display a sine wave
Write code in your favorite language and let Windows Task Manager represent a sine wave in CPU Usage History. This is a technical interview quiz from Microsoft China. I think it's a good question. Especially it's worth knowing how candidate understand and figure out the solution. Edit: It's a good point if may involve multi-core(cpu) cases.
A thread time slice in Windows is 40ms, iirc, so that might be a good number to use as the 100% mark. unsigned const TIME_SLICE = 40; float const PI = 3.14159265358979323846f; while(true) { for(unsigned x=0; x!=360; ++x) { float t = sin(static_cast<float>(x)/180*PI)*0.5f + 0.5f; DWORD busy_time = static_cast<DWORD>(t*TIME_SLICE); DWORD wait_start = GetTickCount(); while(GetTickCount() - wait_start < busy_time) { } Sleep(TIME_SLICE - busy_time); } } This would give a period of about 14 seconds. Obviously this assumes there is no other significant cpu usage in the system, and that you are only running it on a single CPU. Neither of these is really that common in reality.
Here's a slightly modified #flodin's solution in Python: #!/usr/bin/env python import itertools, math, time, sys time_period = float(sys.argv[1]) if len(sys.argv) > 1 else 30 # seconds time_slice = float(sys.argv[2]) if len(sys.argv) > 2 else 0.04 # seconds N = int(time_period / time_slice) for i in itertools.cycle(range(N)): busy_time = time_slice / 2 * (math.sin(2*math.pi*i/N) + 1) t = time.perf_counter() + busy_time while t > time.perf_counter(): pass time.sleep(time_slice - busy_time); A CPU-curve can be fine-tuned using time_period and time_slice parameters.
Ok I have a different, probably BETTER solution than my first answer. Instead of trying to manipulate the CPU, instead hook into the task manager app, force it to draw what you want it to instead of CPU results. Take over the GDI object that plots the graph, etc. Sort of "Cheating" but they didnt say you had to manipulate the CPU Or even hook the call from task manager that gets the CPU %, returning a sine result instead.
With the literally hundreds (thousands?) of threads a PC runs today, the only way I can think to even come close would be to poll CPU usage as fast as possible, and if the usage% was below where it should be on the curve, to fire off a short method that just churns numbers. That will at least bring the typical low usage UP where needed, but I can't think of a good way to LOWER it without somehow taking control of other threads, and doing something such as forcing thier priority lower.
Something like this: while(true) { for(int i=0;i<360;i++) { // some code to convert i into radians if needed ... Thread.Sleep(Math.Sin(i)*something_that_makes_it_noticeable_number_of_ms+something_that_makes_it_non_negative) // some work to make cpu busy, may be increased to bigger number to see the influence on the cpu. for(j=0;j<100;j++); } }