File size: 1,396 Bytes
5e0b58b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
"""Pure feature calculations used by the signal interpreter."""

from __future__ import annotations

from collections import Counter
from collections.abc import Iterable

from .models import SpikeSample


def population_rate_hz(
    spikes: Iterable[SpikeSample], *, neuron_count: int, duration_ms: float
) -> float:
    """Return population-averaged firing rate in hertz."""
    if neuron_count <= 0 or duration_ms <= 0.0:
        return 0.0
    spike_count = sum(1 for _ in spikes)
    seconds = duration_ms / 1000.0
    return spike_count / (neuron_count * seconds)


def burst_index(spikes: Iterable[SpikeSample]) -> float:
    """Return a bounded heuristic burst score based on same-tick spike concentration."""
    counts = Counter(sample.tick for sample in spikes)
    total = sum(counts.values())
    if total == 0:
        return 0.0
    peak = max(counts.values(), default=0)
    return min(1.0, peak / total)


def synchrony(spikes: Iterable[SpikeSample], *, neuron_count: int) -> float:
    """Return a bounded same-tick synchrony score for the observed population."""
    if neuron_count <= 0:
        return 0.0
    per_tick: dict[int, set[int]] = {}
    for sample in spikes:
        per_tick.setdefault(sample.tick, set()).add(sample.neuron_id)
    if not per_tick:
        return 0.0
    peak = max(len(ids) for ids in per_tick.values())
    return min(1.0, peak / neuron_count)