Пример #1
0
 def update_rawvalues(self):
     rabbit = RabbitController('localhost', 5672, 'guest', 'guest', '/')
     while not self._stop.is_set():
         self._stop.wait(EMIT_EEGDATA_PERIOD_SECONDS)
         # set state in raw_valceiceilues
         self.raw_values[21] = int(self.state)
         # send to the bus
         print("[ ] EMITTING EEGDATA: %s" % (self.raw_values))
         rabbit.publish_eegdata(self.raw_values)
Пример #2
0
class ThreadingOscUDPServer(socketserver.ThreadingMixIn, OscUDPServer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        signal.signal(signal.SIGINT, self._signal_handler)
        self.rabbit = RabbitController('localhost', 5672, 'guest', 'guest',
                                       '/')
        self.queue = deque(
            maxlen=QUEUE_SIZE
        )  # we only use append, therefore no need in queue.Queue
        self.blink_events = 0  # counter of blink events
        self.state = None
        self.state_last_published = None
        self.levels_advance_upwards = True  # auto advance is moving upwards
        self.raw_values = [0] * 22
        self.lock = Lock()
        self._stop = Event()
        self._timer_thread = None
        self.start_emitting_messages()

    def increment_blink(self):
        with self.lock:
            self.blink_events += 1

    def _signal_handler(self, _, unused_frame):
        self._stop.set()

    def start_emitting_messages(self):
        self.state = 1
        self.rabbit.publish_state(self.state)
        self.state_last_published = datetime.datetime.now()
        Thread(target=self.predict_next_level, daemon=True).start()
        Thread(target=self.update_rawvalues, daemon=True).start()
        Thread(target=self.listen_for_keys, daemon=True).start()
        Thread(target=self.auto_advance_level, daemon=True).start()

    def predict_next_level(self):
        while not self._stop.is_set():
            self._stop.wait(EMIT_STAGE_PERIOD_SECONDS)
            try:
                data = np.array(self.queue, dtype=np.float64)
                model = arima_model.ARIMA(data, order=ARIMA_PARAMS)
                model = model.fit(disp=0)
                forecast = model.predict(start=1, end=20)
            except ValueError:
                print(
                    "Skipping state evaluation due to insufficient amount of data collected."
                )
                return
            data_filtered = data[np.where(
                np.logical_and(np.greater_equal(data, np.percentile(data, 5)),
                               np.less_equal(data, np.percentile(data, 95))))]
            mean_diff = np.mean(forecast) - np.mean(data_filtered)
            # add more logic there considering movement and blinks
            if mean_diff > UPPER_THRESHOLD:
                self.state = min(self.state + 1, 5)
                self.levels_advance_upwards = True  # auto advance up after upward transition
            elif mean_diff < LOWER_THRESHOLD:
                self.state = max(self.state - 1, 1)
                self.levels_advance_upwards = False  # auto advance down after downward transition

            # send to the bus
            print("[ ] EMITTING STATE: %s" % (self.state))
            self.rabbit.publish_state(self.state)
            self.state_last_published = datetime.datetime.now()

            with self.lock:
                self.blink_events = 0

    def update_rawvalues(self):
        while not self._stop.is_set():
            self._stop.wait(EMIT_EEGDATA_PERIOD_SECONDS)
            # set state in raw_valceiceilues
            self.raw_values[21] = int(self.state)
            # send to the bus
            print("[ ] EMITTING EEGDATA: %s" % (self.raw_values))
            self.rabbit.publish_eegdata(self.raw_values)

    def listen_for_keys(self):
        while not self._stop.is_set():
            self._stop.wait(LISTEN_FOR_KEY_SECONDS)
            if msvcrt.kbhit():
                ch = msvcrt.getch()
                if ch:
                    key = ch.decode()
                    if key in ['1', '2', '3', '4', '5']:
                        self.state = int(key)
                        print("[ ] PRESSED KEY '%s', EMITTING STATE: %s" %
                              (key, self.state))
                        self.rabbit.publish_state(self.state)
                        self.state_last_published = datetime.datetime.now()

    def auto_advance_level(self):
        while not self._stop.is_set():
            self._stop.wait(AUTO_ADVANCE_LEVEL_PERIOD_SECONDS)

            # headset is worn if nonzero values exist in the queue
            headset_worn = False
            for value in self.raw_values[0:20]:
                if value > 0:
                    headset_worn = True
                    break

            seconds_since_state_publish = (
                datetime.datetime.now() -
                self.state_last_published).total_seconds()

            should_advance_headset_worn = headset_worn and seconds_since_state_publish > AUTO_ADVANCE_AFTER_SECONDS_WHILE_HEADSET_WORN
            should_advance_headset_off = not headset_worn and seconds_since_state_publish > AUTO_ADVANCE_AFTER_SECONDS_WHILE_HEADSET_OFF

            should_advance = should_advance_headset_worn or should_advance_headset_off

            if should_advance:
                if self.state >= 5:
                    self.levels_advance_upwards = False
                if self.state <= 1:
                    self.levels_advance_upwards = True

                next_state = self.state + 1 if self.levels_advance_upwards else self.state - 1
                self.state = next_state

                advancing_direction = "UPWARDS" if self.levels_advance_upwards else "DOWNWARDS"
                print("[ ] AUTOMATICALLY ADVANCING %s, EMITTING STATE: %s" %
                      (advancing_direction, self.state))
                self.rabbit.publish_state(self.state)
                self.state_last_published = datetime.datetime.now()