Skip to content

Commit

Permalink
updates on calcs, to always get same lengths
Browse files Browse the repository at this point in the history
  • Loading branch information
TomDonoghue committed Jan 20, 2021
1 parent ea275c3 commit 1439d48
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 30 deletions.
9 changes: 4 additions & 5 deletions neurodsp/sim/cycles.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import numpy as np
from scipy.signal import gaussian, sawtooth

from neurodsp.utils.checks import check_param
from neurodsp.utils.data import calc_nsamples
from neurodsp.sim.info import get_sim_func
from neurodsp.utils.checks import check_param
from neurodsp.sim.transients import sim_synaptic_kernel

###################################################################################################
Expand Down Expand Up @@ -128,7 +127,7 @@ def sim_asine_cycle(n_seconds, fs, rdsym):
check_param(rdsym, 'rdsym', [0., 1.])

# Determine number of samples in rise and decay periods
n_samples = calc_nsamples(n_seconds, fs)
n_samples = int(n_seconds * fs)
n_rise = int(np.round(n_samples * rdsym))
n_decay = n_samples - n_rise

Expand Down Expand Up @@ -200,7 +199,7 @@ def sim_gaussian_cycle(n_seconds, fs, std):
>>> cycle = sim_gaussian_cycle(n_seconds=0.2, fs=500, std=0.025)
"""

cycle = gaussian(calc_nsamples(n_seconds, fs), std * fs)
cycle = gaussian(int(n_seconds * fs), std * fs)

return cycle

Expand Down Expand Up @@ -239,7 +238,7 @@ def create_cycle_time(n_seconds, fs):
>>> indices = create_cycle_time(n_seconds=1, fs=500)
"""

return 2 * np.pi * 1 / n_seconds * (np.arange(fs * n_seconds) / fs)
return 2 * np.pi * 1 / n_seconds * (np.arange(int(fs * n_seconds)) / fs)


def phase_shift_cycle(cycle, shift):
Expand Down
53 changes: 36 additions & 17 deletions neurodsp/sim/periodic.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def sim_oscillation(n_seconds, fs, freq, cycle='sine', phase=0, **cycle_params):

# Figure out how many cycles are needed for the signal, & length of each cycle
n_cycles = int(np.ceil(n_seconds * freq))
n_seconds_cycle = int(np.ceil(fs / freq)) / fs
n_seconds_cycle = 1/freq

# Create a single cycle of an oscillation
cycle = sim_cycle(n_seconds_cycle, fs, cycle, **cycle_params)
Expand All @@ -64,8 +64,8 @@ def sim_oscillation(n_seconds, fs, freq, cycle='sine', phase=0, **cycle_params):
sig = np.tile(cycle, n_cycles)

# Truncate the length of the signal to be the number of expected samples
n_samps = int(n_seconds * fs)
sig = sig[:n_samps]
n_samples = int(n_seconds * fs)
sig = sig[:n_samples]

return sig

Expand All @@ -83,12 +83,27 @@ def sim_bursty_oscillation(n_seconds, fs, freq, burst_approach='prob', burst_par
freq : float
Oscillation frequency, in Hz.
burst_approach : {'prob', 'durations'}
xx
Which approach to take for simulating bursts:
- 'prob' : simulate bursts based on probabilities of entering and leaving bursts states.
- 'durations' : simulate bursts based on lenghts of bursts and inter-burst periods.
burst_params : dict
enter_burst : float, optional, default: 0.2
Probability of a cycle being oscillating given the last cycle is not oscillating.
leave_burst : float, optional, default: 0.2
Probability of a cycle not being oscillating given the last cycle is oscillating.
Parameters for the burst approach.
For the `prob` approach:
enter_burst : float, optional, default: 0.2
Probability of a cycle being oscillating given the last cycle is not oscillating.
leave_burst : float, optional, default: 0.2
Probability of a cycle not being oscillating given the last cycle is oscillating.
For the `durations` approach:
n_cycles_burst : int
The number of cycles within each burst.
n_cycles_off
The number of non-bursting cycles, between bursts.
cycle : {'sine', 'asine', 'sawtooth', 'gaussian', 'exp', '2exp'}
What type of oscillation cycle to simulate.
See `sim_cycle` for details on cycle types and parameters.
Expand All @@ -108,19 +123,25 @@ def sim_bursty_oscillation(n_seconds, fs, freq, burst_approach='prob', burst_par
If the cycle length does not fit evenly into the simulated data length,
then the last few samples will be non-oscillating.
By default, this function uses the 'prob' approach.
Examples
--------
Simulate a bursty oscillation, with a low probability of bursting:
Simulate a probabilistic bursty oscillation, with a low probability of bursting:
>>> sig = sim_bursty_oscillation(n_seconds=10, fs=500, freq=5, enter_burst=0.2, leave_burst=0.8)
>>> sig = sim_bursty_oscillation(n_seconds=10, fs=500, freq=5,
... burst_params={'enter_burst' : 0.2, 'leave_burst' : 0.8})
Simulate a bursty oscillation, with a high probability of bursting:
Simulate a probabilistic bursty sawtooth oscillation, with a high probability of bursting:
>>> sig = sim_bursty_oscillation(n_seconds=10, fs=500, freq=5, enter_burst=0.8, leave_burst=0.4)
>>> sig = sim_bursty_oscillation(n_seconds=10, fs=500, freq=5, burst_approach='prob',
... burst_params = {'enter_burst' : 0.8, 'leave_burst' : 0.4},
... cycle='sawtooth', width=0.3)
Simulate a bursty oscillation, of sawtooth waves:
Simulate a bursty oscillation, with specified durations:
>>> sig = sim_bursty_oscillation(n_seconds=10, fs=500, freq=10, cycle='sawtooth', width=0.3)
>>> sig = sim_bursty_oscillation(n_seconds=10, fs=500, freq=10, burst_approach='durations',
... burst_params={'n_cycles_burst' : 3, 'n_cycles_off' : 3})
"""

# Consistency fix: catch old parameters, and remap into burst_params
Expand All @@ -132,7 +153,7 @@ def sim_bursty_oscillation(n_seconds, fs, freq, burst_approach='prob', burst_par

# Determine number of samples & cycles
n_samples = int(n_seconds * fs)
n_seconds_cycle = (1/freq * fs)/fs
n_seconds_cycle = 1/freq

# Grab normalization parameters, if any were provided
mean = cycle_params.pop('mean', 0.)
Expand Down Expand Up @@ -162,8 +183,6 @@ def sim_bursty_oscillation(n_seconds, fs, freq, burst_approach='prob', burst_par

return sig

###################################################################################################
###################################################################################################

def make_is_osc_prob(n_cycles, enter_burst, leave_burst):
"""Create bursting definition, based on probabilistic burst starts and stops.
Expand Down
2 changes: 1 addition & 1 deletion neurodsp/tests/utils/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def test_create_samples():

def test_calc_nsamples():

n_samples = calc_nsamples(1, 100)
n_samples = compute_nsamples(1, 100)
assert isinstance(n_samples, int)
assert n_samples == 100

Expand Down
20 changes: 13 additions & 7 deletions neurodsp/utils/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def create_times(n_seconds, fs, start_val=0.):
Time indices.
"""

return np.arange(start_val, n_seconds + start_val, 1/fs)
return np.linspace(start_val, n_seconds, int(fs * n_seconds)+1)[:-1]


def create_samples(n_samples, start_val=0):
Expand All @@ -53,7 +53,7 @@ def create_samples(n_samples, start_val=0):
Parameters
----------
n_seconds : int
Number of sample.
Signal duration, in seconds.
start_val : int, optional, default: 0
Starting value for the samples definition.
Expand All @@ -66,23 +66,29 @@ def create_samples(n_samples, start_val=0):
return np.arange(start_val, n_samples, 1)


def calc_nsamples(n_seconds, fs):
"""Calculate the number of samples.
def compute_nsamples(n_seconds, fs):
"""Calculate the number of samples for a given time definition.
Parameters
----------
n_seconds : int
Number of sample.
Signal duration, in seconds.
fs : float
Signal sampling rate, in Hz.
Returns
-------
int
The number of samples needed.
The number of samples.
Notes
-----
The result has to be rounded, in order to ensure that the number of samples is a whole number.
The `int` function rounds down, by default, which is the convention across the module.
"""

return int(np.ceil(n_seconds * fs))
return int(n_seconds * fs)


def split_signal(sig, n_samples):
Expand Down

0 comments on commit 1439d48

Please sign in to comment.