class FPSDataLimit(Block): ''' This block limits the output update to a certain framerate. ''' Block.alias('fps_data_limit') Block.config('fps', 'Maximum framerate.') Block.input_is_variable('Signals to decimate.', min=1) Block.output_is_variable('Decimated signals.') def init(self): self.state.last_timestamp = None def update(self): should_update = False last = self.state.last_timestamp current = max(self.get_input_signals_timestamps()) if last is None: should_update = True self.state.last_timestamp = current else: fps = self.config.fps delta = 1.0 / fps difference = current - last if difference > delta: should_update = True self.state.last_timestamp = current if not should_update: return # Just copy the input to the output for i in range(self.num_input_signals()): self.set_output(i, self.get_input(i), self.get_input_timestamp(i))
class ASync(Block): ''' The first signal is the "master". Waits that all signals are perceived once. Then it creates one event every time the master arrives. ''' Block.alias('async') Block.input_is_variable( 'Signals to (a)synchronize. The first is the master.', min=2) Block.output_is_variable('Synchronized signals.') def init(self): self.state.last_sent_timestamp = None def update(self): self.state.last_timestamp = None # No signal until everybody is ready if not self.all_input_signals_ready(): return # No signal unless the master is ready master_timestamp = self.get_input_timestamp(0) if self.state.last_timestamp == master_timestamp: return self.state.last_timestamp = master_timestamp # Write all signals using master's timestamp for s in self.get_input_signals_names(): self.set_output(s, self.get_input(s), master_timestamp)
class Wait(Block): ''' This block waits a given number of updates before transmitting the output signal. ''' Block.alias('wait') Block.config('n', 'Number of updates to wait at the beginning.') Block.input_is_variable('Arbitrary signals.') Block.output_is_variable('Copy of the signals, minus the first ' '*n* updates.') def init(self): self.state.count = 0 def update(self): count = self.state.count # make something happen after we have waited enough if count >= self.config.n: # Just copy the input to the output for i in range(self.num_input_signals()): self.set_output(i, self.get_input(i), self.get_input_timestamp(i)) self.state.count = count + 1
class Identity(Block): ''' This block outputs the inputs, unchanged. ''' Block.alias('identity') Block.input_is_variable('Input signals.', min=1) Block.output_is_variable('Output signals, equal to input.') def update(self): # Just copy the input to the output for i in range(self.num_input_signals()): self.set_output(i, self.get_input(i), self.get_input_timestamp(i))
class AllReady(Block): ''' This block outputs the inputs, unchanged. ''' Block.alias('all_ready') Block.input_is_variable('Input signals.', min=1) Block.output_is_variable('Output signals, equal to input.') def update(self): if not self.all_input_signals_ready(): return for i in range(self.num_input_signals()): if self.input_update_available(i): t, value = self.get_input_ts_and_value(i) self.set_output(i, value, t)
class FPSLimit(Block): ''' This block limits the output update to a certain *realtime* framerate. Note that this uses realtime wall clock time -- not the data time! This is mean for real-time applications, such as visualization.''' Block.alias('fps_limit') Block.config('fps', 'Realtime fps limit.') Block.input_is_variable('Arbitrary signals.') Block.output_is_variable('Arbitrary signals with limited framerate.') def init(self): self.state.last_timestamp = None def update(self): should_update = False last = self.state.last_timestamp current = time.time() if last is None: should_update = True self.state.last_timestamp = current else: fps = self.config.fps delta = 1.0 / fps difference = current - last #print "difference: %s ~ %s" % (difference, delta) if difference > delta: should_update = True self.state.last_timestamp = current if not should_update: return # Just copy the input to the output for i in range(self.num_input_signals()): self.set_output(i, self.get_input(i), self.get_input_timestamp(i))
class Sync(Generator): ''' This block synchronizes a set of streams to the first stream (the master). The first signal is called the "master" signal. The other (N-1) are slaves. We guarantee that: - if the slaves are faster than the master, then we output exactly the same. Example diagrams: :: Master * * * * * Slave ++++++++++++++++ Master * * * * * output? v v x v Slave + + + output? v v v ''' Block.alias('sync') Block.input_is_variable('Signals to synchronize. The first is the master.', min=2) Block.output_is_variable('Synchronized signals.') def init(self): # output signals get the same name as the inputs names = self.get_input_signals_names() # create a state for each signal: it is an array # of tuples (timestamp, tuple) queues = {} for signal in names: queues[signal] = [] # note in all queues, # [(t0,...), (t1,...), ... , (tn,...) ] # and we have t0 > tn # The chronologically first (oldest) is queue[-1] # You get one out using queue.pop() # You insert one with queue.insert(0,...) self.set_state('queues', queues) self.state.already_seen = {} self.set_state('master', names[0]) self.set_state('slaves', names[1:]) # The output is an array of tuple (timestamp, values) # [ # (timestamp1, [value1,value2,value3,...]), # (timestamp1, [value1,value2,value3,...]) # ]# self.set_state('output', []) def update(self): def debug(s): if False: # XXX: use facilities print('sync %s %s' % (self.name, s)) output = self.get_state('output') queues = self.get_state('queues') names = self.get_input_signals_names() # for each input signal, put its value in the queues # if it is not already present for i, name in enumerate(names): # Commenting this; we clarified 0 = eternity; None = no signal yet if not self.input_signal_ready(i): debug('Ignoring signal %r because timestamp is None.' % name) continue current_timestamp = self.get_input_timestamp(i) current_value = self.get_input(i) if (name in self.state.already_seen and self.state.already_seen[name] == current_timestamp): continue else: self.state.already_seen[name] = current_timestamp queue = queues[name] # if there is nothing in the queue # or this is a new sample if ((len(queue) == 0) or newest(queue).timestamp != current_timestamp): # new sample debug("Inserting signal '%s' ts %s (queue len: %d)" % (name, current_timestamp, len(queue))) # debug('Before the queue is: %s' % queue) add_last( queue, Sample(timestamp=current_timestamp, value=current_value)) # debug('Now the queue is: %s' % queue) master = self.get_state('master') master_queue = queues[master] slaves = self.get_state('slaves') # if there is more than one value in each slave if len(master_queue) > 1: val = master_queue.pop() debug('DROPPING master (%s) ts =%s' % (master, val.timestamp)) # Now check whether all slaves signals are >= the master # If so, output a synchronized sample. if master_queue: all_ready = True master_timestamp = master_queue[-1].timestamp # print "Master timestamp: %s" % (master_timestamp) for slave in slaves: slave_queue = queues[slave] # remove oldest while (len(slave_queue) > 1 and oldest(slave_queue).timestamp < master_timestamp and oldest(slave_queue).timestamp != ETERNITY): debug("DROP one from %s" % slave) slave_queue.pop() if not slave_queue: # or (master_timestamp > slave_queue[-1].timestamp): all_ready = False # its_ts = map(lambda x:x.timestamp, slave_queue) # print "Slave %s not ready: %s" %(slave, its_ts) break if all_ready: debug("**** Ready: master timestamp %s " % (master_timestamp)) master_value = master_queue.pop().value output_values = [master_value] for slave in slaves: # get the freshest still after the master slave_queue = queues[slave] slave_timestamp, slave_value = slave_queue.pop() # print('Slave, %s %s ' % (slave, slave_timestamp)) if slave_timestamp == ETERNITY: slave_queue.append((slave_timestamp, slave_value)) # # not true anymore, assert slave_timestamp >= # master_timestamp # difference = slave_timestamp - master_timestamp # debug(" - %s timestamp %s diff %s" % # (slave, slave_timestamp, difference)) output_values.append(slave_value) output.insert(0, (master_timestamp, output_values)) # XXX XXX not really sure here # if master has more than one sample, then drop the first one # if we have something to output, do it if output: timestamp, values = output.pop() # FIXME: had to remove this for Vehicles simulation # assert timestamp > 0 debug("---------------- @ %s" % timestamp) for i in range(self.num_output_signals()): self.set_output(i, values[i], timestamp) def next_data_status(self): output = self.get_state('output') if not output: # no output ready return (False, None) else: timestamp = self.output[-1][0] return (True, timestamp)
class MyBlockA(Block): Block.input_is_variable() Block.output_is_variable()
class MyBlock(Block): Block.output_is_variable()
class MyBlock(Block): Block.input('x') Block.output_is_variable()