class NotchFilter(Block): input = Input() frequency = Float(50.0) # Find out what module_pole is and rename it module_pole = Float(0.9) nyquist = Float(125.0) @on_trait_change("frequency,module_pole") def compute_filter(self): theta = 2 * np.pi * self.frequency / self.nyquist * 2 zero = np.exp(np.array([1j, -1j]) * theta) pole = self.module_pole * zero self._filter_b = np.poly(zero) self._filter_a = np.poly(pole) def init(self, input): self.compute_filter() self.input = input self.output = Signal() def process(self): buffer = self.input.buffer assert self.input.new_samples == 1 filt = lfilter(self._filter_b, self._filter_a, buffer) self.output.append(filt[-1:]) self.output.process()
class JitterBuffer(Block): input = Input() buffer_size = 5 def init(self, input, sample_rate): self.input = input self.output = Signal() self.period = 1.0 / sample_rate self.buffer = [] self.started = False def process(self): newbuf = self.input.new newbuf.extend(self.buffer) self.buffer = newbuf if not self.started and len(self.buffer) > self.buffer_size: self.started = True import threading threading.Thread(target=self.run).start() def clock_sample(self): if len(self.buffer): self.output.append([self.buffer.pop()]) self.output.process() else: print('Warning: JitterBuffer ran empty') def run(self): nperiod = int(self.period * 1000000000) ncomputation = nperiod // 10 nconstraint = ncomputation * 2 print(self.period, nperiod, ncomputation, nconstraint) set_realtime(nperiod, ncomputation, nconstraint) start = monotonic() while (True): loop_begin = monotonic() #print ('diff time %f' % (loop_begin - start)) wait_time = start + self.period - monotonic() if wait_time <= 0.000001: start += self.period self.clock_sample() loop_end = monotonic() #print ('clock process took %f seconds' % (loop_end - loop_begin)) elif wait_time > self.period / 2: #print ('%f seconds left, sleeping' % wait_time) thread_yield() else: pass
class Normalizer(Block): input = Input() time_factor = Float(0.9999) def __init__(self, input, **config): self.output = Signal() super(Normalizer, self).__init__(**config) self.min = 0.0 self.max = 1.0 self.input = input def process(self): min = np.min(self.input.buffer) / 2 self.min = self.min * self.time_factor + min * (1.0 - self.time_factor) max = np.max(self.input.buffer) * 2 self.max = self.max * self.time_factor + max * (1.0 - self.time_factor) out = (np.array(self.input.new) - self.min) / (self.max - self.min) * 2 self.output.append(out) self.output.process()
def init(self, input): self.input = input self.cnt = 0 self.window = np.hanning(self.chunk_size) self.freq = Signal()
def __init__(self, input, **config): self.dc = Signal() self.ac = Signal() super(DCBlock, self).__init__(**config) self.input = input
class DominantFrequency(Block): input = Input() chunk_size = 256 def init(self, input): self.input = input self.cnt = 0 self.window = np.hanning(self.chunk_size) self.freq = Signal() def process(self): self.cnt += 1 if self.cnt > 20: self.cnt = 0 else: return C = np.fft.rfft(self.input.buffer[-self.chunk_size:] * self.window) C = abs(C) Fs = 250.0 def index_max(values): return max(xrange(len(values)),key=values.__getitem__) freq = index_max(C) freq = freq / Fs self.freq.append([freq]) self.freq.process()
class DCBlock(Block): input = Input() def __init__(self, input, **config): self.dc = Signal() self.ac = Signal() super(DCBlock, self).__init__(**config) self.input = input def _input_changed(self): traits = self.input.trait_get(['label', 'color']) self.ac.trait_set(**traits) def process(self): for x in self.input.new: new_dc = self.dc.buffer[-1] * 0.95 + x * 0.05 self.dc.append([new_dc]) self.dc.process() self.ac.append([x - self.dc.buffer[-1] for x in self.input.new]) self.ac.process()
class BandPass(Block): input = Input() order = Range(low=2, high=8, value=5) lo = Float hi = Float nyquist = Float(125) def init(self, lo, hi, input): self.lo = lo self.hi = hi self.input = input self.output = Signal() @on_trait_change("lo,hi,order,nyquist") def _range_changed(self): b,a = iirfilter(self.order, (self.lo / self.nyquist, self.hi / self.nyquist)) self._filter_b, self._filter_a = b,a def process(self): buffer = self.input.buffer[-self.order*3:] filt = lfilter(self._filter_b, self._filter_a, buffer) self.output.append(filt[-1:]) self.output.process() @property def range(self): return self.lo, self.hi
def init(self, input): self.input = input self.last_time = monotonic() self.time_diff = Signal() self.sample_rate = Signal() self.jitter = Signal()
def init(self, input, sample_rate): self.input = input self.output = Signal() self.period = 1.0 / sample_rate self.buffer = [] self.started = False
def __init__(self, input, **config): self.output = Signal() super(Normalizer, self).__init__(**config) self.min = 0.0 self.max = 1.0 self.input = input
def __init__(self, sample_rate): super(TestClock, self).__init__() self.output = Signal() self.period = 1.0 / sample_rate #self.start(QtCore.QThread.HighestPriority) #self.start() threading.Thread(target=self.run).start()
def init(self, input): self.input = input self.output = Signal() self.bpm = Signal() self.gradient = Signal() self.pulse = Signal() self.last_beat = -1 self.timestamp = 0
class NotchDelay(Block): input = Input() frequency = Float(50.0) samplerate = Int(250) def init(self, input): self.readjust() self.input = input self.output = Signal() self.delayed = Signal() @on_trait_change("frequency,samplerate") def readjust(self): delay = self.samplerate / self.frequency / 2 delay = 3 self.delayline = [0] * int(delay) def process(self): for sample in self.input.new: self.delayline[1:] = self.delayline[:-1] self.delayline[0] = sample self.output.append([self.delayline[-1] + sample]) self.delayed.append([self.delayline[-1] + self.delayline[-2]]) self.output.process() self.delayed.process()
class Averager(Block): input = Input() def __init__(self, input): self.output = Signal() self.average = 0.0 self.factor = 0.99 super(Averager, self).__init__(input=input) def process(self): for x in self.input.new: self.average = self.average * self.factor + x * (1.0 - self.factor) self.output.append([self.average]) self.output.process()
def init(self, func, *args): # HACK: should not directly reference lupa here import lupa if lupa.lua_type(args) == 'table': args = args.values() print ('Expression: ', func, args) self.func = func self.args = list(args) self.output = Signal() # Workaround for list event bug self.input = self.args[0]
def init(self, func, *args): self.func = func self.args = list(args) # Workaround for list event bug self.input = args[0] self.output = Signal()
class Expression(Block): args = List(Input) input = Input() def init(self, func, *args): self.func = func self.args = list(args) # Workaround for list event bug self.input = args[0] self.output = Signal() def process(self): args = [chan.last for chan in self.args] self.output.append([self.func(*args)]) self.output.process()
def __init__(self, input): self.output = Signal(buffer_size=1000) self.cnt = 0 super(Trendline, self).__init__(input=input) def _input_changed(self): traits = self.input.trait_get(['label', 'color']) self.ac.trait_set(**traits)
class TestClock(QtCore.QThread): def __init__(self, sample_rate): super(TestClock, self).__init__() self.output = Signal() self.period = 1.0 / sample_rate #self.start(QtCore.QThread.HighestPriority) #self.start() threading.Thread(target=self.run).start() def clock_sample(self): self.output.append([monotonic()]) self.output.process() def run(self): nperiod = int(self.period * 1000000000) ncomputation = nperiod // 10 nconstraint = ncomputation * 2 print (self.period, nperiod, ncomputation, nconstraint) set_realtime(nperiod, ncomputation, nconstraint) start = monotonic() while (True): loop_begin = monotonic() #print ('diff time %f' % (loop_begin - start)) wait_time = start + self.period - monotonic() if wait_time <= 0.000001: start += self.period self.clock_sample() loop_end = monotonic() #print ('clock process took %f seconds' % (loop_end - loop_begin)) elif wait_time > self.period / 2: #print ('%f seconds left, sleeping' % wait_time) thread_yield() else: pass
class TestClock(QtCore.QThread): def __init__(self, sample_rate): super(TestClock, self).__init__() self.output = Signal() self.period = 1.0 / sample_rate #self.start(QtCore.QThread.HighestPriority) #self.start() threading.Thread(target=self.run).start() def clock_sample(self): self.output.append([monotonic()]) self.output.process() def run(self): nperiod = int(self.period * 1000000000) ncomputation = nperiod // 10 nconstraint = ncomputation * 2 print(self.period, nperiod, ncomputation, nconstraint) set_realtime(nperiod, ncomputation, nconstraint) start = monotonic() while (True): loop_begin = monotonic() #print ('diff time %f' % (loop_begin - start)) wait_time = start + self.period - monotonic() if wait_time <= 0.000001: start += self.period self.clock_sample() loop_end = monotonic() #print ('clock process took %f seconds' % (loop_end - loop_begin)) elif wait_time > self.period / 2: #print ('%f seconds left, sleeping' % wait_time) thread_yield() else: pass
def init(self, name, input): self.FS = 250 self.name=name epoch_samples = int(self.FS * self.epoch) self.signal = Signal(buffer_size=epoch_samples) self.passfail = Signal() self.ratio = Signal() self.threshold = 1.0 self.high_threshold = 0.0 self.calc_cnt = 0 self.bar = QtGui.QProgressBar(orientation=QtCore.Qt.Vertical) self.slider = QtGui.QSlider() self.slider.setRange(0, 17) self.bar.setRange(0, 17) self.pass_palette = self.bar.palette() self.input = input if isinstance(self.input.color, QtGui.QColor): self.color = self.input.color else: self.color = QtGui.QColor(self.input.color) self.bar.setStyleSheet(""" QProgressBar::chunk { background: red; } QProgressBar::chunk[pass='******'] { background: %s ; } """ % self.color.name()) self.button = QtGui.QPushButton("config") self.button.clicked.connect(self.configure_traits) self._widget = ThresholdWidget(self)
class Expression(Block): args = List(Input) input = Input() def init(self, func, *args): # HACK: should not directly reference lupa here import lupa if lupa.lua_type(args) == 'table': args = args.values() print ('Expression: ', func, args) self.func = func self.args = list(args) self.output = Signal() # Workaround for list event bug self.input = self.args[0] def _input_changed(self): self.output.copy_traits(self.input, ['label', 'color']) def process(self): args = [chan.last for chan in self.args] self.output.append([self.func(*args)]) self.output.process()
class Trendline(Block): input = Input() interval = Int(25) def __init__(self, input): self.output = Signal(buffer_size=1000) self.cnt = 0 super(Trendline, self).__init__(input=input) def _input_changed(self): traits = self.input.trait_get(['label', 'color']) self.ac.trait_set(**traits) def process(self): self.cnt += self.input.new_samples if self.cnt >= self.interval: self.cnt = 0 avg = sum(self.input.buffer[-self.interval:]) / self.interval self.output.append([avg]) self.output.process()
class RMS(Block): input = Input() avg_size = Int(42) def init(self, input): self.output = Signal() self.input = input def _input_changed(self): self.output.copy_traits(self.input, ['label', 'color']) def process(self): buf = np.array(self.input.buffer[-self.avg_size:]) rms = sum(buf ** 2) / len(buf) avg = np.sqrt(rms) self.output.append([avg]) self.output.process()
class HeartAnalyzer(Block): input = Input() def init(self): self.beat = Signal('Beat Event') self.bpm = Signal("Beats per Minute") def process(self): square = np.array(self.input.buffer)**2 threshold = np.percentile(square, 98) if np.max(self.input.buffer[:self.input.new_samples]) > threshold: self.beat.append([1.0]) print 'beat event' else: self.beat.append([0.0]) self.beat.process()
class HeartAnalyzer(Block): input = Input() def init(self): self.beat = Signal('Beat Event') self.bpm = Signal("Beats per Minute") def process(self): square = np.array(self.input.buffer) ** 2 threshold = np.percentile(square, 98) if np.max(self.input.buffer[:self.input.new_samples]) > threshold: self.beat.append([1.0]) print 'beat event' else: self.beat.append([0.0]) self.beat.process()
def init(self, name, input): self.FS = 250 self.name = name epoch_samples = int(self.FS * self.epoch) self.signal = Signal(buffer_size=epoch_samples) self.passfail = Signal() self.ratio = Signal() self.threshold = 1.0 self.high_threshold = 0.0 self.calc_cnt = 0 self.bar = QtGui.QProgressBar(orientation=QtCore.Qt.Vertical) self.slider = QtGui.QSlider() self.slider.setRange(0, 17) self.bar.setRange(0, 17) self.pass_palette = self.bar.palette() self.input = input if isinstance(self.input.color, QtGui.QColor): self.color = self.input.color else: self.color = QtGui.QColor(self.input.color) self.bar.setStyleSheet(""" QProgressBar::chunk { background: red; } QProgressBar::chunk[pass='******'] { background: %s ; } """ % self.color.name()) self.button = QtGui.QPushButton("config") self.button.clicked.connect(self.configure_traits) self._widget = ThresholdWidget(self)
def init(self): self.beat = Signal('Beat Event') self.bpm = Signal("Beats per Minute")
class ClockAnalyzer(Block): input = Input() alpha = 0.5 def init(self, input): self.input = input self.last_time = monotonic() self.time_diff = Signal() self.sample_rate = Signal() self.jitter = Signal() def process(self): #self.input.buffer_size = 1024 #if len(self.input.buffer) < 1024: return new_time = monotonic() diff = new_time - self.last_time self.last_time = new_time self.time_diff.append([diff]) self.time_diff.process() sample_rate = 1.0 / moving_average_exp(self.alpha, self.time_diff.buffer) self.sample_rate.append([sample_rate]) self.sample_rate.process() period = 1.0 / sample_rate jitter = abs(diff - period) * 1000 self.jitter.append([jitter]) self.jitter.process()
def init(self, lo, hi, input): self.lo = lo self.hi = hi self.input = input self.output = Signal()
def init(self, input): self.output = Signal() self.input = input
def __init__(self, input): self.output = Signal() self.average = 0.0 self.factor = 0.99 super(Averager, self).__init__(input=input)
def init(self, input): self.readjust() self.input = input self.output = Signal() self.delayed = Signal()
class JitterBuffer(Block): input = Input() buffer_size = 5 def init(self, input, sample_rate): self.input = input self.output = Signal() self.period = 1.0 / sample_rate self.buffer = [] self.started = False def process(self): newbuf = self.input.new newbuf.extend(self.buffer) self.buffer = newbuf if not self.started and len(self.buffer) > self.buffer_size: self.started = True import threading threading.Thread(target=self.run).start() def clock_sample(self): if len(self.buffer): self.output.append([self.buffer.pop()]) self.output.process() else: print ('Warning: JitterBuffer ran empty') def run(self): nperiod = int(self.period * 1000000000) ncomputation = nperiod // 10 nconstraint = ncomputation * 2 print (self.period, nperiod, ncomputation, nconstraint) set_realtime(nperiod, ncomputation, nconstraint) start = monotonic() while (True): loop_begin = monotonic() #print ('diff time %f' % (loop_begin - start)) wait_time = start + self.period - monotonic() if wait_time <= 0.000001: start += self.period self.clock_sample() loop_end = monotonic() #print ('clock process took %f seconds' % (loop_end - loop_begin)) elif wait_time > self.period / 2: #print ('%f seconds left, sleeping' % wait_time) thread_yield() else: pass
def __init__(self, input): self.output = Signal(buffer_size=1000) self.cnt = 0 super(Trendline, self).__init__(input=input)
class PulseAnalyzer(Block): input = Input() def init(self, input): self.input = input self.output = Signal() self.bpm = Signal() self.gradient = Signal() self.pulse = Signal() self.last_beat = -1 self.timestamp = 0 def _input_changed(self): self.output.copy_traits(self.input, ['label', 'color']) def process(self): avg = np.average(self.output.buffer) max = np.max(self.output.buffer) self.timestamp += 1 self.gradient.append([self.input.buffer[-1] - self.input.buffer[-2]]) buf = np.power(self.gradient.buffer[-50:], 2) s = np.sum(np.hanning(50)[:50] * buf) self.output.append([s]) for i, sample in enumerate(self.output.new): new = 1.0 if sample > max * 0.7 else 0.0 self.pulse.append([new]) if new > self.pulse.buffer[-2]: diff = self.timestamp - self.last_beat bpm = 1.0 / (diff / 250.) * 60 self.bpm.append([bpm]) self.bpm.process() print('beat event', diff, bpm, self.timestamp, self.last_beat) self.last_beat = self.timestamp self.output.process() self.gradient.process()
def init(self, input): self.compute_filter() self.input = input self.output = Signal()
def register_channel(self, idx, channel_name): self.input_channels[idx] = Signal(name=channel_name)
class PulseAnalyzer(Block): input = Input() def init(self, input): self.input = input self.output = Signal() self.bpm = Signal() self.gradient = Signal() self.pulse = Signal() self.last_beat = -1 self.timestamp = 0 def _input_changed(self): self.output.copy_traits(self.input, ["label", "color"]) def process(self): avg = np.average(self.output.buffer) max = np.max(self.output.buffer) self.timestamp += 1 self.gradient.append([self.input.buffer[-1] - self.input.buffer[-2]]) buf = np.power(self.gradient.buffer[-50:], 2) s = np.sum(np.hanning(50)[:50] * buf) self.output.append([s]) for i, sample in enumerate(self.output.new): new = 1.0 if sample > max * 0.7 else 0.0 self.pulse.append([new]) if new > self.pulse.buffer[-2]: diff = self.timestamp - self.last_beat bpm = 1.0 / (diff / 250.0) * 60 self.bpm.append([bpm]) self.bpm.process() print("beat event", diff, bpm, self.timestamp, self.last_beat) self.last_beat = self.timestamp self.output.process() self.gradient.process()