summaryrefslogtreecommitdiff
path: root/core/acquisition.py
diff options
context:
space:
mode:
Diffstat (limited to 'core/acquisition.py')
-rw-r--r--core/acquisition.py83
1 files changed, 25 insertions, 58 deletions
diff --git a/core/acquisition.py b/core/acquisition.py
index 640e6d5..afccb56 100644
--- a/core/acquisition.py
+++ b/core/acquisition.py
@@ -3,7 +3,7 @@ core/acquisition.py
Background acquisition engine.
Polls all connected devices, buffers data, fires Qt signals,
-writes CSV logs, and checks alarm thresholds.
+and writes CSV logs.
"""
import csv
@@ -18,7 +18,7 @@ from PyQt6.QtCore import QObject, pyqtSignal
from devices.base_device import BaseDevice, DeviceStatus
-MAX_BUFFER = 20_000 # samples per channel
+MAX_BUFFER = 20_000
class ChannelBuffer:
@@ -33,7 +33,6 @@ class ChannelBuffer:
self.values.append(v)
def window(self, seconds: float) -> Tuple[List[float], List[float]]:
- """Return the last `seconds` worth of data."""
if not self.times:
return [], []
cutoff = self.times[-1] - seconds
@@ -63,35 +62,29 @@ class AcquisitionEngine(QObject):
Signals
-------
new_data(device_id, channel_id, timestamp, value)
- alarm_triggered(device_id, channel_id, value, kind) kind: "low"|"high"
device_status_changed(device_id, status_str)
log_started(filepath)
log_stopped(filepath)
"""
- new_data = pyqtSignal(str, str, float, float)
- alarm_triggered = pyqtSignal(str, str, float, str)
- device_status_changed = pyqtSignal(str, str)
- log_started = pyqtSignal(str)
- log_stopped = pyqtSignal(str)
+ new_data = pyqtSignal(str, str, float, float)
+ device_status_changed = pyqtSignal(str, str)
+ log_started = pyqtSignal(str)
+ log_stopped = pyqtSignal(str)
def __init__(self, poll_interval_ms: int = 100):
super().__init__()
self._interval = poll_interval_ms / 1000.0
- self._devices: List[BaseDevice] = []
- self._buffers: Dict[str, Dict[str, ChannelBuffer]] = {}
- self._running = False
- self._thread: Optional[threading.Thread] = None
- self._t0 = 0.0
-
- # Logging
- self._logging = False
- self._log_path = ""
- self._csv_file = None
- self._csv_writer = None
-
- # Alarm dedup
- self._alarm_state: Dict[str, bool] = {}
+ self._devices: List[BaseDevice] = []
+ self._buffers: Dict[str, Dict[str, ChannelBuffer]] = {}
+ self._running = False
+ self._thread: Optional[threading.Thread] = None
+ self._t0 = 0.0
+
+ self._logging = False
+ self._log_path = ""
+ self._csv_file = None
+ self._csv_writer = None
# ── Device management ────────────────────────────────────────────────
@@ -128,10 +121,11 @@ class AcquisitionEngine(QObject):
# ── Logging ──────────────────────────────────────────────────────────
def start_logging(self, filepath: str = "") -> str:
- if not filepath:
- os.makedirs("logs", exist_ok=True)
- ts = datetime.now().strftime("%Y%m%d_%H%M%S")
- filepath = f"logs/daq_{ts}.csv"
+ if not filepath or filepath.endswith(os.sep) or filepath.endswith("/"):
+ dir_ = filepath if filepath else "logs"
+ os.makedirs(dir_, exist_ok=True)
+ ts = datetime.now().strftime("%Y%m%d_%H%M%S")
+ filepath = os.path.join(dir_, f"daq_{ts}.csv")
self._log_path = filepath
self._csv_file = open(filepath, "w", newline="")
headers = ["elapsed_s"]
@@ -163,9 +157,9 @@ class AcquisitionEngine(QObject):
def _loop(self):
while self._running:
- t_start = time.time()
- elapsed = t_start - self._t0
- log_row = [f"{elapsed:.4f}"]
+ t_start = time.time()
+ elapsed = t_start - self._t0
+ log_row = [f"{elapsed:.4f}"]
for dev in list(self._devices):
active = dev.status in (DeviceStatus.CONNECTED, DeviceStatus.SIMULATED)
@@ -180,15 +174,11 @@ class AcquisitionEngine(QObject):
if val is None:
log_row.append("")
continue
- # Buffer
buf = self._buffers.get(dev.info.device_id, {}).get(ch.channel_id)
if buf is not None:
buf.append(elapsed, float(val))
- # Signal
self.new_data.emit(dev.info.device_id, ch.channel_id, elapsed, float(val))
log_row.append(f"{val:.5f}")
- # Alarms
- self._check_alarm(dev.info.device_id, ch, float(val))
if self._logging and self._csv_writer:
try:
@@ -196,30 +186,7 @@ class AcquisitionEngine(QObject):
except Exception:
pass
- # Sleep remainder of interval
- dt = time.time() - t_start
+ dt = time.time() - t_start
sleep = self._interval - dt
if sleep > 0:
time.sleep(sleep)
-
- # ── Alarm logic ───────────────────────────────────────────────────────
-
- def _check_alarm(self, device_id: str, ch, val: float):
- lo_key = f"{device_id}.{ch.channel_id}.lo"
- hi_key = f"{device_id}.{ch.channel_id}.hi"
-
- if ch.alarm_low is not None:
- if val < ch.alarm_low:
- if not self._alarm_state.get(lo_key):
- self._alarm_state[lo_key] = True
- self.alarm_triggered.emit(device_id, ch.channel_id, val, "low")
- else:
- self._alarm_state[lo_key] = False
-
- if ch.alarm_high is not None:
- if val > ch.alarm_high:
- if not self._alarm_state.get(hi_key):
- self._alarm_state[hi_key] = True
- self.alarm_triggered.emit(device_id, ch.channel_id, val, "high")
- else:
- self._alarm_state[hi_key] = False