Adalm1000_Logger/DeviceController.py
Vincent Hanewinkel 559f512bee fix
2025-08-14 22:40:44 +02:00

106 lines
3.9 KiB
Python

# 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}")