For testing and demonstrational purposes it is always good to work with synthetic data. Syncopy brings its own suite of synthetic data generators, but it is also possible to devise your own synthetic data and conveniently analyze it with Syncopy.
To create a synthetic data set follow these steps:
write a function which returns a single trial with desired shape
(nSamples, nChannels), such that each trial is a 2d-
collect all the trials into a Python
list, for example with a list comprehension or simply a for loop
AnalogDataobject by passing this list holding the trials and set the samplerate
In (pseudo-)Python code:
def generate_trial(nSamples, nChannels): trial = .. something fancy .. # These should evaluate to True isinstance(trial, np.ndarray) trial.shape == (nSamples, nChannels) return trial # here we use a list comprehension trial_list = [generate_trial(nSamples, nChannels) for _ in range(nTrials)] my_fancy_data = spy.AnalogData(trial_list, samplerate=my_samplerate)
The same recipe can be used to generally instantiate Syncopy data objects from NumPy arrays.
These generators return single-trial NumPy arrays, so to import them into Syncopy use the General Recipe described above.
- syncopy.tests.synth_data.phase_diffusion(freq, eps=0.1, fs=1000, nChannels=2, nSamples=1000, return_phase=False)¶
Linear (harmonic) phase evolution + a Brownian noise term inducing phase diffusion around the deterministic phase drift with slope
2pi * freq(angular frequency).
The linear phase increments are given by
dPhase = 2pi * freq/fs, the Brownian increments are scaled with eps relative to these phase increments.
freq (float) – Harmonic frequency in Hz
eps (float) – Scaled Brownian increments 1 means the single Wiener step has on average the size of the harmonic increments
fs (float) – Sampling rate in Hz
nChannels (int) – Number of channels
nSamples (int) – Number of samples in time
return_phase (bool, optional) – If set to true returns the phases in radians
phases – Synthetic nSamples x nChannels data array simulating noisy phase evolution/diffusion
- Return type:
- syncopy.tests.synth_data.AR2_network(AdjMat=None, nSamples=1000, alphas=[0.55, - 0.8])¶
Simulation of a network of coupled AR(2) processes
With the default parameters the individual processes (as in Dhamala 2008) have a spectral peak at 40Hz with a sampling frequency of 200Hz.
- NOTE: There is no check for stability: setting the
alphas ad libitum and/or defining large and dense (many connections) systems will almost surely lead to an unstable system
AdjMat (np.ndarray or None) – nChannel x nChannel adjacency matrix where entry
(i,j)is the coupling strength from channel
i -> j. If left at None, the default 2 Channel system with unidirectional
2 -> 1coupling is generated.
nSamples (int, optional) – Number of samples in time
alphas (2-element sequence, optional) – The AR(2) parameters for lag1 and lag2
sol – The nSamples x nChannel solution of the network dynamics
- Return type:
import numpy as np import syncopy as spy def generate_noisy_harmonics(nSamples, nChannels, samplerate): f1, f2 = 20, 50 # the harmonic frequencies in Hz # the sampling times vector tvec = np.arange(nSamples) * 1 / samplerate # define the two harmonics harm1 = np.cos(2 * np.pi * f1 * tvec) harm2 = np.cos(2 * np.pi * f2 * tvec) # add some white noise trial = 0.5 * np.random.randn(nSamples, nChannels) # add 1st harmonic to 1st channel trial[:, 0] += harm1 # add 2nd harmonic to 2nd channel trial[:, 1] += 0.5 * harm2 return trial nTrials = 50 nSamples = 1000 nChannels = 3 samplerate = 500 # in Hz trials =  for _ in range(nTrials): trial = generate_noisy_harmonics(nSamples, nChannels, samplerate) trials.append(trial) synth_data = spy.AnalogData(trials, samplerate=samplerate)
Here we first defined the number of trials and then the number of samples and channels per trial. With a sampling rate of 500Hz and 1000 samples this gives us a trial length of two seconds. The function
generate_noisy_harmonics adds white noise to all channels, a 20Hz harmonic on the 1st channel and a 50Hz harmonic on the 2nd channel. Every trial got collected into a Python
list, which at the last line was used to initialize our
AnalogData object. Note that data instantiated that way always has a default trigger offset of -1 seconds.
Now we can directly run a simple FFT analysis and plot the power spectra of all 3 channels:
spectrum = spy.freqanalysis(synth_data, foilim=[0,80], keeptrials=False) spectrum.singlepanelplot()
As constructed, we have two harmonic peaks at the respective frequencies (20Hz and 50Hz) and the white noise floor on all channels.