Synthetic Data Generation
This module provides functions for generating synthetic neural data with known ground truth properties.
Experiment Generators
- driada.experiment.synthetic.generators.generate_tuned_selectivity_exp(population, tuning_defaults=None, duration=600, fps=20, baseline_rate=0.05, peak_rate=2.0, decay_time=2.0, calcium_noise=0.02, calcium_amplitude_range=(0.5, 2.0), n_discrete_features=2, event_active_fraction=0.08, event_avg_duration=0.8, skip_prob=0.0, hurst=0.3, seed=None, verbose=True, reconstruct_spikes=None)[source]
Generate synthetic experiment with principled tuning-based selectivity.
Creates neurons with biologically meaningful tuning to various feature types. Each neuron group can respond to one or more features with configurable combination modes (OR/AND).
- Parameters:
Population configuration. Each dict specifies a neuron group with keys:
”name” : str - Group name (e.g., “hd_cells”, “place_cells”)
”count” : int - Number of neurons in this group
”features” : list of str - Feature names this group responds to. Supported: “head_direction” (von Mises), “position_2d” (2D Gaussian), “x”, “y” (1D Gaussian), “speed” (sigmoid), “event_0”/”event_1”/… (binary), “fbm_0”/”fbm_1”/… (FBM continuous).
”combination” : str, optional - How to combine multiple features: “or” (default) or “and”
”tuning_params” : dict, optional - Override default tuning parameters
tuning_defaults (dict, optional) – Override module-level tuning defaults. Keys are feature names, values are dicts with parameter names and values.
duration (float, optional) – Recording duration in seconds. Default: 600.
fps (float, optional) – Sampling rate in Hz. Default: 20.
baseline_rate (float, optional) – Baseline firing rate (spikes/frame). Default: 0.05.
peak_rate (float, optional) – Peak firing rate during selectivity. Default: 2.0.
decay_time (float, optional) – Calcium decay time constant in seconds. Default: 2.0.
calcium_noise (float, optional) – Calcium signal noise standard deviation. Default: 0.02.
calcium_amplitude_range (tuple of float, optional) – Range for calcium event amplitudes (min, max). Default: (0.5, 2.0).
n_discrete_features (int, optional) – Number of discrete event features to generate. Default: 2.
event_active_fraction (float, optional) – Fraction of time each event is active. Default: 0.08.
event_avg_duration (float, optional) – Average event duration in seconds. Default: 0.8.
skip_prob (float, optional) – Probability of skipping an event (for event features). Default: 0.0.
hurst (float, optional) – Hurst parameter for FBM features. Default: 0.3.
seed (int, optional) – Random seed for reproducibility.
verbose (bool, optional) – Print progress messages. Default: True.
reconstruct_spikes (str, optional) – Spike reconstruction method to apply after generating calcium traces. If
None, no spike reconstruction is performed.
- Returns:
exp – DRIADA Experiment object with neural signals and features. Ground truth is accessible via exp.ground_truth containing: - “expected_pairs” : list of (neuron_idx, feature_name) tuples - “neuron_types” : dict mapping neuron_idx to group name - “tuning_parameters” : dict with detailed tuning params per neuron - “population_config” : reference to input population config
- Return type:
Examples
>>> # Minimal example with default parameters >>> population = [ ... {"name": "hd_cells", "count": 4, "features": ["head_direction"]}, ... {"name": "nonselective", "count": 2, "features": []}, ... ] >>> exp = generate_tuned_selectivity_exp(population, duration=60, verbose=False) >>> exp.n_cells 6 >>> len(exp.ground_truth["expected_pairs"]) 4
>>> # Advanced example with custom parameters >>> population = [ ... {"name": "narrow_hd", "count": 2, "features": ["head_direction"], ... "tuning_params": {"kappa": 4.0}}, # Narrower tuning ... {"name": "conjunctive", "count": 2, "features": ["x", "y"], ... "combination": "and"}, # AND combination ... ] >>> exp = generate_tuned_selectivity_exp( ... population, tuning_defaults={"x": {"sigma": 0.3}}, verbose=False ... )
- driada.experiment.generate_synthetic_exp(n_dfeats=20, n_cfeats=20, nneurons=500, seed=0, fps=20, duration=1200, **kwargs)[source]
Generate a synthetic experiment with neurons selective to discrete and continuous features.
This is a convenience wrapper around generate_tuned_selectivity_exp() that provides a simpler API for basic synthetic data. Ground truth is always available via exp.ground_truth.
- Parameters:
n_dfeats (int, optional) – Number of discrete event features. Default: 20.
n_cfeats (int, optional) – Number of continuous FBM features. Default: 20.
nneurons (int, optional) – Total number of neurons. Default: 500.
seed (int, optional) – Random seed for reproducibility. Default: 0.
fps (float, optional) – Frames per second. Default: 20.
duration (int, optional) – Duration of the experiment in seconds. Default: 1200.
**kwargs (dict, optional) – Additional parameters passed to generate_tuned_selectivity_exp. Supported: verbose, baseline_rate, peak_rate, decay_time, calcium_noise, hurst.
- Returns:
exp – Synthetic experiment object with calcium signals. Ground truth accessible via exp.ground_truth.
- Return type:
Examples
>>> exp = generate_synthetic_exp(n_dfeats=10, n_cfeats=10, nneurons=100, verbose=False) >>> exp.n_cells 100 >>> exp.ground_truth is not None True
- driada.experiment.generate_circular_manifold_exp(n_neurons=100, kappa=4.0, step_std=0.1, add_mixed_features=False, seed=None, verbose=True, return_info=False, **kwargs)[source]
Generate complete experiment with circular manifold (head direction cells).
Creates a synthetic experiment with head direction cells arranged on a circular manifold. Neurons have Von Mises tuning curves with uniformly distributed preferred directions.
- Parameters:
n_neurons (int, optional) – Number of neurons. Must be positive. Default is 100.
kappa (float, optional) – Von Mises concentration parameter (tuning width). Higher values give narrower tuning. Must be positive. Typical values: 2-8. Default is 4.0.
step_std (float, optional) – Head direction random walk step size in radians. Must be non-negative. Default is 0.1 (~5.7 degrees).
add_mixed_features (bool, optional) – Whether to add circular_angle MultiTimeSeries with cos/sin representation of head direction. Useful for algorithms that cannot handle circular variables directly. Default is False.
seed (int, optional) – Random seed for reproducibility. Default is None.
verbose (bool, optional) – Print progress messages. Default is True.
return_info (bool, optional) – If True, return additional information dictionary. Default is False.
**kwargs (dict) – Additional parameters from DEFAULT_SYNTHETIC_PARAMS: duration, fps, baseline_rate, peak_rate, firing_noise, decay_time, calcium_noise, amplitude_range.
- Returns:
exp (Experiment) – DRIADA Experiment object containing: - calcium signals as main data - static features: fps, decay times, manifold parameters - dynamic features: head_direction (and circular_angle if requested)
info (dict, optional) – Only returned if return_info=True. Contains: - ‘manifold_type’: “circular” - ‘n_neurons’: number of neurons - ‘head_direction’: trajectory array - ‘preferred_directions’: array of preferred directions - ‘firing_rates’: underlying firing rates - ‘parameters’: dict of all generation parameters
- driada.experiment.generate_2d_manifold_exp(n_neurons=100, field_sigma=0.1, step_size=0.02, momentum=0.8, grid_arrangement=True, bounds=(0, 1), seed=None, verbose=True, return_info=False, **kwargs)[source]
Generate complete experiment with 2D spatial manifold (place cells).
Creates a DRIADA Experiment object with synthetic hippocampal place cell data, including calcium imaging signals and behavioral trajectory.
- Parameters:
n_neurons (int, optional) – Number of neurons. Must be positive. Default is 100.
field_sigma (float, optional) – Place field width. Must be positive. Default is 0.1.
step_size (float, optional) – Random walk step size. Must be positive. Default is 0.02.
momentum (float, optional) – Trajectory smoothness factor. Must be in [0, 1]. Default is 0.8.
grid_arrangement (bool, optional) – If True, arrange place fields in grid. Default is True.
bounds (tuple, optional) – Spatial bounds (min, max). Default is (0, 1).
seed (int, optional) – Random seed for reproducibility.
verbose (bool, optional) – Print progress messages. Default is True.
return_info (bool, optional) – If True, return (exp, info) tuple with additional information. Default is False.
**kwargs (dict) – Additional parameters from DEFAULT_SYNTHETIC_PARAMS: duration, fps, baseline_rate, peak_rate, firing_noise, decay_time, calcium_noise, amplitude_range.
- Returns:
exp (Experiment) – DRIADA Experiment object with 2D spatial manifold data.
info (dict, optional) – If return_info=True, dictionary with manifold info including: manifold_type, n_neurons, positions, place_field_centers, firing_rates, and all parameters.
- driada.experiment.generate_mixed_population_exp(n_neurons=100, manifold_fraction=0.6, manifold_type='2d_spatial', n_discrete_features=3, n_continuous_features=3, duration=600, fps=20.0, seed=None, verbose=True, return_info=False, manifold_params=None)[source]
Generate synthetic experiment with mixed population of manifold and feature-selective cells.
This is a convenience wrapper around generate_tuned_selectivity_exp() that provides a simpler API for common mixed population scenarios. Ground truth is always available via exp.ground_truth.
- Parameters:
n_neurons (int) – Total number of neurons in the population. Default: 100.
manifold_fraction (float) – Fraction of neurons that are manifold cells (0.0-1.0). Default: 0.6. Remaining neurons are split between event and FBM cells.
manifold_type (str) – Type of manifold: ‘circular’ (head direction) or ‘2d_spatial’ (place cells). Default: ‘2d_spatial’.
n_discrete_features (int) – Number of discrete event features. Default: 3.
n_continuous_features (int) – Number of continuous FBM features. Default: 3.
duration (float) – Duration of experiment in seconds. Default: 600.
fps (float) – Sampling rate in Hz. Default: 20.0.
seed (int, optional) – Random seed for reproducibility.
verbose (bool) – Print progress messages. Default: True.
return_info (bool) – If True, return (exp, info) tuple for backward compatibility. Ground truth is always available via exp.ground_truth regardless. Default: False.
manifold_params (dict, optional) – Override tuning parameters for manifold cells. Supported keys: - field_sigma: Size of place field (default: 0.15) - baseline_rate: Baseline firing rate (default: 0.05) - peak_rate: Peak firing rate (default: 2.0) - firing_noise: Firing rate noise (default: 0.05) - decay_time: Calcium decay time (default: 2.0) - calcium_noise: Calcium signal noise (default: 0.02)
- Returns:
exp (Experiment) – Experiment object with mixed population. Ground truth accessible via exp.ground_truth containing expected_pairs, tuning_parameters, etc.
info (dict (only if return_info=True)) – Dictionary containing ground_truth for backward compatibility.
Examples
>>> # Generate population with 60% place cells, 40% feature-selective >>> exp = generate_mixed_population_exp( ... n_neurons=50, ... manifold_fraction=0.6, ... manifold_type='2d_spatial', ... verbose=False ... ) >>> exp.n_cells 50 >>> len(exp.ground_truth['expected_pairs']) > 0 True
Signal Generators
- driada.experiment.synthetic.core.generate_pseudo_calcium_signal(events=None, duration=600, sampling_rate=20.0, event_rate=0.2, amplitude_range=(0.5, 2), decay_time=2, noise_std=0.1, seed=None, rise_time=None, kernel='exponential')[source]
Generate a pseudo-calcium imaging signal with configurable dynamics.
Creates a synthetic calcium fluorescence signal that mimics GCaMP-like dynamics with configurable kernel shapes, random event amplitudes, and Gaussian noise.
- Parameters:
events (ndarray or None, optional) – Binary array indicating event occurrences at each time point. If None, events are generated randomly using a Poisson process. When provided, indices directly correspond to sample indices (not time in seconds).
duration (float, default=600) – Total duration of the signal in seconds. Only used if events is None. Must be positive.
sampling_rate (float, default=20.0) – Sampling rate in Hz. Must be positive.
event_rate (float, default=0.2) – Average rate of calcium events per second. Only used if events is None. Must be non-negative.
amplitude_range (tuple of float, default=(0.5, 2)) – (min, max) range for random calcium event amplitudes. Must have min <= max.
decay_time (float, default=2) – Time constant for exponential decay of calcium events in seconds. Typical GCaMP indicators have decay times of 1-2 seconds. Must be positive.
noise_std (float, default=0.1) – Standard deviation of additive Gaussian noise. Must be non-negative.
seed (int, optional) – Random seed for reproducibility. Default is None.
rise_time (float, optional) – Rise time constant in seconds. Only used for ‘double_exponential’ kernel. Default is None, which uses 0.25s (typical for GCaMP indicators).
kernel ({'exponential', 'double_exponential', 'step'}, default='exponential') –
Type of calcium transient kernel:
’exponential’: Simple exponential decay with instantaneous rise. Form: amplitude * exp(-t/decay_time). Fast but less realistic.
’double_exponential’: Physiologically realistic kernel with separate rise and decay phases. Form: (1 - exp(-t/rise)) * exp(-t/decay). Matches real GCaMP dynamics.
’step’: Non-physiological step-like waveform with sharp edges. Useful as negative control for testing model assumptions.
- Returns:
1D array representing the pseudo-calcium signal with shape (n_samples,).
- Return type:
ndarray
- Raises:
ValueError – If duration, sampling_rate, or decay_time <= 0. If event_rate or noise_std < 0. If amplitude_range[0] > amplitude_range[1]. If kernel is not one of the valid options.
Notes
The calcium signal is modeled as a sum of transients triggered at event times, plus additive Gaussian noise. This approximates the dynamics of genetically encoded calcium indicators like GCaMP6.
When events is None: Event times are drawn uniformly in [0, duration) seconds. When events is provided: Non-zero indices are treated as event sample indices.
Multiple overlapping events accumulate additively without saturation modeling.
Examples
>>> # Generate random calcium signal with simple exponential decay >>> signal = generate_pseudo_calcium_signal(duration=100, event_rate=0.5) >>> signal.shape (2000,)
>>> # Generate with realistic double-exponential dynamics >>> signal = generate_pseudo_calcium_signal( ... duration=100, event_rate=0.5, ... kernel='double_exponential', rise_time=0.25 ... )
>>> # Generate from specific spike times >>> spikes = np.zeros(1000) >>> spikes[[100, 200, 300]] = 1 # 3 spike events at sample indices >>> signal = generate_pseudo_calcium_signal(events=spikes)
- driada.experiment.synthetic.core.generate_pseudo_calcium_multisignal(n, events=None, duration=600, sampling_rate=20, event_rate=0.2, amplitude_range=(0.5, 2), decay_time=2, noise_std=0.1, seed=None, rise_time=None, kernel='exponential')[source]
Generate multiple pseudo calcium signals.
- Parameters:
n (int) – Number of neurons. Must be non-negative.
events (ndarray, optional) – Event array of shape (n_neurons, n_timepoints). If provided, must have n_neurons == n. Each row corresponds to one neuron’s event indices.
duration (float, default=600) – Duration in seconds. Only used if events is None.
sampling_rate (float, default=20) – Sampling rate in Hz.
event_rate (float, default=0.2) – Average rate of calcium events per second. Only used if events is None.
amplitude_range (tuple, default=(0.5, 2)) – (min, max) for the amplitude of calcium events.
decay_time (float, default=2) – Time constant for the decay of calcium events in seconds.
noise_std (float, default=0.1) – Standard deviation of the Gaussian noise.
seed (int, optional) – Random seed for reproducibility. Default is None.
rise_time (float, optional) – Rise time constant in seconds. Only used for ‘double_exponential’ kernel. Default is None, which uses 0.25s.
kernel ({'exponential', 'double_exponential', 'step'}, default='exponential') – Type of calcium transient kernel. See generate_pseudo_calcium_signal for details on each kernel type.
- Returns:
Calcium signals of shape (n_neurons, n_timepoints).
- Return type:
ndarray
- Raises:
ValueError – If n < 0. If events is provided with wrong shape.
Notes
This is a convenience wrapper that calls generate_pseudo_calcium_signal for each neuron independently. Each neuron gets independent random events (if events=None) and independent noise.
Examples
>>> # Generate 5 neurons with random events >>> signals = generate_pseudo_calcium_multisignal(5, duration=100) >>> signals.shape (5, 2000)
>>> # Generate with specific events per neuron >>> events = np.random.binomial(1, 0.01, size=(3, 1000)) >>> signals = generate_pseudo_calcium_multisignal(3, events=events)
Usage Examples
Basic Synthetic Data
from driada.experiment import generate_synthetic_exp
# Generate basic synthetic experiment
exp = generate_synthetic_exp(
nneurons=100, # number of neurons
n_dfeats=10, # discrete features
n_cfeats=10, # continuous features
duration=600, # 10 minutes
fps=30, # 30 Hz sampling
seed=42 # For reproducibility
)
print(f"Generated {exp.n_cells} neurons, {exp.n_frames/exp.fps}s recording")
Head Direction Cells (Circular Manifold)
from driada.experiment import generate_circular_manifold_exp
# Generate head direction cell population
exp = generate_circular_manifold_exp(
n_neurons=50,
duration=600,
fps=30,
kappa=4.0, # concentration parameter
noise_std=0.1,
step_std=0.1 # angular velocity noise
)
# Access ground truth data if return_info=True
# exp, info = generate_circular_manifold_exp(..., return_info=True)
# true_angle = info['true_angle']
# preferred_directions = info['preferred_directions']
2D Place Cells
from driada.experiment import generate_2d_manifold_exp
# Generate place cell population
exp = generate_2d_manifold_exp(
n_neurons=50,
duration=60, # 1 minute (for demo)
fps=20,
field_sigma=0.1, # receptive field size
step_size=0.02, # movement step
momentum=0.8, # movement momentum
noise_std=0.15
)
# Access data if return_info=True
# exp, info = generate_2d_manifold_exp(..., return_info=True)
# position = info['position'] # (2, n_frames)
# place_fields = info['place_fields'] # neuron receptive fields
Mixed Selectivity Population
from driada.experiment import generate_mixed_population_exp
# Generate population with mixed selectivity
exp = generate_mixed_population_exp(
n_neurons=100,
manifold_fraction=0.6, # 60% manifold cells
manifold_type="2d_spatial",
n_discrete_features=3,
n_continuous_features=2,
duration=1200,
fps=30
)
# Access info if return_info=True
# exp, info = generate_mixed_population_exp(..., return_info=True)
# manifold_neurons = info['manifold_neurons']
# feature_neurons = info['feature_neurons']
Ground Truth Information
When using return_info=True parameter, synthetic experiments return ground truth data:
# Get ground truth information
exp, info = generate_circular_manifold_exp(
n_neurons=50,
duration=600,
return_info=True
)
# Access ground truth data from info dict
# The exact contents depend on the generator used
Best Practices
Reproducibility: Always set random seed for reproducible results
Realistic Parameters: Use physiologically plausible parameters
Validation: Use ground truth to validate analysis methods
Noise Levels: Start with low noise, increase to test robustness
Duration: Ensure sufficient data for statistical analyses