Skip to content

Commit db7faa5

Browse files
committed
Bump version to 0.8.1 and clean up dependencies
- Remove unused dependencies: pyqt6, noise - Move scipy-stubs to dev dependencies only - Clean up Watanabe examples: remove colloquial references, use proper citation format "Watanabe and Kohn (2015)"
1 parent 533e2ea commit db7faa5

10 files changed

Lines changed: 67 additions & 45 deletions

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.8.1] - 2025-12-28
11+
12+
### Changed
13+
- **Dependencies**: Removed unused dependencies
14+
- Removed `pyqt6` (not used in codebase)
15+
- Moved `scipy-stubs` to dev dependencies only (was duplicated)
16+
1017
## [0.8.0] - 2025-12-28
1118

1219
### Added

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
[![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://nsquaredlab.github.io/MyoGen/)
1010
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
11-
[![Version](https://img.shields.io/badge/version-0.8.0-orange.svg)](https://github.com/NsquaredLab/MyoGen)
11+
[![Version](https://img.shields.io/badge/version-0.8.1-orange.svg)](https://github.com/NsquaredLab/MyoGen)
1212

1313
[Installation](https://nsquaredlab.github.io/MyoGen/#installation)
1414
[Documentation](https://nsquaredlab.github.io/MyoGen/)

examples/03_papers/watanabe/01_compute_baseline_force.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Compute Reference Force with Constant Drive (Watanabe Network)
2+
Compute Reference Force with Constant Drive
33
===============================================================
44
55
This example computes the reference muscle force using constant descending drive.
@@ -10,7 +10,7 @@
1010
1111
- 800 motor neurons
1212
- 400 descending drive neurons
13-
- 30% connectivity (Watanabe specification)
13+
- 30% connectivity
1414
- Constant drive frequency (configurable, default 40 Hz)
1515
- Poisson process (order 1)
1616
@@ -29,7 +29,7 @@
2929
These represent cortical/brainstem input to motor neurons.
3030
``poisson_batch_size=1`` creates order-1 (renewal) Poisson processes.
3131
32-
- :class:`~myogen.simulator.neuron.Network`:
32+
- :class:`~myogen.simulator.Network`:
3333
Container that manages populations and synaptic connections between them.
3434
Supports probabilistic connectivity (``connect()``) and external input (``connect_from_external()``).
3535
@@ -71,7 +71,7 @@
7171
from myogen import RANDOM_GENERATOR
7272
from myogen.simulator import RecruitmentThresholds
7373
from myogen.simulator.core.force.force_model import ForceModel
74-
from myogen.simulator.neuron import Network
74+
from myogen.simulator import Network
7575
from myogen.simulator.neuron.populations import AlphaMN__Pool, DescendingDrive__Pool
7676
from myogen.utils.helper import calculate_firing_rate_statistics
7777
from myogen.utils.nmodl import load_nmodl_mechanisms
@@ -121,7 +121,7 @@
121121
print(f"DD neurons: {N_DD_NEURONS}")
122122
print(f"Connection probability: {DD_CONNECTIVITY:.1%}")
123123
print(f"Drive frequency: {DD_DRIVE_HZ:.1f} Hz (constant)")
124-
print(f"Process type: Poisson (batch size: 1)")
124+
print("Process type: Poisson (batch size: 1)")
125125
print("=" * 60 + "\n")
126126

127127
##############################################################################
@@ -293,7 +293,7 @@
293293
n_active = int(stats["n_active"])
294294

295295
print("Firing Rate Statistics:")
296-
print(f" Active units: {n_active}/{N_MOTOR_UNITS} ({n_active/N_MOTOR_UNITS*100:.1f}%)")
296+
print(f" Active units: {n_active}/{N_MOTOR_UNITS} ({n_active / N_MOTOR_UNITS * 100:.1f}%)")
297297
print(f" Mean firing rate: {fr_mean:.2f} Hz")
298298
print(f" Std deviation: {fr_std:.2f} Hz")
299299
print(f" Coefficient of variation: {fr_std / fr_mean:.3f}\n")
@@ -313,9 +313,9 @@
313313

314314
force_model = ForceModel(
315315
recruitment_thresholds=recruitment_thresholds,
316-
recording_frequency__Hz=2048 * pq.Hz, # Output sampling rate
317-
longest_duration_rise_time__ms=90.0 * pq.ms, # Slowest unit's rise time
318-
contraction_time_range_factor=3, # Ratio of slowest/fastest T
316+
recording_frequency__Hz=2048 * pq.Hz, # Output sampling rate
317+
longest_duration_rise_time__ms=90.0 * pq.ms, # Slowest unit's rise time
318+
contraction_time_range_factor=3, # Ratio of slowest/fastest T
319319
)
320320

321321
# Generate force from spike trains

examples/03_papers/watanabe/02_optimize_oscillating_dc.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"""
2-
Optimize Oscillating DC Offset to Match Reference Force (Watanabe Network)
2+
Optimize Oscillating DC Offset to Match Reference Force
33
===========================================================================
44
55
This example optimizes the DC offset component of an oscillating descending drive to
66
match the reference force produced by constant drive (from script 01).
77
The drive pattern is: `DC_offset + 20*sin(2π*20*t)`.
88
9-
This finds the equivalent of Watanabe's 58 pps value (Phase 3) that produces the same
9+
This finds the equivalent of the original 58 pps value (Phase 3) that produces the same
1010
force as constant drive (Phase 1) when combined with 20 Hz oscillation.
1111
1212
.. note::
@@ -31,7 +31,7 @@
3131
Poisson spike generators driven by time-varying rate: ``DC_offset + amplitude*sin(2πft)``.
3232
The ``integrate()`` method advances the internal Poisson process by one timestep.
3333
34-
- :class:`~myogen.simulator.neuron.Network`:
34+
- :class:`~myogen.simulator.Network`:
3535
Rebuilds the network for each trial with same connectivity parameters (30%).
3636
3737
- :class:`~myogen.simulator.core.force.force_model.ForceModel`:
@@ -41,7 +41,7 @@
4141
4242
**Key Concept**: The oscillation itself contributes to motor neuron activation, so
4343
the DC offset in Phase 3 must be *lower* than the constant drive in Phase 1 to
44-
produce the same mean force. Watanabe found 58 Hz offset vs 65 Hz constant.
44+
produce the same mean force. The original paper found 58 Hz offset vs 65 Hz constant.
4545
4646
**Workflow Position**: Step 2 of 6
4747
@@ -130,8 +130,7 @@
130130

131131
if not reference_file.exists():
132132
raise FileNotFoundError(
133-
f"Reference force not found: {reference_file}\n"
134-
f"Run 01_compute_baseline_force.py first!"
133+
f"Reference force not found: {reference_file}\nRun 01_compute_baseline_force.py first!"
135134
)
136135

137136
with open(reference_file, "r") as f:
@@ -530,5 +529,7 @@ def objective(trial):
530529

531530
print("\n[DONE] DC offset optimization complete!")
532531
print(f"Best DC offset: {best_trial.user_attrs['dc_offset__Hz']:.2f} Hz")
533-
print(f"Original Watanabe: 65 Hz constant → 58 Hz + oscillation (ratio: {58/65:.3f})")
534-
print(f"This implementation: {REFERENCE_DRIVE__HZ:.1f} Hz constant → {best_trial.user_attrs['dc_offset__Hz']:.1f} Hz + oscillation (ratio: {best_trial.user_attrs['dc_offset__Hz']/REFERENCE_DRIVE__HZ:.3f})")
532+
print(f"Original Watanabe: 65 Hz constant → 58 Hz + oscillation (ratio: {58 / 65:.3f})")
533+
print(
534+
f"This implementation: {REFERENCE_DRIVE__HZ:.1f} Hz constant → {best_trial.user_attrs['dc_offset__Hz']:.1f} Hz + oscillation (ratio: {best_trial.user_attrs['dc_offset__Hz'] / REFERENCE_DRIVE__HZ:.3f})"
535+
)

examples/03_papers/watanabe/03_10pct_mvc_simulation.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
"""
2-
Watanabe Spinal Network Simulation with Optimized DC Offset
2+
Spinal Network Simulation with Optimized DC Offset
33
============================================================
44
5-
This example runs the Watanabe et al. (2015) spinal network simulation using:
5+
This example runs the Watanabe and Kohn (2015) spinal network simulation using:
66
- Constant drive (Phase 1) - baseline from script 01
77
- Constant + oscillation (Phase 2) - oscillation added to baseline
88
- Optimized DC + oscillation (Phase 3) - DC offset matches Phase 1 force
99
1010
.. note::
1111
**Simulation Phases** (5 seconds each):
1212
13-
- **Phase 1**: Constant drive (Watanabe baseline, e.g., 40-65 Hz)
13+
- **Phase 1**: Constant drive (baseline, e.g., 40-65 Hz)
1414
- **Phase 2**: Constant + 20*sin(20Hz) (oscillation added to baseline)
1515
- **Phase 3**: Optimized DC + 20*sin(20Hz) (DC offset matches Phase 1 force)
1616
@@ -22,7 +22,7 @@
2222
2323
**Scientific Context**: Demonstrates how shared descending drive creates motor unit
2424
synchronization, while independent noise reduces it. Phase 3 uses lower DC offset than
25-
Phase 1 (like Watanabe's 58 < 65) because oscillation contributes additional activation.
25+
Phase 1 (e.g., 58 < 65) because oscillation contributes additional activation.
2626
2727
**MyoGen Components Used**:
2828
@@ -54,8 +54,8 @@
5454
Essential for 15-second simulations with 800+ neurons.
5555
5656
**Key Concept**: The ratio of shared vs independent input determines motor unit
57-
synchronization. Watanabe showed that 20 Hz cortical oscillations are transmitted
58-
through the spinal network and can be detected in EMG coherence spectra.
57+
synchronization. Watanabe and Kohn (2015) showed that 20 Hz cortical oscillations are
58+
transmitted through the spinal network and can be detected in EMG coherence spectra.
5959
6060
**Workflow Position**: Step 3 of 6
6161
@@ -113,8 +113,7 @@
113113

114114
if not dc_offset_file.exists():
115115
raise FileNotFoundError(
116-
f"Optimized DC offset not found: {dc_offset_file}\n"
117-
f"Run 02_optimize_oscillating_dc.py first!"
116+
f"Optimized DC offset not found: {dc_offset_file}\nRun 02_optimize_oscillating_dc.py first!"
118117
)
119118

120119
with open(dc_offset_file) as f:
@@ -134,7 +133,9 @@
134133
print(" Phase 1: 65 pps")
135134
print(" Phase 2: 65 + 20*sin(20Hz) pps")
136135
print(" Phase 3: 58 + 20*sin(20Hz) pps")
137-
print(f"\nOptimization ratio: {DC_OFFSET_OPTIMIZED/DD_DRIVE_CONSTANT:.3f} (Watanabe: {58/65:.3f})")
136+
print(
137+
f"\nOptimization ratio: {DC_OFFSET_OPTIMIZED / DD_DRIVE_CONSTANT:.3f} (Watanabe: {58 / 65:.3f})"
138+
)
138139
print(f"Current setup uses {DD_DRIVE_CONSTANT:.1f} Hz baseline (configurable in script 11)")
139140
print("=" * 70 + "\n")
140141

@@ -211,8 +212,8 @@
211212
plt.xlabel("Time (s)")
212213
plt.ylabel("DD Drive (Hz)")
213214
plt.title("Descending Drive Pattern (Optimized)")
214-
plt.axvline(segment_duration__s, color='r', linestyle='--', alpha=0.5, label='Phase boundary')
215-
plt.axvline(2*segment_duration__s, color='r', linestyle='--', alpha=0.5)
215+
plt.axvline(segment_duration__s, color="r", linestyle="--", alpha=0.5, label="Phase boundary")
216+
plt.axvline(2 * segment_duration__s, color="r", linestyle="--", alpha=0.5)
216217
plt.legend()
217218
plt.grid()
218219

@@ -352,9 +353,9 @@ def eachStep(
352353
# Creates NetCon objects for external event delivery (e.g., commands).
353354
#
354355
# The ratio of shared (DD) to private (IN) input determines the degree of
355-
# motor unit synchronization - a key parameter in Watanabe's analysis.
356+
# motor unit synchronization - a key parameter in the original analysis.
356357

357-
# DD connectivity: 30% probability (Watanabe specification)
358+
# DD connectivity: 30% probability (original specification)
358359
# This means each motor neuron receives input from ~30% of DD neurons
359360
DD_connectivity = 0.3
360361
expected_DD_per_MN = int(DD_connectivity * nDD) # ~120 connections per MN
@@ -514,4 +515,4 @@ def step_callback(step_counter):
514515
print(f" Spikes: {save_path / 'watanabe_spikes.pkl'}")
515516
print(f"\nPhase 1 constant drive: {DD_DRIVE_CONSTANT:.2f} Hz")
516517
print(f"Phase 3 DC offset: {DC_OFFSET_OPTIMIZED:.2f} Hz (optimized to match Phase 1 force)")
517-
print(f"Ratio: {DC_OFFSET_OPTIMIZED/DD_DRIVE_CONSTANT:.3f} (Watanabe: {58/65:.3f})")
518+
print(f"Ratio: {DC_OFFSET_OPTIMIZED / DD_DRIVE_CONSTANT:.3f} (Watanabe: {58 / 65:.3f})")

examples/03_papers/watanabe/04_load_and_analyze_results.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Load and Analyze Membrane Potentials and Spike Trains
33
======================================================
44
5-
This example demonstrates **post-simulation analysis** of the Watanabe et al. (2015)
5+
This example demonstrates **post-simulation analysis** of the Watanabe and Kohn (2015)
66
spinal network model. It shows how to load chunked simulation data, convert it to
77
NEO format, and analyze membrane potentials, spike trains, and population dynamics.
88
@@ -52,7 +52,7 @@
5252
- ``neo.AnalogSignal``: Continuous data (e.g., membrane potential) with sampling rate
5353
5454
**Use Case**: Analyze motor unit recruitment, synchronization, and firing patterns
55-
to validate model predictions against experimental data from Watanabe et al. (2015).
55+
to validate model predictions against experimental data from Watanabe and Kohn (2015).
5656
5757
**Workflow Position**: Step 4 of 6
5858
@@ -197,8 +197,20 @@
197197

198198
# Highlight the three experimental phases
199199
ax.axvspan(0, phase1_end, alpha=0.2, color=phase_colors[0], label="Phase 1: Constant")
200-
ax.axvspan(phase1_end, phase2_end, alpha=0.2, color=phase_colors[1], label="Phase 2: Sinusoid DC=65")
201-
ax.axvspan(phase2_end, phase3_end, alpha=0.2, color=phase_colors[2], label="Phase 3: Sinusoid DC=58")
200+
ax.axvspan(
201+
phase1_end,
202+
phase2_end,
203+
alpha=0.2,
204+
color=phase_colors[1],
205+
label="Phase 2: Sinusoid DC=65",
206+
)
207+
ax.axvspan(
208+
phase2_end,
209+
phase3_end,
210+
alpha=0.2,
211+
color=phase_colors[2],
212+
label="Phase 3: Sinusoid DC=58",
213+
)
202214

203215
if ax == axes[0]:
204216
ax.legend(loc="upper right", framealpha=1.0, edgecolor="none")
@@ -267,8 +279,12 @@
267279

268280
# Highlight the three experimental phases
269281
ax.axvspan(0, phase1_end, alpha=0.2, color=phase_colors[0], label="Phase 1: Constant")
270-
ax.axvspan(phase1_end, phase2_end, alpha=0.2, color=phase_colors[1], label="Phase 2: Sinusoid DC=65")
271-
ax.axvspan(phase2_end, phase3_end, alpha=0.2, color=phase_colors[2], label="Phase 3: Sinusoid DC=58")
282+
ax.axvspan(
283+
phase1_end, phase2_end, alpha=0.2, color=phase_colors[1], label="Phase 2: Sinusoid DC=65"
284+
)
285+
ax.axvspan(
286+
phase2_end, phase3_end, alpha=0.2, color=phase_colors[2], label="Phase 3: Sinusoid DC=58"
287+
)
272288
ax.legend(loc="upper right", framealpha=1.0, edgecolor="none")
273289

274290
plt.tight_layout()

examples/03_papers/watanabe/05_compute_force_from_spinal_network.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
6161
**Use Case**: Generate realistic muscle force output from motor neuron spike trains
6262
for biomechanical analysis, force-EMG relationship studies, and validation against
63-
experimental force recordings from Watanabe et al. (2015).
63+
experimental force recordings from Watanabe and Kohn (2015).
6464
6565
**Workflow Position**: Step 5 of 6
6666

examples/03_papers/watanabe/06_visualize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Generate Publication-Quality Figures and Analysis Plots
33
========================================================
44
5-
This example generates **publication-quality figures** for the Watanabe et al. (2015)
5+
This example generates **publication-quality figures** for the Watanabe and Kohn (2015)
66
spinal network model reproduction. It creates comprehensive visualizations including
77
coherence analysis, force timeseries, and detailed raster plots.
88

examples/03_papers/watanabe/README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.. _watanabe-reproduction:
22

3-
Watanabe and Kohn (2015)
3+
Watanabe and Kohn (2015)
44
======================
55

66
Reproduces findings from:

pyproject.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "MyoGen"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
description = "Modular and extensible neuromuscular simulation framework for generating physiologically grounded motor-unit activity, muscle force, and EMG signals (surface and intramuscular)"
55
readme = "README.md"
66
requires-python = ">=3.12"
@@ -37,17 +37,14 @@ dependencies = [
3737
"neuron==8.2.7 ; sys_platform == 'linux' or sys_platform == 'darwin'",
3838
#"neuron-gpu-nightly>=9.0a0",
3939
#"neuron-nightly>=9.0a1.dev1492",
40-
"noise>=1.2.2",
4140
"numba>=0.61.2",
4241
"numpy>=1.26,<2.0",
4342
"optuna>=4.5.0",
44-
"pyqt6>=6.9.0",
4543
"quantities>=0.16.2",
4644
"scienceplots>=2.1.1",
4745
"scikit-fmm>=2025.1.29",
4846
"scikit-learn>=1.6.1",
4947
"scipy>=1.15.3",
50-
"scipy-stubs==1.16.1.0",
5148
"seaborn>=0.13.2",
5249
"setuptools>=80.9.0",
5350
"tqdm>=4.67.1",

0 commit comments

Comments
 (0)