# device_controller.py import threading, queue, time, math, os, csv, statistics RAW_SAMPLE_RATE = 100_000.0 # M1K nominal CHUNK_RAW = 2000 # ~20 ms pro Chunk pro Gerät OUTDIR = "./logs" class DeviceController: def __init__(self, session_manager, dev, effective_rate_hz=10_000): self.sm = session_manager self.dev = dev self.serial = getattr(dev, "serial", "UNKNOWN") # ---- Decimation berechnen ---- # z.B. effective_rate_hz=10_000 -> DECIM=10 -> effektiv 10 kS/s self.decim = max(1, int(round(RAW_SAMPLE_RATE / float(effective_rate_hz)))) self.eff_rate = RAW_SAMPLE_RATE / self.decim self.dt = 1.0 / self.eff_rate self.cmdq = queue.Queue() # größere Queue; wenn voll, verwerfen wir älteste Chunks ("Ringpuffer") self.writer_q = queue.Queue(maxsize=400) self.stop_evt = threading.Event() self.running = False self.reader_t = threading.Thread(target=self.reader_loop, daemon=True) self.writer_t = threading.Thread(target=self.writer_loop, daemon=True) def start(self): if not self.reader_t.is_alive(): self.reader_t.start() if not self.writer_t.is_alive(): self.writer_t.start() self.cmdq.put(("start", None)) def stop(self): self.cmdq.put(("stop", None)) def set_mode(self, ch, mode): key = {0:"A",1:"B"}.get(ch, str(ch).upper()) self.dev.channels[key].mode = mode # -------- Reader: liest roh und decimiert -------- def reader_loop(self): filter_window_size = 10 # wie in deinem Logger interval = 0.1 # 10 Hz Mess-Update last_log_time = 0 while not self.stop_evt.is_set(): # Start/Stop Kommandos try: cmd, _ = self.cmdq.get_nowait() if cmd == "start" and not self.running: self.sm.start() self.running = True elif cmd == "stop" and self.running: self.sm.stop() self.running = False except queue.Empty: pass if not self.running: time.sleep(0.05) continue try: # Rohdaten holen (filter_window_size Samples) samples = self.dev.read(filter_window_size, -1) if not samples: time.sleep(interval) continue # Kanäle extrahieren & mitteln va = statistics.mean(row[0] for row in samples) vb = statistics.mean(row[2] for row in samples) now = time.time() if now - last_log_time >= 1.0: # nur jede Sekunde loggen self.writer_q.put((now, va, vb)) last_log_time = now except Exception as e: print(f"[{self.serial}] Read-Fehler: {e}") time.sleep(0.01) # Loop-Rate steuern time.sleep(max(0.05, interval)) # -------- Writer: Wide-Format, effektive Zeitachse -------- def writer_loop(self): os.makedirs(OUTDIR, exist_ok=True) fn = os.path.join(OUTDIR, f"{time.strftime('%Y%m%d_%H%M%S')}_{self.serial}.csv") print(f"[{self.serial}] Writer -> {fn}") try: with open(fn, "w", newline="") as f: w = csv.writer(f) w.writerow(["timestamp", "A", "B"]) while not (self.stop_evt.is_set() and self.writer_q.empty()): try: ts, va, vb = self.writer_q.get(timeout=0.5) except queue.Empty: continue w.writerow([ts, va, vb]) f.flush() except Exception as e: print(f"[{self.serial}] Writer-Fehler: {e}") finally: print(f"[{self.serial}] Writer beendet: {fn}")