opsecsystems commited on
Commit
3fa1fc6
Β·
verified Β·
1 Parent(s): 8b1e87d

Upload openbci_impedance.py

Browse files
Files changed (1) hide show
  1. openbci_impedance.py +26 -17
openbci_impedance.py CHANGED
@@ -51,7 +51,7 @@ SCALE_UV = (ADS1299_VREF / ADS1299_GAIN) / (2**23 - 1) * 1_000_000
51
  # Pleine echelle ADS1299 en Β΅V (seuil railing)
52
  ADC_MAX_UV = (2**23 - 1) * SCALE_UV # β‰ˆ 187 500 Β΅V
53
 
54
- LEAD_OFF_FREQ = 31.25 # Hz β€” frΓ©quence exacte ADS1299 (31.25 Hz, pas 31.5)
55
  LEAD_OFF_AMPS = 6e-9 # A
56
  SERIES_RESISTOR = 2200 # Ξ©
57
 
@@ -142,19 +142,15 @@ def parse_packet(data: bytes):
142
  return None
143
  if data[0] != START_BYTE:
144
  return None
145
- stop_byte = data[32]
146
- if (stop_byte & 0xF0) != 0xC0:
147
  return None
148
  sample_num = data[1]
149
- # FIX : stop byte 0xC0 = Cyton packet, 0xC1 = Daisy packet
150
- # C'est le nibble bas qui indique la source, PAS la paritΓ© du sample_num
151
- is_daisy = (stop_byte & 0x0F) == 0x01
152
  channels_uv = []
153
  for ch in range(8):
154
  offset = 2 + ch * 3
155
  raw = parse_24bit_signed(data[offset], data[offset+1], data[offset+2])
156
  channels_uv.append(raw * SCALE_UV)
157
- return sample_num, channels_uv, is_daisy
158
 
159
 
160
  # ╔══════════════════════════════════════════════════╗
@@ -186,7 +182,7 @@ def _make_bandpass_sos(low_hz: float, high_hz: float, order: int = 4,
186
  # Pre-calculer les filtres une seule fois
187
  # Californie = reseau 60 Hz uniquement (pas de 50 Hz)
188
  _NOTCH_60_SOS = _make_notch_sos(60.0)
189
- _BANDPASS_SOS = _make_bandpass_sos(30.5, 32.0) # FIX : bande Γ©troite Β±0.75 Hz autour de 31.25 Hz
190
 
191
 
192
  # ╔══════════════════════════════════════════════════╗
@@ -257,6 +253,8 @@ class CytonDaisyBoard:
257
 
258
  self._buf_size = SAMPLE_RATE * 4
259
  self._buffers = [deque(maxlen=self._buf_size) for _ in range(N_CHANNELS)]
 
 
260
  self._rx_thread = None
261
 
262
  def connect(self):
@@ -421,17 +419,28 @@ class CytonDaisyBoard:
421
  print(f"[Board] Erreur lecture : {e}")
422
  time.sleep(0.005)
423
 
424
- def _handle_sample(self, sample_num: int, ch_data_uv: list, is_daisy: bool):
425
- # FIX : on utilise le flag is_daisy du stop byte, pas la paritΓ© du sample_num
 
 
426
  with self._lock:
427
- if not is_daisy:
428
- # Packet Cyton β†’ canaux 0-7, on stocke directement
429
- for i in range(8):
430
- self._buffers[i].append(ch_data_uv[i])
431
  else:
432
- # Packet Daisy β†’ canaux 8-15
433
- for i in range(8):
434
- self._buffers[8 + i].append(ch_data_uv[i])
 
 
 
 
 
 
 
 
 
 
435
 
436
  def get_impedances(self) -> list:
437
  with self._lock:
 
51
  # Pleine echelle ADS1299 en Β΅V (seuil railing)
52
  ADC_MAX_UV = (2**23 - 1) * SCALE_UV # β‰ˆ 187 500 Β΅V
53
 
54
+ LEAD_OFF_FREQ = 31.25 # Hz β€” frΓ©quence exacte ADS1299
55
  LEAD_OFF_AMPS = 6e-9 # A
56
  SERIES_RESISTOR = 2200 # Ξ©
57
 
 
142
  return None
143
  if data[0] != START_BYTE:
144
  return None
145
+ if (data[32] & 0xF0) != 0xC0:
 
146
  return None
147
  sample_num = data[1]
 
 
 
148
  channels_uv = []
149
  for ch in range(8):
150
  offset = 2 + ch * 3
151
  raw = parse_24bit_signed(data[offset], data[offset+1], data[offset+2])
152
  channels_uv.append(raw * SCALE_UV)
153
+ return sample_num, channels_uv
154
 
155
 
156
  # ╔══════════════════════════════════════════════════╗
 
182
  # Pre-calculer les filtres une seule fois
183
  # Californie = reseau 60 Hz uniquement (pas de 50 Hz)
184
  _NOTCH_60_SOS = _make_notch_sos(60.0)
185
+ _BANDPASS_SOS = _make_bandpass_sos(30.5, 32.0) # bande Γ©troite Β±0.75 Hz autour de 31.25 Hz
186
 
187
 
188
  # ╔══════════════════════════════════════════════════╗
 
253
 
254
  self._buf_size = SAMPLE_RATE * 4
255
  self._buffers = [deque(maxlen=self._buf_size) for _ in range(N_CHANNELS)]
256
+ self._last_cyton_data = None
257
+ self._last_cyton_snum = None
258
  self._rx_thread = None
259
 
260
  def connect(self):
 
419
  print(f"[Board] Erreur lecture : {e}")
420
  time.sleep(0.005)
421
 
422
+ def _handle_sample(self, sample_num: int, ch_data_uv: list):
423
+ # Protocole OpenBCI Cyton+Daisy : odd sample_num = Cyton, even = Daisy
424
+ # Ref: https://docs.openbci.com/Cyton/CytonDataFormat/
425
+ is_cyton = (sample_num % 2) == 1
426
  with self._lock:
427
+ if is_cyton:
428
+ self._last_cyton_data = ch_data_uv[:]
429
+ self._last_cyton_snum = sample_num
 
430
  else:
431
+ # VΓ©rification de cohΓ©rence : le sample Daisy doit suivre
432
+ # immΓ©diatement le sample Cyton (sample_num = last_cyton + 1)
433
+ if self._last_cyton_data is not None:
434
+ expected = (self._last_cyton_snum + 1) % 256
435
+ if sample_num != expected:
436
+ # DΓ©synchronisation β€” on jette ce couple et on repart
437
+ self._last_cyton_data = None
438
+ return
439
+ for i in range(8):
440
+ self._buffers[i].append(self._last_cyton_data[i])
441
+ for i in range(8):
442
+ self._buffers[8 + i].append(ch_data_uv[i])
443
+ self._last_cyton_data = None
444
 
445
  def get_impedances(self) -> list:
446
  with self._lock: