Skip to content

Robotics — CPG + Swarm Coupling

Spiking neural network primitives for robotic control: central pattern generation for locomotion and multi-agent spike-based swarm synchronization.

StochasticCPG — Central Pattern Generator

Two mutually inhibiting HomeostaticLIFNeuron instances produce rhythmic alternating spike outputs (e.g., left/right leg stepping). The mutual inhibition ensures anti-phase firing: when neuron 1 fires, its spike trace suppresses neuron 2 via inhibitory current, and vice versa.

Parameter Default Meaning
drive_current 2.0 Tonic excitatory input to both neurons
inhibition_weight 2.0 Strength of mutual inhibition

The step() method returns a (spike1, spike2) tuple on each timestep. The adaptation rate (0.1) and target rate (0.3) of the homeostatic neurons control oscillation frequency.

SwarmCoupling — Multi-Agent Synchronization

Synchronizes two SCLearningLayer agents by shifting their weights toward each other via Hebbian cross-correlation: W_a += α * (W_b - W_a), W_b -= α * (W_b - W_a). After sufficient synchronization steps, both agents converge to identical weight configurations.

Parameter Default Meaning
coupling_strength 0.1 Fraction of weight difference applied per step

Both agents must have the same neuron count (raises ValueError otherwise).

Usage

Python
from sc_neurocore.robotics import StochasticCPG, SwarmCoupling

# Locomotion CPG
cpg = StochasticCPG(drive_current=2.0, inhibition_weight=2.0)
left_steps, right_steps = [], []
for _ in range(500):
    s1, s2 = cpg.step()
    left_steps.append(s1)
    right_steps.append(s2)
print(f"Left spikes: {sum(left_steps)}, Right spikes: {sum(right_steps)}")

# Swarm synchronization
from sc_neurocore.layers.sc_learning_layer import SCLearningLayer
agent_a = SCLearningLayer(n_inputs=8, n_neurons=4)
agent_b = SCLearningLayer(n_inputs=8, n_neurons=4)
coupler = SwarmCoupling(coupling_strength=0.3)
for _ in range(20):
    coupler.synchronize(agent_a, agent_b)
# Weights now converged

sc_neurocore.robotics

sc_neurocore.robotics -- Tier: research (experimental / research).

StochasticCPG dataclass

Central Pattern Generator using two mutually inhibiting neurons. Generates rhythmic alternating outputs (e.g., Left/Right leg).

Source code in src/sc_neurocore/robotics/cpg.py
Python
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
44
45
46
47
48
49
50
@dataclass
class StochasticCPG:
    """
    Central Pattern Generator using two mutually inhibiting neurons.
    Generates rhythmic alternating outputs (e.g., Left/Right leg).
    """

    drive_current: float = 2.0
    inhibition_weight: float = 2.0

    def __post_init__(self) -> None:
        # High adaptation rate to force switching
        self.n1 = HomeostaticLIFNeuron(v_threshold=1.0, adaptation_rate=0.1, target_rate=0.3)
        self.n2 = HomeostaticLIFNeuron(v_threshold=1.0, adaptation_rate=0.1, target_rate=0.3)

        self.s1_trace = 0.0
        self.s2_trace = 0.05  # Small asymmetry to break initial symmetry
        self.decay = 0.8

    def step(self) -> tuple[int, int]:
        # Inhibition logic:
        # Input to N1 = Drive - Weight * N2_Activity
        # Input to N2 = Drive - Weight * N1_Activity

        # We use a trace of spikes for inhibition "potential"
        i1 = self.drive_current - self.inhibition_weight * self.s2_trace
        i2 = self.drive_current - self.inhibition_weight * self.s1_trace

        spike1 = self.n1.step(i1)
        spike2 = self.n2.step(i2)

        # Update traces
        self.s1_trace = self.s1_trace * self.decay + spike1
        self.s2_trace = self.s2_trace * self.decay + spike2

        return spike1, spike2

SwarmCoupling dataclass

Brain-to-Brain coupling for SC Networks (Swarm Intelligence). Synchronizes two agents via mutual spike injection.

Source code in src/sc_neurocore/robotics/swarm.py
Python
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@dataclass
class SwarmCoupling:
    """
    Brain-to-Brain coupling for SC Networks (Swarm Intelligence).
    Synchronizes two agents via mutual spike injection.
    """

    coupling_strength: float = 0.1

    def synchronize(self, agent_a: SCLearningLayer, agent_b: SCLearningLayer) -> None:
        """
        Adjust weights of both agents to align their firing patterns.
        (Simplified: Hebbian cross-correlation update)
        """
        # We assume both agents have same number of neurons
        if agent_a.n_neurons != agent_b.n_neurons:
            raise ValueError("Agents must have same size for direct coupling.")

        # Extract weights
        wa = agent_a.get_weights()
        wb = agent_b.get_weights()

        # Mutual Attraction: Weights shift toward each other
        # W_new = W + alpha * (W_other - W)
        delta = self.coupling_strength * (wb - wa)

        # Update Agent A
        new_wa = wa + delta
        for i in range(agent_a.n_neurons):
            for j in range(agent_a.n_inputs):
                agent_a.synapses[i][j].update_weight(new_wa[i, j])

        # Update Agent B (Reciprocal)
        new_wb = wb - delta
        for i in range(agent_b.n_neurons):
            for j in range(agent_b.n_inputs):
                agent_b.synapses[i][j].update_weight(new_wb[i, j])

        logger.info(
            "Swarm Synchronization: Shifted weights by magnitude %.6f", np.mean(np.abs(delta))
        )

synchronize(agent_a, agent_b)

Adjust weights of both agents to align their firing patterns. (Simplified: Hebbian cross-correlation update)

Source code in src/sc_neurocore/robotics/swarm.py
Python
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def synchronize(self, agent_a: SCLearningLayer, agent_b: SCLearningLayer) -> None:
    """
    Adjust weights of both agents to align their firing patterns.
    (Simplified: Hebbian cross-correlation update)
    """
    # We assume both agents have same number of neurons
    if agent_a.n_neurons != agent_b.n_neurons:
        raise ValueError("Agents must have same size for direct coupling.")

    # Extract weights
    wa = agent_a.get_weights()
    wb = agent_b.get_weights()

    # Mutual Attraction: Weights shift toward each other
    # W_new = W + alpha * (W_other - W)
    delta = self.coupling_strength * (wb - wa)

    # Update Agent A
    new_wa = wa + delta
    for i in range(agent_a.n_neurons):
        for j in range(agent_a.n_inputs):
            agent_a.synapses[i][j].update_weight(new_wa[i, j])

    # Update Agent B (Reciprocal)
    new_wb = wb - delta
    for i in range(agent_b.n_neurons):
        for j in range(agent_b.n_inputs):
            agent_b.synapses[i][j].update_weight(new_wb[i, j])

    logger.info(
        "Swarm Synchronization: Shifted weights by magnitude %.6f", np.mean(np.abs(delta))
    )