Example #1
0
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()
Example #2
0
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()
Example #3
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()
Example #4
0
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()
Example #5
0
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
Example #6
0
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()
Example #7
0
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
Example #8
0
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()
Example #9
0
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()
Example #10
0
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()
Example #11
0
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
Example #12
0
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()
Example #13
0
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()
Example #14
0
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
Example #15
0
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()
Example #16
0
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()
Example #17
0
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()
Example #18
0
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()
Example #19
0
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()
Example #20
0
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()
Example #21
0
class Threshold(Block):
	input = Input()

	average_period = Float(0.35)
	epoch = Float(13.0)

	auto_mode = Bool(True)
	mode = Enum('increase', 'decrease', 'range')

	auto_target = Float(90.)

	low_target = Float(90)
	high_target = Float(90)


	def init(self, name):
		self.FS = 250
		self.name=name

		epoch_samples = int(self.FS * self.epoch)

		self.signal = Signal(buffer_size=epoch_samples)
		self.passfail = 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()

		if isinstance(self.input.color, QtGui.QColor):
			self.color = self.input.color
		else:
			self.color = QtGui.QColor(QtGui.qRgb(*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)

	def widget(self):
		w = QtGui.QGroupBox()
		w.setTitle(self.name)

		l = QtGui.QGridLayout()
		l.addWidget(self.bar, 0, 0)
		l.addWidget(self.slider, 0, 1)

		l.addWidget(self.button, 1, 0, 1, 2)

		w.setLayout(l)
		w.block = self

		return w

	def updateGUI(self):
		self.bar.setValue(self.signal.last)

		self.bar.setProperty('pass', self.passfail.last)
		self.bar.style().polish(self.bar)
		
		if self.auto_mode:
			self.slider.setValue(self.threshold)

			#print type(self.threshold), self.threshold, self.nameano

	def process(self):
		assert self.input.new_samples == 1

		avg_period_samples = int(self.average_period * self.FS)

		avg = sum(self.input.buffer[-avg_period_samples:]) / avg_period_samples
		self.signal.append([avg])
		self.signal.process()



		self.calc_cnt += 1
		if self.auto_mode and self.calc_cnt >= avg_period_samples:
			self.calc_cnt = 0

			if self.mode == 'decrease':
				self.threshold = np.percentile(self.signal.buffer, self.auto_target)
			elif self.mode == 'increase':
				self.threshold = np.percentile(self.signal.buffer, 100 - self.auto_target)
			else:
				self.high_threshold = np.percentile(self.signal.buffer, self.high_target)
				self.threshold = np.percentile(self.signal.buffer, 100 - self.low_target)

		success = False

		if self.mode == 'decrease':
			if avg < self.threshold:
				success = True
		elif self.mode == 'increase':
			if avg > self.threshold:
				success = True
		else:
			if avg > self.threshold and avg < self.high_threshold:
				success = True

		self.passfail.append([success])
		self.passfail.process()
Example #22
0
class Threshold(Block):
    input = Input()

    average_period = Float(0.35)
    epoch = Float(3.0)

    auto_mode = Bool(True)
    mode = Enum('increase', 'decrease', 'range')

    auto_target = Float(0.90)

    low_target = Float(0.90)
    high_target = Float(0.90)

    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 widget(self):
        return self._widget

        w = QtGui.QGroupBox()
        w.setTitle(self.name)

        l = QtGui.QGridLayout()
        l.addWidget(self.bar, 0, 0)
        l.addWidget(self.slider, 0, 1)

        l.addWidget(self.button, 1, 0, 1, 2)

        w.setLayout(l)
        w.block = self

        return w

    def updateGUI(self):
        self._widget.update()
        return
        self.bar.setValue(self.signal.last)

        self.bar.setProperty('pass', self.passfail.last)
        self.bar.style().polish(self.bar)

        if self.auto_mode:
            self.slider.setValue(self.threshold)

            #print type(self.threshold), self.threshold, self.nameano

    def process(self):
        assert self.input.new_samples == 1

        avg_period_samples = int(self.average_period * self.FS)

        avg = sum(self.input.buffer[-avg_period_samples:]) / avg_period_samples
        self.signal.append([avg])
        self.signal.process()

        self.calc_cnt += 1
        if self.auto_mode and self.calc_cnt >= avg_period_samples:
            self.calc_cnt = 0

            if self.mode == 'decrease':
                self.threshold = np.percentile(self.signal.buffer,
                                               100 * self.auto_target)
            elif self.mode == 'increase':
                self.threshold = np.percentile(self.signal.buffer,
                                               100 - 100 * self.auto_target)
            else:
                self.high_threshold = np.percentile(self.signal.buffer,
                                                    self.high_target)
                self.threshold = np.percentile(self.signal.buffer,
                                               100 - 100 * self.low_target)

        success = False

        self.ratio.append([avg / self.threshold])
        self.ratio.process()

        if self.mode == 'decrease':
            if avg < self.threshold:
                success = True
        elif self.mode == 'increase':
            if avg > self.threshold:
                success = True
        else:
            if avg > self.threshold and avg < self.high_threshold:
                success = True

        self.passfail.append([float(success)])
        self.passfail.process()
Example #23
0
class NotchFilter(Block):
	input = Input()

	frequency = Float(50.0)
	notchWidth = Float(0.1)

	nyquist = Float(125.0)

	@on_trait_change("frequency,notchWidth")
	def compute_filter(self):
		freqRatio = self.frequency / self.nyquist
		print self.frequency, self.nyquist, freqRatio
		print type(self.frequency), type(self.nyquist), type(freqRatio)

		wn = freqRatio
		r = 0.1
		B, A = np.zeros(3), np.zeros(3)
		A[0],A[1],A[2] = 1.0, -2.0*r*np.cos(2*np.pi*wn), r*r
		B[0],B[1],B[2] = 1.0, -2.0*np.cos(2*np.pi*wn), 1.0


		self._filter_b = B
		self._filter_a = A

		#%Compute zeros
		#zeros = np.array([np.exp(0+1j *np.pi*freqRatio ), np.exp( 0-1j*np.pi*freqRatio )])

		#%Compute poles
		#poles = (1-self.notchWidth) * zeros

		#self._filter_b = np.poly( zeros ) # Get moving average filter coefficients
		#self._filter_a = np.poly( poles ) # Get autoregressive filter coefficients

		self._filter_b, self._filter_a = iirfilter(4, (45. / self.nyquist, 55. / self.nyquist), 'bandstop')


	def init(self, input):
		self.input = input

		self.output = Signal()

		self.compute_filter()


	def process(self):
		buffer = self.input.buffer
		filt = lfilter(self._filter_b, self._filter_a, buffer)
		self.output.append(filt[-1:])
		self.output.process()

		#fft = np.fft.fft(self.input.buffer[-256:] * np.hanning(256))
		#fft[90:110] = 0
		#fft[120:140] = 0
		#fft[100:200] = 0
		#ifft = np.fft.ifft(fft)

		#self.output.append([self.input.buffer[-1]])
		#self.output.append(np.real(ifft[-1:]))
		#self.output.process()


	@property
	def range(self):
		return self.lo, self.hi
Example #24
0
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