Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review timeseries #144

Merged
merged 70 commits into from
Feb 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
e19ad7b
Adds comments, expands documentation, minor clean-up.
stuart-knock Dec 19, 2017
4b1c943
Reviews Const. Adds explicit links to TIMESERIES functions in file doc.
stuart-knock Dec 19, 2017
7b1413a
Reviews Pulse.
stuart-knock Dec 19, 2017
915c8dd
Uses different variables for different input parameters #138.
stuart-knock Dec 19, 2017
6ea28ae
Replaces explicit loops with vector's assign method. Adds TODO.
stuart-knock Dec 19, 2017
912980c
Bits and pieces while reviewing.
stuart-knock Dec 20, 2017
a9a70f4
Minor clean-up, reorder operations, in init. Adds comments.
stuart-knock Jan 16, 2018
5bc3a69
Converts a few more Node indices from double to size_type.
stuart-knock Jan 16, 2018
a3cf3bd
Renames TIMESERIES::Pulse to TIMESERIES::PulseRect.
stuart-knock Jan 16, 2018
65efdf7
Renames TIMESERIES::Sine() to TIMESERIES::PulseSine().
stuart-knock Jan 16, 2018
74d2aa7
Moves PulseSine to group Pulse* timeseries. Adds doc.
stuart-knock Jan 16, 2018
c61f4ee
Removes redundant duration declaration.
stuart-knock Jan 16, 2018
7f712f9
Uses "Amplitude" consistently as the keyword for amplitudes.
stuart-knock Jan 23, 2018
5beaf67
Adds a simple Sine Timeseries, two args: Amplitude; Frequency.
stuart-knock Jan 23, 2018
e7677fd
Adds a sigmoidal pulse train to TIMESERIES.
stuart-knock Jan 23, 2018
84f2424
Merge branch 'review-timeseries' of https://github.com/stuart-knock/n…
stuart-knock Jan 23, 2018
e7c9370
Fixes doc.
stuart-knock Jan 30, 2018
94459ee
Fixes edge-case and cleans-up PulseSigmoid.
stuart-knock Jan 30, 2018
d89de6b
Fixes PiOnSqrt3 definition for clang.
stuart-knock Jan 30, 2018
fbdd649
Removes redundant "series" initialiser.
stuart-knock Jan 30, 2018
2c299fd
Fixes variable initialisation.
stuart-knock Jan 30, 2018
70ca4dd
Moves larger remaining TODOs to GitHub issues, #142, #143.
stuart-knock Jan 30, 2018
6ab473b
Fixes constant name.
stuart-knock Jan 30, 2018
634291b
Merge branch 'master' into review-timeseries
stuart-knock Jan 30, 2018
1bc502f
Changes neurofield to nftsim in Makefile.
stuart-knock Feb 2, 2018
183064e
Changes neurofield to nftsim in Matlab interface.
stuart-knock Feb 2, 2018
b2b6b7d
Changes neurofield to nftsim in src.
stuart-knock Feb 2, 2018
061f674
Changes neurofield to nftsim in documentation.
stuart-knock Feb 2, 2018
489642e
Changes NeuroField to NFTsim in user-manual.
stuart-knock Feb 2, 2018
2fc6e0a
Changes NEUROFIELD to NFTSIM in header guards.
stuart-knock Feb 2, 2018
eb5b27e
Changes variables neurofield_* to nftsim_* in Matlab interface.
stuart-knock Feb 2, 2018
d501376
Changes remaining neurofield to nftsim in Matlab interface.
stuart-knock Feb 2, 2018
f43d650
Changes Neurofield to nftsim in main() header and help message.
stuart-knock Feb 2, 2018
d8180a5
Changes neurofield to nftsim in Python interface.
stuart-knock Feb 2, 2018
6ee6f73
Changes Python class file-name from neurofield to nftsim.
stuart-knock Feb 2, 2018
0d4657b
Changes neurofield to nftsim in nf_configs.
stuart-knock Feb 2, 2018
ec850b9
Changes NeuroField to NFTsim in noise doc.
stuart-knock Feb 2, 2018
9a77856
Changes neurofield to nftsim in nf_benchmarks.
stuart-knock Feb 2, 2018
2d83d62
Changes remaining, scattered, neurofield references to nftsim.
stuart-knock Feb 2, 2018
ba47ca7
Updates user-guide pdf with recent changes.
stuart-knock Feb 2, 2018
1caee4e
Update README.md
Feb 4, 2018
0ddffe6
Update name of the binary in code examples
Feb 4, 2018
4fff476
Fix broken link and reference to NeuroField
Feb 4, 2018
88c6453
Document input and output arguments
Feb 4, 2018
b7496f8
Improve comments
Feb 4, 2018
2a7aa33
Fix spatial coordinates of grid points.
Feb 5, 2018
5ae6a87
Updates variable names used for array size
Feb 5, 2018
8525a56
Update inline TODO
Feb 5, 2018
77f1ff6
Update inline TODO
Feb 5, 2018
358f3ad
Document input and output arguments
Feb 5, 2018
8d5b9ae
Update conditions text; link to preprint
Feb 5, 2018
9e44e3c
Update inline TODOs
Feb 5, 2018
3701634
Fixes #141. Covers part of #147
Feb 5, 2018
931f284
Merge branch 'review-timeseries' of https://github.com/stuart-knock/n…
Feb 5, 2018
bf9395b
Remov abuse of notation. Use different variables for standard deviati…
Feb 5, 2018
3f88561
Remov abuse of notation in white coherent.
Feb 5, 2018
34d2f3a
Set default values for standard deviation and psd
Feb 5, 2018
773e1df
Set default values for standard deviation and psd for WhiteCoherent
Feb 5, 2018
b81706c
Renames Psd to PSD
Feb 5, 2018
fa4bac0
Change Std to StdDev
Feb 5, 2018
46c8332
Change Std to StdDev
Feb 5, 2018
e467241
Fixes boundary error in PulseRect::fire() definition.
stuart-knock Feb 13, 2018
cc0f936
Adds stimulus examples to user-manual. Updates pdf.
stuart-knock Feb 13, 2018
708ea8b
Fixes node indexing. Adds arg to disable detrend.
stuart-knock Feb 13, 2018
d0160a7
Check whether the file is a configuration file.
Feb 15, 2018
14b703f
Remove leftover OR operator
Feb 15, 2018
6228ba5
Adds caption to example of superimposed PulseRect and PulseSigmoid
Feb 15, 2018
91cf63e
Adds .eps files that are included in the user-manual.
stuart-knock Feb 15, 2018
b9c13b5
Merge branch 'review-timeseries' of https://github.com/stuart-knock/n…
Feb 15, 2018
221cd20
Update caption
Feb 15, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions +nf/extract.m
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
%% Extract a specific subset of data from a neurofield output struct.
%% Extract a specific subset of data from a nftsim output struct.
%
% The subset can be specified in terms of: traces; times; and nodes.
%
% ARGUMENTS:
% obj -- A neurofield output struct (a Matlab struct containing data
% obj -- A nftsim output struct (a Matlab struct containing data
% from a simulation).
% traces -- A cell array or a comma separated string of the traces
% you want to extract, e.g. 'Propagator.2.phi, Coupling.2.nu'.
Expand Down Expand Up @@ -35,7 +35,7 @@
% If no nodes are provided, output all nodes
if ~isstruct(obj) || ~isfield(obj, 'data')
error(['nf:' mfilename ':BadArgument'], ...
'The first argument must be a neurofield output struct.');
'The first argument must be a nftsim output struct.');
end

if nargin < 4 || isempty(nodes)
Expand Down
56 changes: 35 additions & 21 deletions +nf/get_frequencies.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
% Return corresponding grids of frequencies and positions
%
% ARGUMENTS:
% data -- .
% fs -- .
% Lx -- .
% Ly -- .
% data -- an 1D or 3D array of size space points along x, space points along y, tim points,
% fs -- sampling temporal frequency in [Hz]
% Lx -- physical size of the spatial domain along x in [m]
% Ly -- physical size of the spatial domain along y in [m]
%
% OUTPUT:
% f -- .
% Kx -- .
% Ky -- .
% x -- .
% y -- .
% df -- .
% dk -- .
% dx -- .
% f -- vector of (positives) frequencies in [Hz]
% Kx -- vector of angular wavenumbers in [rad/m]
% Ky -- vector of angular wavenumbers in [rad/m]
% x -- vector with spatial coordinates in [m]
% y -- vector with spatial coordinates in [m]
% df -- temporal frequency resolution in [Hz]
% dk -- radial spatial frequency resolution in [rad/m]
% dx -- spatial resolution in [m]
%
% REQUIRES:
% -- <description>
Expand All @@ -38,16 +38,19 @@
x = [];
y = [];

% This is the single positive sided frequency vector
if isvector(data)
f = (0:(fs / length(data)):(fs / 2)).'; % This is the single sided frequency
f = (0:(fs / length(data)):(fs / 2)).';
return
end

f = (0:(fs / size(data, 3)):(fs / 2)).'; % This is the single sided frequency
% This is the single positive sided frequency
f = (0:(fs / size(data, 3)):(fs / 2)).';
df = fs / size(data, 3);

Kx = 2*pi*(0:1/Lx:size(data, 1)/Lx/2); % This is the single sided frequency
Ky = 2*pi*(0:1/Ly:size(data, 2)/Ly/2); % This is the single sided frequency

% Wavenumbers / single sided and positive
Kx = 2*pi*(0:1/Lx:size(data, 1)/Lx/2);
Ky = 2*pi*(0:1/Ly:size(data, 2)/Ly/2);

if mod(size(data, 1), 2) % If there is NO nyquist frequency component
Kx = [-Kx(end:-1:2) Kx];
Expand All @@ -60,13 +63,24 @@
else
Ky = [-Ky(end:-1:2) Ky(1:end-1)];
end

[Kx, Ky] = meshgrid(Kx, Ky);

% Smallest wavenumber - resolution in k-space (angular spatial frequency)
% This is assuming the spatial domain is square (Lx=Ly)

dk = 2 * pi / Lx;

% dx and dy should be the same
dx = Lx / size(data, 1); % [m]
dy = Ly / size(data, 1); % [m]

% the stencil in NFTsim assumes the coordinates of a parcel of the discretized domain
% is at the centre of the parcel, thus the first coordinate is at (dx/2; dy/2)

x = dx * (0:size(data, 1)) + dx/2;
y = dy * (0:size(data, 1)) + dx/2;

dx = Lx / size(data, 1); % Metres per pixel
x = dx * (0:size(data, 1)-1);
dy = Ly / size(data, 1);
y = dy * (0:size(data, 1)-1);
[x, y] = meshgrid(x, y);

end %function get_frequencies()
6 changes: 3 additions & 3 deletions +nf/grid.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
% output all nodes), or the number of nodes is not a perfect square..
%
% ARGUMENTS:
% obj -- A neurofield output struct (a Matlab struct containing data
% obj -- A nftsim output struct (a Matlab struct containing data
% from a simulation).
% trace -- A string with the name of the array to reshape.
%
Expand All @@ -35,7 +35,7 @@

if output_nodes ~= obj.input_nodes
error(['nf:' mfilename ':IncompatibleOutput'], ...
'Output from NeuroField must be for all nodes')
'Output from NFTsim must be for all nodes')
end

data = nf.extract(obj, trace);
Expand All @@ -48,7 +48,7 @@
longside_nodes = obj.longside_nodes;
shortside_nodes = obj.input_nodes / obj.longside_nodes;
end
%Reshape to an array of (n,m,tpts)
%Reshape to an array of (nx,ny,tpts)

%data = reshape(data, grid_edge, grid_edge, obj.npoints);

Expand Down
26 changes: 19 additions & 7 deletions +nf/plot_timeseries.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
% node_idx -- cell array with vectors of node indices, one per trace.
% reref -- boolean, true: removes spatial average at each time-step,
% this is equivalent to the "grand-average" often used in EEG.
% rm_linear_trend -- boolean, true: remove any linear trend from data before
% plotting. Disable to view non-stationary time-series.
%
% OUTPUT: (Generates a time-series figure for each trace.)
% figure_handles -- cell array of figure handles.
%
% REQUIRES:
% nf.extract() -- Extract a specific subset of data from a neurofield
% nf.extract() -- Extract a specific subset of data from a nftsim
% output struct.
%
% AUTHOR:
Expand All @@ -28,7 +30,7 @@
%{
%Either run a simulation:
nf_obj = nf.run('./configs/eirs-corticothalamic.conf')
%Or load some neurofield output data
%Or load some nftsim output data
nf_obj = nf.read('./configs/eirs-corticothalamic.output')

%Plot every fourth node for the trace 'Propagator.1.phi'.
Expand All @@ -38,7 +40,7 @@
close([figure_handles{:}])
%}

function figure_handles = plot_timeseries(obj, traces, node_idx, reref)
function figure_handles = plot_timeseries(obj, traces, node_idx, reref, rm_linear_trend)
% Default to plotting all fields.
if nargin < 2 || isempty(traces)
traces = obj.fields;
Expand All @@ -54,6 +56,10 @@
if nargin < 4
reref = true;
end
% Default to linear detrend of data before plot.
if nargin < 5
rm_linear_trend = true;
end
% Get some size info about data
num_figs = length(traces);
time = obj.time;
Expand All @@ -63,15 +69,21 @@
for nof=1:num_figs
num_nodes = length(node_idx{nof});
labels = cell(1, num_nodes);
node_data_index = nan(1, num_nodes);
for k = 1:num_nodes
labels{k} = num2str(node_idx{nof}(k));
labels{k} = num2str(node_idx{nof}(k));
node_data_index(k) = find(obj.nodes{nof} == node_idx{nof}(k));
end %index labels

figure_handles{nof} = figure;
fig_title = [traces{nof}];
% Get fata to plot
% Get data to plot
data = nf.extract(obj, traces{nof});
data = detrend(data);

% Remove any linear trend from individual time-series.
if rm_linear_trend
data = detrend(data);
end

% Rescale data to the range [0, 1]
data = data - min(data(:));
Expand All @@ -88,7 +100,7 @@
separate_by = 0.33*(max(data(:)) - min(data(:)));
nodes_by_timestepsize = repmat((1:num_nodes), [time_steps,1]);

plot(time, data(:, node_idx{nof}) + separate_by*nodes_by_timestepsize, ...
plot(time, data(:, node_data_index) + separate_by*nodes_by_timestepsize, ...
'color', [0.42, 0.42, 0.42]);

title(fig_title, 'interpreter', 'none');
Expand Down
14 changes: 9 additions & 5 deletions +nf/read.m
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
%% Read a neurofield output file and return a neurofield output struct.
%% Read a nftsim output file and return a nftsim output struct.
%
% ARGUMENTS:
% fname -- The name of the neurofield output file to read (absolute
% fname -- The name of the nftsim output file to read (absolute
% or relative path).
%
% OUTPUT:
% obj -- A neurofield output struct. A Matlab struct containing data
% obj -- A nftsim output struct. A Matlab struct containing data
% and parameters from a simulation.
%
% AUTHOR:
Expand All @@ -20,7 +20,11 @@
function [obj] = read(fname)

% Check that our input arg is actually a file.
if ~exist(fname, 'file')
if endsWith(fname,'.conf')
error(['nf:' mfilename ':BadArgument'], ...
'The file provided is a configuration file: "%s".', fname)
end
if ~exist(fname, 'file')
% Try appending .output to the name we were provided.
if ~exist([fname, '.output'], 'file')
error(['nf:' mfilename ':FileDoesNotExist'], ...
Expand All @@ -42,7 +46,7 @@


while isempty(strfind(buffer, '======================='))
% TODO: consider cleaning up this part.
% TODO: CLEAN UP - this part refers to EEGCODE.
if ~isempty(strfind(buffer, 'Time |'))
error(['nf:' mfilename ':OldStyleOutput'], ...
'Did you try and open and old-style output file? Found a | that looked like a delimiter.')
Expand Down
6 changes: 3 additions & 3 deletions +nf/report.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
%% Given a neurofield output struct, print some information about it.
%% Given a nftsim output struct, print some information about it.
%
% ARGUMENTS:
% obj -- A neurofield output struct (a Matlab struct containing data
% obj -- A nftsim output struct (a Matlab struct containing data
% from a simulation).
%
% OUTPUT: Prints to terminal.
Expand All @@ -16,7 +16,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function report(obj)
fprintf(1, 'Output for: neurofield -i "%s"\n', obj.conf_file)
fprintf(1, 'Output for: nftsim -i "%s"\n', obj.conf_file)
fprintf(1, 'Traces: ');
for j = 1:length(obj.fields)
fprintf(1, '%s ', obj.fields{j});
Expand Down
4 changes: 3 additions & 1 deletion +nf/rfft.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
% http://www.brain-dynamics.net/~chris_rennie/fourier.pdf
%
% AUTHOR:
% Original: Chris Rennie circa 2000
% Romesh Abeysuriya (2012-03-22).
%
% USAGE:
Expand Down Expand Up @@ -75,9 +76,10 @@
P(2:(end - 1), :) = P(2:(end - 1), :) .* 2.0;
end

% TODO: check normalizations
% P now contains properly normalized spectral power
%f = fs / 2 * linspace(0, 1, NFFT / 2 + 1)';
f = 0:(fs / NFFT):(fs / 2); % I think this is more correct
f = 0:(fs / NFFT):(fs / 2); % I think this is more correct
P = mean(P, 2);
P = P ./ f(2); % Divide by frequency bin size to get power density

Expand Down
50 changes: 25 additions & 25 deletions +nf/run.m
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
%% Function to run neurofield and return a neurofield output struct.
%% Function to run nftsim and return a nftsim output struct.
%
% Provided a configuration file-name (fname.conf), run the neurofield
% Provided a configuration file-name (fname.conf), run the nftsim
% executable, generating an output file (fname.output). Optionally, if an
% output argument is provided then, parse the output file and return a
% neurofield output struct containing the simulation results.
% nftsim output struct containing the simulation results.
%
%
% ARGUMENTS:
% fname -- Name of the configuration file, it can be with or without
% the .conf extension.
% time_stamp -- boolean flag to use a time_stamp YYYY-MM-DDTHHMMSS
% in the output file name.
% neurofield_path -- neurofield executable (full or relative path).
% nftsim_path -- nftsim executable (full or relative path).
%
% OUTPUT: Writes a .output file in the same location as the .conf file.
% obj -- A neurofield output struct (a Matlab struct containing
% obj -- A nftsim output struct (a Matlab struct containing
% data from a simulation).
%
% REQUIRES:
% neurofield -- The neurofield executable, must be in your path.
% nf.read -- Read a neurofield output file and return a neurofield
% nftsim -- The nftsim executable, must be in your path.
% nf.read -- Read a nftsim output file and return a nftsim
% output struct.
%
% AUTHOR:
% Romesh Abeysuriya (2012-03-22).
%
% USAGE:
%{
%At a matlab command promt, from neurofield's main directory:
%At a matlab command promt, from nftsim's main directory:
nf_obj = nf.run('./configs/eirs-corticothalamic.conf')
%}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function obj = run(fname, time_stamp, neurofield_path)
function obj = run(fname, time_stamp, nftsim_path)
%
tic;
fname = strrep(fname, '.conf', ''); %Strip any .conf suffix.
Expand All @@ -41,39 +41,39 @@
if nargin < 2
time_stamp = false;
end
% If we were not provided a path to neurofield, try to determine one.
if nargin < 3 || isempty(neurofield_path)
% If we were not provided a path to nftsim, try to determine one.
if nargin < 3 || isempty(nftsim_path)
% Check typical locations, the first path that exists will be selected.
locations = {'neurofield', ...
'./bin/neurofield', ...
'./neurofield/bin/neurofield', ...
'neurofield.exe'};
locations = {'nftsim', ...
'./bin/nftsim', ...
'./nftsim/bin/nftsim', ...
'nftsim.exe'};
selected_path = find(cellfun(@(name) exist(name, 'file')==2, locations), 1, 'first');
if ~isempty(selected_path)
neurofield_path = locations{selected_path};
nftsim_path = locations{selected_path};
else
error(['nf:' mfilename ':BadPath'], ...
'neurofield not found. Either change into the neurofield base directory or make a symlink to neurofield in the current directory.');
'nftsim not found. Either change into the nftsim base directory or make a symlink to nftsim in the current directory.');
end
% If we were provided a path, check that it is valid.
elseif ~exist(neurofield_path, 'file')
elseif ~exist(nftsim_path, 'file')
error(['nf:' mfilename ':BadPath'], ...
'The neurofield_path you provided is incorrect:"%s".',neurofield_path);
'The nftsim_path you provided is incorrect:"%s".',nftsim_path);
end

if ~time_stamp
neurofield_cmd = sprintf('%s -i %s.conf -o %s.output', neurofield_path, fname, fname);
nftsim_cmd = sprintf('%s -i %s.conf -o %s.output', nftsim_path, fname, fname);
else
neurofield_cmd = sprintf('%s -i %s.conf -t', neurofield_path, fname);
nftsim_cmd = sprintf('%s -i %s.conf -t', nftsim_path, fname);
end
fprintf('INFO: Executing command:\n')
fprintf('%s\n', neurofield_cmd);
[status, cmdout] = system(neurofield_cmd);
fprintf('%s\n', nftsim_cmd);
[status, cmdout] = system(nftsim_cmd);

string(cmdout)
if status ~= 0
error(['nf:' mfilename ':NeurofieldError'], ...
'An error occurred while running neurofield!');
error(['nf:' mfilename ':NFTsimError'], ...
'An error occurred while running nftsim!');
end

fprintf(1, 'INFO: tic-toc: Took about %.3f seconds\n', toc);
Expand Down
Loading