function [output] = EdulogRun(port, dur, sps, loggers)
% Run specified Eduloggers for a specified duration at a specified temporal
% resolution.
%
% "port" is the port Eduloggers are connected to, this is visible on the
% Neulog API window. "dur" is the duration (s) of the clap test, it must be
% at least 15s for any response to be visible. "sps" is the number of
% samples the edulogger should take per second, up to a maximum of 5.
% "loggers" is a one dimensional cell array, with each string specifying
% the name of a different Edulogger as described in the Neulog API
% literature:
% https://neulog.com/wp-content/uploads/2014/06/NeuLog-API-version-7.pdf
%
% "output" is a structure generated by running an Edulogger experiment,
% consisting of the following fields: Time: The time (s) since the start of
% the experiment of each sample. (double) Concern: Whether or not each
% sample took more than twice the specified sample rate to retrieve
% (logical) An additional field for each kind of Edulogger used, containing
% the measurements taken at each point in data.Time. Fieldnames should line
% up with the names specified in "loggers".
% History:
% ??-??-???? Todd Parsons Written.
%% Essential checks. Not sure where the folder on Linux or macOS would be?
if IsWin && ~exist('C:\neulog_api', 'dir') % If the Neulog API is not installed...
error('Neulog API not found, please install.') % Link user to the installation page
end
if ~exist('webread')
error('Required webread() function unavailable. You need Matlab R2014b+ or GNU/Octave 6.0+ for this to work.');
end
if ~isnumeric(port) % If the port given is not a number...
error('Port number (port) must be numeric') % Deliver an error
end
switch isnumeric(sps) % Is the given SPS a number?
case true % If so...
if sps > 5 % If it is greater than 5...
error('SPS exceeds max temporal resolution, please choose a value lower than 5') % Deliver an error
elseif sps < 0 % If it is less than 0...
error('Cannot take fewer than 0 samples per second') % Deliver an error
end
case false % If not...
error('Samples per second (sps) must be numeric') % Deliver an error
end
if ~isnumeric(dur) % If the given duration is not a number...
error('Duration (dur) must be a numeric value') % Deliver an error
end
%% Run edulogger
preface = ['http://localhost:' num2str(port) '/NeuLogAPI?']; % Construct the string to preface any argument passed to the Eduloggers
for n = 1:dur*sps % For each sample...
tic % Start a timer
while toc < 1/sps % Until the timer reaches sps^-1
for l = 1:length(loggers) % For each logger...
data.(loggers{l}){n} = ... % Set the appropriate cell in data to equal...
webread( ... % ...the response received from the Edulogger when you send it...
[preface, 'GetSensorValue:[', loggers{l}, '],[1]'] ... % ...this command: The preface, a request for values and the logger type
);
end
data.Time(n) = toc; % Record the time taken
data.Concern(n) = round(toc, 1) > 2/sps; % Did this sample take more than twice the desired time to retrieve?
data.Event(n) = false;
end
end
%% Transform data
output=struct(); % Create a blank structure
data.Time = cumsum(data.Time); % Convert time to a cumulative sum
for n = 1:dur*sps % For each sample...
for l = 1:length(loggers) % For each logger...
output(n).(loggers{l}) = ... % Set the appropriate cell in output to equal...
str2num( ... % ...as a number, not a string...
data.(loggers{l}){n}( ... % ...the appropriate value from data...
findnum(data.(loggers{l}){n}) ... % ...put through a function which removes anything which isn't a number
)); %#ok
end
output(n).Time = data.Time(n); % Save timestamps to the output
output(n).Concern = data.Concern(n); % Save concern matrix to the output
end
end
function i = findnum(str)
% Find values in a string which can be converted to numeric without
% returning an error.
%
% "str" is the string in which to find numbers
%
% "i" is a logical matrix with the indices of numbers in the string as
% true.
i = find(... % Find indices at which str is equal to...
str == '0' | ... % ...0
str == '1' | ... % ...1
str == '2' | ... % ...2
str == '3' | ... % ...3
str == '4' | ... % ...4
str == '5' | ... % ...5
str == '6' | ... % ...6
str == '7' | ... % ...7
str == '8' | ... % ...8
str == '9' | ... % ...9
str == '.' | ... % ...a decimal point
str == '-' ... % ...a minus sign
);
end