Source code for myogen.simulator.neuron.proprioception.golgi
"""
Golgi Tendon Organ (GTO) Model API Wrapper
This module provides a clean API wrapper for the Golgi Tendon Organ model,
allowing for intuitive parameter names while maintaining compatibility
with the underlying GTO implementation.
"""
from typing import Any, Dict
import numpy as np
from myogen.simulator.neuron._cython._gto import _GolgiTendonOrgan__Cython
from myogen.utils.decorators import beartowertype
from myogen.utils.types import Quantity__ms
[docs]
@beartowertype
class GolgiTendonOrganModel:
"""
API wrapper for the Golgi Tendon Organ (GTO) model.
This class provides an intuitive interface for creating GTO models
with user-friendly parameter names that are internally mapped to the
correct format expected by the underlying GTO implementation.
The Golgi Tendon Organ is a proprioceptive sensory organ located at the
muscle-tendon junction that detects muscle force/tension and provides
feedback for motor control and protection against excessive forces.
The model is based on Lin & Crago (2002) and implements a logarithmic
force-to-firing relationship with digital filtering for realistic
afferent discharge patterns.
Parameters
----------
simulation_time__ms : Quantity__ms
Total simulation time in milliseconds
time_step__ms : Quantity__ms
Integration time step in milliseconds
gto_parameters : Dict[str, Any]
Dictionary containing GTO model parameters
"""
[docs]
def __init__(
self,
simulation_time__ms: Quantity__ms,
time_step__ms: Quantity__ms,
gto_parameters: Dict[str, Any],
):
# Store original parameters (immutable)
self.simulation_time__ms = simulation_time__ms
self.time_step__ms = time_step__ms
self.gto_parameters = gto_parameters.copy()
# Private working copies for internal use
self._simulation_time__ms = simulation_time__ms
self._time_step__ms = time_step__ms
self._gto_parameters = gto_parameters.copy()
# Validate inputs
self._validate_parameters()
# Create the underlying GTO model
self._gto_model = self._create_gto_model()
def _validate_parameters(self) -> None:
"""Validate input parameters."""
if self._simulation_time__ms <= 0:
raise ValueError("simulation_time__ms must be positive")
if self._time_step__ms <= 0:
raise ValueError("time_step__ms must be positive")
if self._simulation_time__ms <= self._time_step__ms:
raise ValueError("simulation_time__ms must be greater than time_step__ms")
def _create_gto_model(self) -> _GolgiTendonOrgan__Cython:
"""
Create the underlying GTO model instance.
This method maps the user-friendly parameter names to the format
expected by the GTO cython constructor.
"""
return _GolgiTendonOrgan__Cython(
gtoD=self._gto_parameters,
tstop__ms=self._simulation_time__ms.magnitude,
dt__ms=self._time_step__ms.magnitude,
)
[docs]
def integrate(self, muscle_force__N: float) -> float:
"""
Integrate the GTO model for one time step.
Parameters
----------
muscle_force__N : float
Current muscle force in Newtons
Returns
-------
float
Ib afferent firing rate in Hz
"""
return self._gto_model.integrate(muscle_force__N)
@property
def ib_afferent_firing__Hz(self) -> np.ndarray:
"""Get Ib afferent firing rate time series in Hz."""
return np.asarray(self._gto_model.Ib)
def __repr__(self) -> str:
"""String representation of the GTO model."""
return (
f"GolgiTendonOrganModel(t_sim={self.simulation_time__ms}ms, dt={self.time_step__ms}ms)"
)
[docs]
@staticmethod
def create_default_gto_parameters() -> Dict[str, Any]:
"""
Create default Golgi Tendon Organ parameter dictionary.
The GTO model uses a logarithmic force-to-firing relationship:
firing_rate = G1 * log(force/G2 + 1)
This is followed by digital filtering to create realistic temporal
dynamics in the afferent discharge pattern.
Returns
-------
Dict[str, Any]
Dictionary of GTO parameters with detailed explanations
Notes
-----
Model based on:
- Lin & Crago (2002): Mathematical model framework
- Aniss et al. (1990b): Human GTO physiological data
- Elias PhD thesis (pg 83): Implementation details
The logarithmic relationship captures the GTO's ability to encode
force over a wide dynamic range, from threshold detection of small
forces to saturation at high forces, providing force feedback for
motor control and protective reflexes.
"""
return {
# Force-to-firing relationship parameters
# Firing rate [Hz] = G1 * log(force[N]/G2 + 1)
"G1": 40, # Logarithmic gain coefficient [Hz]
# Controls the sensitivity of force-to-firing conversion
# Higher G1 = more sensitive to force changes
# Typical range: 30-60 Hz for different muscles
# Source: Lin & Crago (2002), Elias thesis uses 40 Hz
"G2": 4, # Force scaling coefficient [N]
# Sets the force level for logarithmic scaling
# Lower G2 = more sensitive to low forces
# Higher G2 = requires higher forces for activation
# Typical range: 2-8 N depending on muscle strength
# Source: Calibrated for human muscle force ranges
}
[docs]
@staticmethod
def create_gto_parameters_for_muscle(muscle_type: str = "FDI") -> Dict[str, Any]:
"""
Create GTO parameters optimized for specific muscle types.
Parameters
----------
muscle_type : str, optional
Type of muscle ("FDI", "Sol", "generic"), by default "FDI"
Returns
-------
Dict[str, Any]
Dictionary of muscle-specific GTO parameters
Notes
-----
Different muscles have different force production capabilities
and thus require different GTO sensitivity parameters:
- FDI (First Dorsal Interosseous): Small hand muscle, low forces
- Sol (Soleus): Large calf muscle, high forces
- Generic: General-purpose parameters
"""
if muscle_type == "FDI":
# Small hand muscle - more sensitive to small forces
return {
"G1": 45, # Higher sensitivity for small force detection
"G2": 2, # Lower threshold for activation at small forces
}
elif muscle_type == "Sol":
# Large calf muscle - less sensitive, handles high forces
return {
"G1": 35, # Lower sensitivity appropriate for large forces
"G2": 8, # Higher threshold matching muscle's force capacity
}
elif muscle_type == "generic":
# General-purpose parameters
return create_default_gto_parameters()
else:
raise ValueError(f"Unknown muscle type: {muscle_type}. Use 'FDI', 'Sol', or 'generic'.")