Using KbQueueCheck to continuously check for device input - matlab

I am using PsychToolbox to run an experiment on a fMRI scanner. I want to collect the timepoints of pulses sent out by the scanner. If you are not familiar with this topic: A scanner gives out a signal - equivalent to pressing keyboard digit "5" - in defined time-intervals. The first such signal starts the code, such that measurements by the scanner, and starting time of the code are synchronized. My code is sequential, as sketched out below. How could I implement a loop which at any time checks for these inputed "5", even though my main code runs in a "for"-loop?
My code:
% here I wait for the scanner to input a "5", then my code will start
KbQueueCreate;
KbQueueStart;
Trigger = KbName('5%');
keyboard = -1;
AllowedKeys = zeros(256,1); %Disable all keys
AllowedKeys([LeftPress RightPress MiddlePress]) = 1; %Also allow escape always.
while 1
[pressed, firstPress] = KbQueueCheck();
if firstPress(Trigger)
startExperiment = GetSecs;
break
end
end
KbQueueStop;
KbQueueRelease;
% In the foolowing loop, the main experiment runs. here I show a screen,
% signal etc.
for i = 1:nrTrials
% here I would like to have code checking for scanner inputs
end
The function KbQueueCheck should check for any keyboard input starting from the most recent call to KbQueueStart.
Any input is very welcome.

I think you're going about this all wrong. There are much simpler ways to capture and process events without involving expensive for loops at all. Specifically, matlab (and octave) do this most effectively via graphics handle instances (even though you don't necessarily need a graphics object to be visible for it).
Here's a very simple example (I created this on octave, but it should also work on matlab). Run it to see how it works, then study and modify accordingly.
%% In file 'run_fMRI_experiment.m'
% Main experiment function
function fMRIData = run_fMRI_experiment
global fMRIData;
F = figure;
text(-1,0,{'Glorious Experiment, she is now runnink, yes?', 'Please to be pressink "5", I will collectink data.', '', 'Please to be pressink key of escapeness when finishedski, da?'}, 'fontsize', 14);
axis off; axis ([-1, 1, -1, 1]);
set (F, 'keypressfcn', #detectFirstKeyPress);
waitfor(F);
end
% subfunctions (i.e. in same file) acting as callback functions
function detectFirstKeyPress(CallerHandle, KeyPressEvent)
if strcmp(KeyPressEvent.Key, '5')
set (CallerHandle, 'keypressfcn', {#detectKeyPresses, tic()});
fprintf ('Experiment started at %s\n', datestr(now()));
end
end
function detectKeyPresses (CallerHandle, KeyPressEvent, StartTime)
if strcmp (KeyPressEvent.Key, '5');
global fMRIData; fMRIData(end+1) = toc(StartTime);;
fprintf('"5" pressed at %d seconds.\n', fMRIData(end)); return
elseif strcmp (KeyPressEvent.Key, 'escape');
disp ('Escape Pressed. Ending Experiment');
close (CallerHandle);
end
end
PS: Note that for a keypress event to be considered linked to the figure, the figure must be in focus. I.e. do not press '5' while the terminal is in focus, this won't be counted. Just launch the function and start pressing buttons as the window appears.
PS2: As an aside, if you must perform certain tasks asynchronously, matlab provides the batch function for this. Also worth having a look.

We do the similar stuff with our scanner, so I providing a function I use. I normally only detect first trigger to start the stimulus, and won't read later triggers. But I do register all triggers, as well as other response, in the background, so I can check the events in case there is any problem.
The function, KbQueue.m, can do almost all related response collection, including background key register. Please read the help for how to use different functionality. Some part of the code, such as different keyboard indices, is not well tested for MAC and Linux.
function varargout = KbQueue(cmd, param)
% KbQueueXXX series functions have some good features:
% 1. detect short key event, like those from fOPR KbCheck may miss;
% 2. detect only interested keys;
% 3. buffer key event while code is running.
%
% But the syntax of KbQueueXXX is a little inconvenient due to the flexibility.
%
% This code tries to provide a convenient wrapper for practical purpose, by
% sacrificing some flexibility, like deviceIndex etc. By default, KbQueue
% detects events for the first device (this doesn't seem the case for Windows,
% where it detects all devices). If you have more than one keyboard, and like to
% detect a different one, you have to add following in your code:
%
% global KbQueueDevice; KbQueueDevice = 2;
%
% where 2 means the second device. You need to find this index for your target
% keyboard.
%
% KbQueue('start', keys);
% - Create a queue and start it. The second input specify the keys to be queued.
% The default are numbers 1~5, both keyboard and keypad numbers. The key names
% adopt those with KbName('UnifyKeyNames'). The 'start' command can be called
% more than once to update new keys. If it is not called, other subfunctions
% will call it with the default keys automatically.
%
% Example:
% KbQueue('start', {'LeftArrow' 'RightArrow'}); % start to queue 2 arrows
%
% The input keys can also be 256-element keyCode, such as that returned by
% KbCheck etc. It can also be the index in the keyCode, such as that returned by
% KbQueue('wait') etc.
%
% nEvents = KbQueue('nEvents' [, 'type']);
% - Return number of events in the queue. The default event type is 'press',
% which returns the number of keypress. It can be 'release' or 'all', which will
% return number of release events or all events.
%
% [pressTime, pressCode] = KbQueue('wait' [, secs or keys]);
% - Wait for a new event, and return key press time and keycode. During the
% wait, pressing Escape will abort code execution, unless 'Escape' is included
% in defined keys.
%
% If there is no second input, this will wait forever till a defined key by
% previous 'start' command is detected.
%
% If the second input is numeric, it will be interpreted as the seconds to wait,
% and wait for a key defined by previous 'start' command is pressed, or the
% seconds has elapsed, whichever is earlier. If there is no any event during the
% time window, both output will be empty. For example:
%
% [t, key] = KbQueue('wait', 1); % wait for 1 sec or a key is detected
%
% If the second input is a string or cellstr, it will be interpreted as the
% key(s) to detect. The provided keys here affects only this call, i.e. it has
% no effect on the queue keys defined by previous 'start' command. For example:
%
% t = KbQueue('wait', {'5%' '5'}); % wait till 5 is pressed
%
% [pressCodeTime, releaseCodeTime] = KbQueue('check' [, t0]);
% - Return first and last press keycode and times for each queued key, and
% optionally release keycode and times. The output will be empty if there is no
% buffered response. Both output are two row vector, with the first row for the
% keycode and second row for times. If the second input t0, default 0, is
% provided, the returned times will be relative to t0. For example:
%
% press = KbQueue('check'); % return 1st and last key press in the queue
% pressedKey = KbName(press(1, :); % convert keycode into key names
%
% KbQueue('flush');
% - Flush events in the current queue.
%
% t = KbQueue('until', whenSecs);
% - This is the same as WaitSecs('UntilTime', whenSecs), but allows to exit by
% pressing ESC. If whenSecs is not provided or is already passed, this still
% checks ESC, so allows use to quit. For example:
% KbQueue('until', GetSecs+5); % wait for 5 secs from now
% KbQueue('until'); % only check ESC exit
%
% [pressCodeTime, releaseCodeTime] = KbQueue('stop' [, t0]);
% - This is similar to 'check' command, but it returns all queued events since
% last 'flush', or since the queue was started. It also stops and releases the
% queue. This provides a way to check response in the end of a session. For
% example:
% KbQueue('start', {'5%' '5'}); % start to queue 5 at beginning of a session
% KbQueue('flush'); % optionally remove unwanted events at a time point
% t0 = GetSecs; % the start time of your experiment
% % run your experiment
% pressCodeTime = KbQueue('stop', t0); % get all keycode and time
% 10/2012 wrote it, xiangrui.li#gmail.com
% 12/2012 try to release queue from GetChar etc, add nEvents
% 11/2014 try to use response device for OSX and Linux
persistent kCode started evts;
global KbQueueDevice; % allow to change in user code
if isempty(started), started = false; end
if nargin<1 || isempty(cmd), cmd = 'start'; end
if any(cmd=='?'), subFuncHelp('KbQueue', cmd); return; end
if strcmpi(cmd, 'start')
if started, BufferEvents; end
if nargin<2
param = {'1' '2' '3' '4' '5' '1!' '2#' '3#' '4$' '5%'};
end
KbName('UnifyKeyNames');
if ischar(param) || iscellstr(param) % key names
kCode = zeros(256, 1);
kCode(KbName(param)) = 1;
elseif length(param)==256 % full keycode
kCode = param;
else
kCode = zeros(256, 1);
kCode(param) = 1;
end
if isempty(KbQueueDevice), KbQueueDevice = responseDevice; end
try KbQueueReserve(2, 1, KbQueueDevice); end %#ok
KbQueueCreate(KbQueueDevice, kCode);
KbQueueStart(KbQueueDevice);
started = true;
return;
end
if ~started, KbQueue('start'); end
if strcmpi(cmd, 'nEvents')
BufferEvents;
n = length(evts);
if n, nPress = sum([evts.Pressed] == 1);
else nPress = 0;
end
if nargin<2, param = 'press'; end
if strncmpi(param, 'press', 5)
varargout{1} = nPress;
elseif strncmpi(param, 'release', 7)
varargout{1} = n - nPress;
else
varargout{1} = n;
end
elseif strcmpi(cmd, 'check')
[down, p1, r1, p2, r2] = KbQueueCheck(KbQueueDevice);
if ~down
varargout = repmat({[]}, 1, nargout);
return;
end
if nargin<2, param = 0; end
i1 = find(p1); i2 = find(p2);
varargout{1} = [i1 i2; [p1(i1) p2(i2)]-param];
if nargout>1
i1 = find(r1); i2 = find(r2);
varargout{2} = [i1 i2; [r1(i1) r2(i2)]-param];
end
elseif strcmpi(cmd, 'wait')
endSecs = GetSecs;
secs = inf; % wait forever unless secs provided
newCode = kCode; % use old keys unless new keys provided
if nargin>1 % new keys or secs provided
if isempty(param), param = inf; end
if isnumeric(param) % input is secs
secs = param;
else % input is keys
newCode = zeros(256, 1);
newCode(KbName(param)) = 1;
end
end
esc = KbName('Escape');
escExit = ~newCode(esc);
newCode(esc) = 1;
changed = any(newCode~=kCode);
if changed % change it so we detect new keys
BufferEvents;
KbQueueCreate(KbQueueDevice, newCode);
KbQueueStart(KbQueueDevice); % Create and Start are twins here :)
else
KbQueueFlush(KbQueueDevice, 1); % flush KbQueueCheck buffer
end
endSecs = endSecs+secs;
while 1
[down, p1] = KbQueueCheck(KbQueueDevice);
if down || GetSecs>endSecs, break; end
WaitSecs('YieldSecs', 0.005);
end
if changed % restore original keys if it is changed
BufferEvents;
KbQueueCreate(KbQueueDevice, kCode);
KbQueueStart(KbQueueDevice);
end
if isempty(p1)
varargout = repmat({[]}, 1, nargout);
return;
end
ind = find(p1);
if escExit && any(ind==esc)
error('User pressed ESC. Exiting ...');
end
varargout = {p1(ind) ind};
elseif strcmpi(cmd, 'flush')
KbQueueFlush(KbQueueDevice, 3); % flush both buffers
evts = [];
elseif strcmpi(cmd, 'until')
if nargin<2 || isempty(param), param = 0; end
while 1
[down, t, kc] = KbCheck(-1);
if down && kc(KbName('Escape'))
error('User pressed ESC. Exiting ...');
end
if t>=param, break; end
WaitSecs('YieldSecs', 0.005);
end
if nargout, varargout = {t}; end
elseif strcmpi(cmd, 'stop')
KbQueueStop(KbQueueDevice);
started = false;
if nargout
BufferEvents;
if isempty(evts)
varargout = repmat({[]}, 1, nargout);
return;
end
isPress = [evts.Pressed] == 1;
if nargin<2, param = 0; end
varargout{1} = [[evts(isPress).Keycode]
[evts(isPress).Time]-param];
if nargout>1
varargout{2} = [[evts(~isPress).Keycode]
[evts(~isPress).Time]-param];
end
end
KbQueueRelease(KbQueueDevice);
else
error('Unknown command: %s.', cmd);
end
function BufferEvents % buffer events so we don't lose them
n = KbEventAvail(KbQueueDevice);
if n<1, return; end
for ic = 1:n
foo(ic) = KbEventGet(KbQueueDevice); %#ok
end
if isempty(evts), evts = foo;
else evts = [evts foo];
end
end
end
function idx = responseDevice
if IsWin, idx = []; return; end % all keyboards
clear PsychHID; % refresh
[ind, pName] = GetKeyboardIndices;
if IsOSX
idx = ind(1); % based on limited computers
else % Linux
for i = length(ind):-1:1
if ~isempty(strfind(pName{i}, 'HIDKeys')) || ...
~isempty(strfind(pName{i}, 'fORP')) % faked, need to update
idx = ind(i);
return;
end
idx = ind(end); % based on limited computers
end
end
end

Related

setting state variable to a given value using ode15s

I'm using ode15s to simulate/solve a set of ODEs. I would like to implement a feature, where upon reaching a given condition during the simulation, a number in the model changes programatically (e.g., an indicator constant) for a fixed amount of time, and then reverts back.
This could be, for example using Lotka-Volterra equations:
dx/dt = alphax - betax*y
dy/dt = (delta+indicator)xy - gammay + epsilonindicator
indicator starts as 0. Let's say that when x reaches 10, I'd like to switch indicator to 1 for 10 time units, and then flip it back to 0.
This can be done in a dirty way by using global variables, however, this is something I'd like to avoid (impossible to parallelize + general avoidance of global variables). Is there a neat alternative way when using ode15s (i.e., I don't know the time step)?
Many thanks for any suggestions!
Edit: As noted correctly by LutzL, wrapping an ODE with non-smooth state without handling events may lead to inaccurate results
as you can not predict at what time points in what order the ODE
function is evaluated. LutzL
So the accurate solution is to deal with ODE events. An example for the modified Lotka-Volterra equations is given below, where the event fires, if x gets >10 and the indicator will be turned on for 10 seconds:
% parameters and times:
params = ones(5,1); % [alpha, ..., epsilon]
z_start = [2, 1];
t_start = 0;
t_end = 30;
options = odeset('Events',#LotkaVolterraModEvents); % set further options here, too.
% wrap ODE function with indicator on and off
LVModODE_indicatorOn = #(t,z)LotkaVolterraModODE(t,z,1, params);
LVModODE_indicatorOff = #(t,z)LotkaVolterraModODE(t,z,0, params);
% storage for simulation values:
data.t = t_start;
data.z = z_start;
data.teout = [];
data.zeout = zeros(0,2);
data.ieout = [];
% temporary loop variables:
z_0 = z_start;
t_0 = t_start;
isIndicatorActive = false;
while data.t(end) < t_end % until the end time is reached
if isIndicatorActive
% integrate for 10 seconds, if indicator is active
active_seconds = 10;
[t, z, te,ze,ie] = ode15s(LVModODE_indicatorOn, [t_0 t_0+active_seconds], z_0, options);
else
% integrate until end or event, if indicator is not active.
[t, z, te,ze,ie] = ode15s(LVModODE_indicatorOff, [t_0 t_end], z_0, options);
isIndicatorActive = true;
end
%append data to storage
t_len = length(t);
data.t = [data.t; t(2:end)];
data.z = [data.z; z(2:end,:)];
data.teout = [data.teout; te];
data.zeout = [data.zeout; ze];
data.ieout = [data.ieout; ie];
% reinitialize start values for next iteration of loop
t_0 = t(end);
z_0 = z(end, :);
% set the length of the last instegration
options = odeset(options,'InitialStep',t(end) - t(end-1));
end
%% plot your results:
figure;
plot(data.t, data.z(:,1), data.t, data.z(:,2));
hold all
plot(data.teout, data.zeout(:,1), 'ok');
legend('x','y', 'Events in x')
%% Function definitions for integration and events:
function z_dot = LotkaVolterraModODE(t, z, indicator, params)
x = z(1); y= z(2);
% state equations: modified Lotka-Volterra system
z_dot = [params(1)*x - params(2)*y;
(params(4) + indicator)*x*y - params(3)*y + params(5)*indicator];
end
function [value, isTerminal, direction] = LotkaVolterraModEvents(t,z)
x = z(1);
value = x-10; % event on rising edge when x passes 10
isTerminal = 1; %stop integration -> has to be reinitialized from outer logic
direction = 1; % only event on rising edge (i.e. x(t_e-)<10 and x(t_e+)>10)
end
The main work is done in the while loop, where the integration takes place.
(Old post) The following solution may lead to inaccurate results, handling events, as explained in the first part should be preferred.
You could wrap your problem in a class, which is able to hold a state (i.e. its properties). The class should have a method, which is used as odefun for the variable-step integrator. See also here on how to write classes in MATLAB.
The example below demonstrates, how it could be achieved for the example you provided:
% file: MyLotkaVolterra.m
classdef MyLotkaVolterra < handle
properties(SetAccess=private)
%define, if the modified equation is active
indicator;
% define the start time, where the condition turned active.
tStart;
% ode parameters [alpha, ..., epsilon]
params;
end
methods
function self = MyLotkaVolterra(alpha, beta, gamma, delta, epsilon)
self.indicator = 0;
self.tStart = 0;
self.params = [alpha, beta, gamma, delta, epsilon];
end
% ODE funciton for the state z = [x;y] and time t
function z_dot = odefun(self, t, z)
x = z(1); y= z(2);
if (x>=10 && ~self.indicator)
self.indicator = 1;
self.tStart = t;
end
%condition to turn indicator off:
if (self.indicator && t - self.tStart >= 10)
self.indicator = false;
end
% state equations: modified Lotka-Volterra system
z_dot = [self.params(1)*x - self.params(2)*y;
(self.params(4) + self.indicator)*x*y - ...
self.params(3)*y + self.params(5)*self.indicator];
end
end
end
This class could be used as follows:
% your ode using code:
% 1. create an object (`lvObj`) from the class with parameters alpha = ... = epsilon = 1
lvObj = MyLotkaVolterra(1, 1, 1, 1, 1);
% 2. pass its `odefun`method to the integrator (exaple call with ode15s)
[t,y] = ode15s(#lvObj.odefun, [0,5], [9;1]); % 5 seconds

Splitting a wav file in Matlab

I previously asked a question, which is related to my actual problem. I converted a mp3 file to a wav file, by using the program audacity. Th duration of the wav-file is about 10 seconds. I want to split it in 10 parts, which means, each part takes 1 second. How can i make it happen? Please apologize my ignorance, even though the community provided me some answer.
[y,fs]=wavread('UnchainMyHeart');
t=linspace(0,length(y)/fs,length(y));
plot(t,y)
The code here, shows my wav file in the time domain, but you probably can't see it, since you don't have the wav file. Doesn't matter. Now, is it possibly to continue from there, concering my question? I believe it has somthing to do with matrix...
Unfortunatley I lack the knowledge, therefore I always appreciate your help!
It depends on what you want to do next. The easiest way to get part of signal is:
part=y(1:Fs);
you probaly want array of this things so use FOR, or WHILE sructure, smth like this:
%in loop
part(i)=(i*Fs:i*Fs+Fs);
i=i+1;
be aware of array length
Here is a WavReader.m class which reads wav in chunks of the same length.
To read 1-second chunks, use it like this:
wr = WavReader('c:/wavs/killyourmama.wav');
wr.SetChunkLengthInMiliSeconds( 1000.0 );
while(true)
[pcm, num_read] = wr.ReadChunk();
if( num_read==0 ); break; end;
fprintf('Progress: %5.2f%%\n', wr.Progress() );
end
Here is the class:
classdef WavReader < handle
%WavReader Reads wav files in chunks
% Flexible wav chunk reader.
%
% 1) Usage steps in case of full file read:
%
% Create wav reader:
% wr = WavReader(path);
% Read all samples:
% [samples, count] = GetAllSamples();
%
% 2) Usage steps in case of range read:
%
% Create wav reader:
% wr = WavReader(path);
%
% Read samples from within a range:
% [samples, count] = GetSamples(seconds_start, seconds_finish);
%
% 3) Usage steps in case chunk-by-chunk read:
%
% Create wav reader:
% wr = WavReader(path);
%
% Set range of interest:
% wr.SetRange( seconds_start, seconds_finish );
%
% Set chunk size you want to read:
% wr.SetChunkLength( chunk_size );
%
% Read chunk-by-chunk:
% while(num_read)
% [pcm, num_read] = wr.ReadChunk();
%
%
properties (Access=private)
% Info
path;
fs;
total_samples;
total_seconds;
% Range of interest
range_length;
range_samples;
% Current state of chunks
chunk_length;
total_chunks;
chunks_read;
end
methods
function obj = WavReader( in_path_wav )
% Constructor
try
obj.path = in_path_wav;
info = audioinfo(obj.path);
obj.fs = info.SampleRate;
obj.total_samples = info.TotalSamples;
obj.total_seconds = info.Duration;
catch
error('Problem with opening wav file. Exiting.')
end
% Defaul reads full range, whole file.
obj.SetRangeFull();
end
%%
function [range_length] = SetRangeFull(obj)
%SetRangeFull Sets the range to full (we are interested in all samples).
try
obj.range_samples = audioread(obj.path);
catch
error('Problem with reading wav file. Exiting.')
end
obj.range_length = obj.total_samples;
range_length = obj.range_length;
end
%%
function [range_length] = SetRange(obj, start_sec, end_sec)
% SetRange Sets target range of interest.
%
%# [range_length] = SetRange(obj, start_sec, end_sec)
%# INPUT start_sec: staring point in target range
%# INPUT end_sec: ending point in target range
%# OUTPUT range_length: number of total samples available in the range
%
% To use full range call SetRangeFull().
% If start beyond end: throws exception.
% If end beyond end: sets end to end.
[start_sec, end_sec] = obj.checks( start_sec,end_sec );
% Full range if both zeroes:
%if(start_sec==0 && end_sec==0)
% start_sample = 1;
% stop_sample = obj.total_samples;
%else
start_sample = obj.seconds_to_samples(start_sec);
stop_sample = obj.seconds_to_samples(end_sec);
%end
obj.range_length = stop_sample - start_sample;
obj.range_samples = 0;
try
obj.range_samples = audioread(obj.path, [start_sample, stop_sample]);
catch
error('Problem with reading wav file. Exiting.')
end
range_length = obj.range_length;
end
%%
function [total_chunks] = SetChunkLength( obj, chunk_length )
% SetChunkLength Defines chunk length for chunk-by-chunk read.
%
%# [total_chunks] = SetChunkLength( obj, chunk_length )
%# INPUT chunk_length: desired chunk length
%# OUTPUT total_chunks: total number of available full chunks
%
% Abandonds last incomplete chunk.
obj.chunk_length = chunk_length;
obj.chunks_read = 0;
obj.total_chunks = round( obj.range_length / obj.chunk_length - 0.5 );
total_chunks = obj.total_chunks;
end
%%
function [total_chunks] = SetChunkLengthInMiliSeconds( obj, chunk_length_ms )
% SetChunkLengthInMiliSeconds Defines chunk length for chunk-by-chunk read.
%
%# [total_chunks] = SetChunkLengthInMiliSeconds( obj, chunk_length_ms )
%# INPUT chunk_length_ms: desired chunk length in mili-seconds
%# OUTPUT total_chunks: total number of available full chunks
%
% Abandonds last incomplete chunk.
seconds = chunk_length_ms/1000.0;
chunk_length_samples = seconds_to_samples( obj, seconds );
total_chunks = SetChunkLength( obj, chunk_length_samples );
end
%%
function [chunk, num_read] = ReadChunk( obj )
% ReadChunk Reads next chunk of blocklength.
%
%# [chunk, num_read] = ReadChunk( obj )
%# OUTPUT chunk: chunk samples
%# OUTPUT num_read: number of read samples.
%
% If next chunk incomplete: returns zero.
% If next chunk not available: returns zero.
start_pos = 1 + obj.chunks_read * obj.chunk_length;
stop_pos = start_pos + obj.chunk_length -1;
if( start_pos>obj.range_length || stop_pos>obj.range_length)
num_read = 0;
chunk = 0;
% warning('Reached the end of samples, nothing read.')
% To do: handle last incomplete frame.
return;
end
chunk = obj.range_samples(start_pos:stop_pos);
num_read = 1 + stop_pos - start_pos;
obj.chunks_read = 1 + obj.chunks_read;
end
%%
function progress = Progress(obj)
% Progress Returns progress in percentages.
progress = 100.0 * double(obj.chunks_read) / double(obj.total_chunks);
end
%%
function range = GetFullRange(obj)
% GetFullRange Returns all samples available.
range = obj.range_samples;
end
%%
function fs = GetSamplingRate(obj)
% GetSamplingRate Returns sampling rate.
fs = obj.fs;
end
%%
function samples = GetNumberOfSamples(obj)
samples = obj.total_samples;
end
%%
function num_chunks_read = GetNumberOfReadChunks(obj)
% GetNumberOfReadChunks Returns number of chunks read so far.
num_chunks_read = obj.chunks_read;
end
%%
function [samples, count] = GetSamples(obj, start_sec, end_sec)
% GetSamples Call to immediately get range of samples.
[start_sec, end_sec] = obj.checks( start_sec,end_sec );
start_sample = obj.seconds_to_samples(start_sec);
stop_sample = obj.seconds_to_samples(end_sec);
count = 1 + stop_sample - start_sample;
try
samples = audioread(obj.path, [start_sample, stop_sample]);
catch
error('Problem with reading wav file. Exiting.')
end
end
%%
function [samples, count] = GetAllSamples(obj)
% GetAllSamples Call to immediately get all of the samples.
try
samples = audioread(obj.path);
catch
error('Problem with reading wav file. Exiting.')
end
count = obj.total_samples;
end
end % methods public
methods (Access=private)
% Secs to samples
function [sample] = seconds_to_samples( obj, seconds )
sample = obj.fs * seconds;
end
% Check range
function [start_checked, end_checked] = checks(obj, start_sec, end_sec)
start_checked = start_sec;
end_checked = end_sec;
% Check fatal errors
if( start_sec>obj.total_seconds ||...
start_sec>=end_sec ||...
start_sec<0 ||...
end_sec<0 )
throw(MException( 'WavReader:FatalError', 'Range error.') );
end
% Handle overflow
if( end_sec > obj.total_seconds )
end_checked = obj.total_seconds;
end
end
end % methods private
end % class

Executing nested functions with a timer object

I am trying to write a program which acquires an image from a webcam, averages over several of the vertical pixel rows, displays the result and then applies a Gaussian fit to locate the peak position with a high degree of accuracy. All of this is to be done in real time. I used a timer object to run the function (called datain) which triggers the camera and acquires the data. To iterate and update the data the function includes a while loop. My code worked perfectly until I added a command inside the while loop to call another function (called GaussianFit) which preformed the fit. When this function is added I receive an error which says the callback function in the timer does not have enough inputs.
"Error while evaluating TimerFcn for timer 'timer-1' Not enough input arguments."
This seems odd since the data acquisition function provides all the inputs needed by the fitting function. My code is as follows:
function WaveAQ()
global webcamin
%%%%%%%%%%%%%%%%%%%%%%%
% Create video object %
%%%%%%%%%%%%%%%%%%%%%%%
dID = 2; vForm = 'MJPG_1280x720';
% Search for existing video objects to avoid creating multiple handles
vObj = imaqfind('DeviceID', dID, 'VideoFormat', vForm);
if isempty(vObj)
webcamin = videoinput('winvideo',dID,vForm);
else
webcamin = vObj{1};
end
% Configure # datasets to be averaged per measurement
set(webcamin,'FramesPerTrigger',1);
% Repeat until stopped
set(webcamin,'TriggerRepeat',Inf);
% Set to grayscale
set(webcamin,'ReturnedColorSpace','grayscale');
% Allow webcam to be triggered by timer
triggerconfig(webcamin,'manual')
% % View the properties for the selected video source object.
% src_obj = getselectedsource(webcamin);
% get(src_obj)
% Prompt for dark reading
j = 1;
j = input('Would you like to take a dark reading? (y/n): ','s');
switch j
case 'y'
j = 1;
case 'n'
j = 2;
end
if j == 1
prompt = input('Block input and enter any number to continue: ');
end
% We now define a function which will acquire data from the camera to be
% executed by the timer function
fig1 = figure(1);
function datain(~,event,input)
persistent image
h = 1; % Initialize Loop
bg = 0;
avgroi = 0;
% Calibration and fitting constants
tol = 1;
calib_slope = .003126;
calib_offset = 781.8;
spect = (1:1280)*calib_slope + calib_offset;
while h == 1
% Check if figure is open
h = ishandle(fig1);
trigger(input);
% First run finds dark reading
if j == 1
bg = getdata(input,1,'uint8');
j = 2;
else
image = getdata(input,1,'uint8');
image = image - bg; % Correct for background
npxy = length(image(:,1));
npxx = length(image(1,:));
% Region of interest for spectral data
dy_roi = 200;
y_roi = npxy/2;
% Region of interest for beam position
dx_roi = npxx/2;
x_roi = npxx/2;
avgroi = sum(image((y_roi-dy_roi):(y_roi+dy_roi),:))/(2*dy_roi);
avgroi = avgroi/256; % Normalize units
avg_y = (sum(image(:,(x_roi-dx_roi+1):(x_roi+dx_roi))).'/(2*dx_roi)).';
[cx,sx,Ipeak] = GaussianFit(avgroi,tol);
% cx = max(avgroi);
% sx = 2;
% Ipeak = max(avgroi);
subplot(2,1,1)
plot(spect,avgroi)
title('Spectrogram')
xlabel('Wavelength (nm)')
ylabel('Intensity (arb.)')
legend(['\lambda_P_e_a_k = ',num2str(cx),'nm'])
subplot(2,1,2)
plot(1:length(avg_y),avg_y/256)
title('Beam Profile in Y')
xlabel('Pixel #')
ylabel('Intensity (arb.)')
end
end
end
%%%%%%%%%%%%%%%%%%%
% Define timer object to execute daq %
%%%%%%%%%%%%%%%%%%%
% Set callback properies
timerfcn = #datain;
% Image acquisition rate
Raq = 5;
timer_exec = timer('TimerFcn',{timerfcn,webcamin},'period',1/Raq,'BusyMode','drop');% Maybe change busy mode to queue if regular acquisition interval needed.
% timer_exec2 = timer('TimerFcn',#GaussianFit,'period',1/Raq,'BusyMode','drop');
% Execute acquistion
start(webcamin);
preview(webcamin);
start(timer_exec);
% start(timer_exec2);
% Clean system
stop(timer_exec);
% stop(timer_exec2);
delete(timer);
stop(webcamin);
delete(webcamin);
clear functions;
end
Can anyone tell me why the timer needs more inputs when GaussianFit is called inside the loop?

Matlab Computation Time for Synonyms

I am importing wordnet library in matlab code given below but it takes almost 5-10 seconds for giving me synonyms of each word.
can its time be reduced in some way because I have to test it on numerous words
Thanks
Code:
function [status,varargout] = dictionary(text)
%DICTIONARY checks the spelling status of word(s) and returns synonyms if found.
%
% [status,synonyms] = dictionary(text);
% status = dictionary(text);
%
% text: word(s) separated by a single space.
% status: returns '1' if word(s) exist in dictionary or '0' otherwise.
% synonyms: an array of synonyms of word(s) or otherwise returns
% a message 'No Synonyms Found!' or 'Incorrect Spelling!'.
%
% Examples:
% [status,synonyms] = dictionary('peddler');
% [status,synonyms] = dictionary('walk match ground');
% status = dictionary('hysteria');
%
% Separating string of words into arrays of words.
k=1;
temp='';
% t=fopen('Crime.txt');
% text=textscan(t,'%s');
% text=texts{1,1};
% fclose(t);
%text='ignorevbnnn';
for n=1:length(text);
if ~isspace(text(n))
temp = [temp text(n)];
else
if ~isspace(text(n-1))
words{k} = temp;
end
temp='';
k=k+1;
end
end
words{k} = temp;
% Opening MS Word and Starting the Spelling Check & Finding Synonyms
Doc = actxserver('Word.Application');
m=1;
for n=1:length(words)
if ~isempty(words{n})
status(m) = invoke(Doc,'CheckSpelling',words{n},[],1,1);
if nargout==2
X = invoke(Doc,'SynonymInfo',words{n});
Synonyms = get(X,'MeaningList');
Meanings{m,1} = words{n};
if length(Synonyms)==0 & status(m)==1
Meanings{m,2} = 'No Synonyms Found!';
elseif status(m)==0
Meanings{m,2} = 'Incorrect Spelling!';
else
for k=2:length(Synonyms)+1
Meanings{m,k} = Synonyms{k-1};
end
end
end
m=m+1;
end
end
if exist('Meanings','var')
varargout = {Meanings};
end
status = all(status);
invoke(Doc,'Quit');
delete(Doc);

Matlab help: how to skip or delay events

Here is a script that I am using for my experiment.
The objects hear 3 different tones, each representing different amount of reward. So when tone 1 comes on, there is no reward, and when tone 2 and 3 come on and the object triggers the photobeam(pb_broken), the rewards will be given.
The problem is that sometimes the object receives reward without even hearing the tone because they're near photobeam thus triggering it, and causing it to release reward.
I want to prevent that from happening and I'm not sure how to do so.
here are my options:
if photobeam 1 is triggered (there are 2 photobeams) before tones, then skip the tone, and proceed with experiment (don't play that tone again and go on to the next whenever it was suppose to come on originally)
if photobeam 1 is triggered before the reward tones (2 and 3) then skip the tone (like above)
if pb 1 is broken, then delay the tone by 1 second, thus delaying everything by 1 second, and still ending at 1200 seconds. this would be the ideal case.
Here's my code:
clear all;
%%
% Set-up DAQ with an output and input session
global outputSession; % this will control the feeders
outputSession = daq.createSession('ni');
outputSession.addDigitalChannel('Dev2', 'Port1/Line0:1', 'OutputOnly');
outputSession.outputSingleScan([0 0]); % set everything to 0 to start
global inputSession; % this reads from the photobeams
inputSession = daq.createSession('ni');
inputSession.addDigitalChannel('Dev2', 'Port1/Line5:6', 'InputOnly');
global leverSession; % read from levers: note, scan returns 1 if not pressed, empty if pressed!
leverSession = daq.createSession('ni');
leverSession.addDigitalChannel('Dev2', 'Port1/Line2', 'InputOnly');
%% intitialize variables, draw status figure etc.
global target_rewarded; % needs to be global so functions can reset it
target_rewarded = [0 0]; % no targets (receptacles) armed to start
% track times and IDs of photobeam breaks
EventLogSize = 10000;
eventLog.pb_broken_time = nan(EventLogSize,1);
eventLog.pb_broken_id = nan(EventLogSize,1);
pb_counter = 1;
% times and IDs of feeders
eventLog.reward_time = nan(500,1);
eventLog.reward_id = nan(500,1);
reward_counter = 1;
eventLog.mistake_time = nan(500,1);
eventLog.mistake_id = nan(500,1);
mistake_counter = 1;
%%% generate trial start times %%%
sound_on = 0;
trial_count = 1;
%%% generate trial list %%%
trial_block = [1 1 2 2 3 3]; % permute block and repeat
eventLog.trial_list = [];
for iBlock = 1:50
eventLog.trial_list = cat(2,eventLog.trial_list,trial_block(randperm(length(trial_block))));
end
%%% SET UP TIMES OF CUE (TONE) ONSET HERE
maxTrials = 500;
mean_ITI = 20;
SD_ITI = 3;
eventLog.trial_times = mean_ITI.*ones(maxTrials,1);
trial_SD = SD_ITI.*randn(maxTrials,1);
eventLog.trial_times = eventLog.trial_times + trial_SD;
eventLog.trial_times = cumsum(eventLog.trial_times);
%%% set up sounds %%%
outputID = 10; % which sound connection on computer to use
duration = 7; % in seconds
samplesPerSecond = 22050; % the bit rate of the tone
tvec = 0:1/samplesPerSecond:duration;
% 1: 2kHz tone, on/off at 10Hz
s1 = sin(2*pi*2000*tvec);
s1 = s1.*square(2*pi*10*tvec);
s1 = 0.2.*s1;
% 2: white noise
s2 = rand(size(tvec));
s2 = 0.2*((s2.*2)-1);
% 4: 8kHz tone, sinewave amplitude-modulated at 2Hz
s3 = sin(2*pi*8000*tvec);
modl = 0.5*(sin(2*pi*2*tvec)+1);
s3 = s3.*modl;
s3 = 0.5.*s3;
tone1 = audioplayer(s1, samplesPerSecond, 16, outputID);
set(tone1,'StopFcn',#reset_rewards); % set it up so that if the tone ends, rewards are reset
tone2 = audioplayer(s2, samplesPerSecond, 16, outputID);
set(tone2,'StopFcn',#reset_rewards); % set it up so that if the tone ends, rewards are reset
tone3 = audioplayer(s3, samplesPerSecond, 16, outputID);
set(tone3,'StopFcn',#reset_rewards); % set it up so that if the tone ends, rewards are reset
sound_timer = [];
%%% tone-to-pellet mapping
tone_to_pellets = [0 2 5];
correct_pb = 1; % which photobeam is rewarded
correct_feeder = 2; % which feeder to use
%%% initialize main timer and photobeam status %%%
start_timer = tic; % call as t_elapsed = toc(start_timer);
t_elapsed = 0;
max_time = 1200; % in seconds
pb_broken = [];
previous_broken = 0;
%%% make task window %%%
fs = 18;
f1_handle = figure(1);
t_handle = title('Task starting...'); set(t_handle,'FontSize',fs);
status_handle = text(0,0.8,sprintf('Correct trials %d, Incorrect trials %d',reward_counter-1,mistake_counter-1)); set(status_handle,'FontSize',fs);
axis off;
%% run task
while t_elapsed < max_time
% update figure text,time
set(t_handle,'String',sprintf('t %.2f, pb %d, target %s',t_elapsed,pb_broken,num2str(target_rewarded)));
drawnow;
t_elapsed = toc(start_timer);
% check if any photobeams are broken
pb_broken = pb_scan(inputSession);
n_broken = numel(pb_broken);
if n_broken > 0 % do something potentially
% check
if n_broken > 1
disp('WARNING: multiple photobeams broken');
pb_broken = pb_broken(1);
end
if pb_broken == previous_broken % no change, do nothing
continue;
end
% log this: it's a new photobeam break
eventLog.pb_broken_time(pb_counter) = t_elapsed;
eventLog.pb_broken_id(pb_counter) = pb_broken;
pb_counter = pb_counter + 1;
disp(sprintf('*** Photobeam %d broken ***',pb_broken));
if any(target_rewarded > 0) % reward active, maybe dispense pellet
if pb_broken == correct_pb
disp('*** CORRECT POKE ***');
switch eventLog.trial_list(trial_count-1) % check what trial it is
case 1
disp(sprintf('Dispensed %d pellets',tone_to_pellets(1)));
dispensePellets(correct_feeder,tone_to_pellets(1));
stop(tone1);
case 2
disp(sprintf('Dispensed %d pellets',tone_to_pellets(2)));
dispensePellets(correct_feeder,tone_to_pellets(2));
stop(tone2);
case 3
disp(sprintf('Dispensed %d pellets',tone_to_pellets(3)));
dispensePellets(correct_feeder,tone_to_pellets(3));
stop(tone3);
end
target_rewarded = [0 0];
eventLog.reward_time(reward_counter) = t_elapsed;
eventLog.reward_id(reward_counter) = tone_to_pellets(eventLog.trial_list(trial_count-1));
reward_counter = reward_counter + 1;
disp(sprintf('Logged %d pellets rewarded',tone_to_pellets(eventLog.trial_list(trial_count-1))));
set(status_handle,'String',sprintf('Correct trials %d, Incorrect trials %d',reward_counter-1,mistake_counter-1));
else % wrong receptacle
if ~poked_this_trial
disp('*** ACTIVE CUE, INCORRECT POKE ***');
mistake_counter = mistake_counter + 1;
poked_this_trial = 1;
end
end
else % no reward active, do nothing
disp('*** INACTIVE CUE, INCORRECT POKE ***');
%mistake_counter = mistake_counter + 1;
end
end % of photobeam broken loop
% check if a new trial (sound) is starting
if t_elapsed > eventLog.trial_times(trial_count)
switch eventLog.trial_list(trial_count) % check what trial it is
case 1
play(tone1);
target_rewarded = [0 tone_to_pellets(1)];
case 2
play(tone2);
target_rewarded = [0 tone_to_pellets(2)];
case 3
play(tone3);
target_rewarded = [0 tone_to_pellets(3)];
end
sound_timer = tic;
trial_count = trial_count + 1;
poked_this_trial = 0;
disp(sprintf('New trial started (%d pellets): updated trial count is %d',target_rewarded(2),trial_count));
end
% check if we need to stop sound
if ~isempty(sound_timer) & toc(sound_timer) > duration
switch eventLog.trial_list(trial_count - 1)
case 1
stop(tone1)
case 2
stop(tone2)
case 3
stop(tone3)
end
end
previous_broken = pb_broken;
end % of main while loop
This really is a complicated problem to troubleshoot without hands on, and less of a programming and more of an experimental design question.
You may want to ensure that no photobeams are interrupted before starting a new tone, perhaps by substituting
if t_elapsed > eventLog.trial_times(trial_count)
with
if t_elapsed > eventLog.trial_times(trial_count) & ~n_broken
You could alternately add a while loop at the end of the pb obstruct check statement that makes sure no new event occurs for 1 sec, before exiting the if statement and proceeding. But then you also have to check the sound and possibly terminate it before exiting that loop.
As a final alternative, running a variety of controls (which I'm sure you are running), for instance an experiment without rewards, should serve to check the likelihood of random obstructions.
I am not sure what kind of constraints you have requiring keeping to a tight trial schedule, but as another comment mentions it may be best to record the time for events but allow arbitrary time for the system to "clear" before proceeding with the new trial.