Matlab help: how to skip or delay events - matlab

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.

Related

Seeking advice on trying to read a moore neighbourhood for a 2D cellular automata in MATLAB for an epidemic simulator

I'm currently working on a code that makes use of a 2D cellular automata as an epidemic simulator in MATLAB. The main basic rule I'm trying to implement is that if any neighbour within a Moore Neighbourhood with a 1-cell radius is infected, the cell will become infected. But I can't seem to get a good code working for it.
Basically what I'm trying to do is say with for a cell with a one cell radius Moore neighbourhood, if any values in this neighbourhood = 2, then the initial cell will become 2.
I've tried using the forest fire code on the rosetta code as a basis for my code behaviour but it doesnt work very well. The rules don't really work that well when applying it to mine. I've tried using the mod function and a series of if loops to attach. I'll put in some code of each to give context.
This example doesn't really function well as an epidemic simulator to be honest.
matlab
clear; clc;
n = 200;
N = n/2;
E = 0.001; % Creating an arbitrary number for population exposed to
the disease but not infected
p = 1 + (rand(n,n)<E);
%p = ceil(rand(n,n)*2.12) - 1;
% ratio0 = sum(p(:)==0)/n^2;
% ratio1 = sum(p(:)==1)/n^2;
% ratio2 = sum(p(:)==2)/n^2;
% ratio3 = sum(p(:)==3)/n^2;
S = ones(3); S(2,2) = 0;
ff = 0.00000000002;
p(N,N) = 3;
%% Running the simulation for a set number of loops
colormap([1,1,1;1,0,1;1,0,0]); %Setting colourmap to Green, red and
grey
count = 0;
while(count<365) % Running the simulation with limited number of runs
count = count + 1;
image(p); pause(0.1); % Creating an image of the model
P = (p==1); % Adding empty cells to new array
P = P + (p==2).*((filter2(S,p==3)>0) + (rand(n,n)<ff) + 2); % Setting
2 as a tree, ignites based on proximity of trees and random
chance ff
P = P + (p==3); % Setting 3 as a burning tree, that becomes 1,
p = P;
end
second idea. this basically returns nothing
matlab
clear;clf;clc;
n = 200;
pos = mod((1:n),n) + 1; neg = mod((1:n)-2,n) + 1;
p = (ceil(rand(n,n)*1.0005));
for t = 1:365
if p(neg,neg) ==2
p(:,:) = 2;
end
if p(:,neg)==2
p(:,:) = 2;
end
if p(pos,neg)==2
p(:,:) = 2;
end
if p(neg,:)==2
p(:,:) = 2;
end
if p(pos,:)==2
p(:,:) = 2;
end
if p(neg,pos)==2
p(:,:) = 2;
end
if p(:,pos)==2
p(:,:) = 2;
end
if p(pos,pos)== 2
p(:,:) = 2;
end
image(p)
colormap([1,1,1;1,0,1])
end
third I tried using logic gates to see if that would work. I don't know if commas would work instead.
matlab
clear;clf;clc;
n = 200;
pos = mod((1:n),n) + 1; neg = mod((1:n)-2,n) + 1;
p = (ceil(rand(n,n)*1.0005));
%P = p(neg,neg) + p(:,neg) + p(pos,neg) + p(neg,:) + p(:,:) + p(pos,:)
+ p(neg,pos) + p(:,pos) + p(pos,pos)
for t=1:365
if p(neg,neg)|| p(:,neg) || p(pos,neg) || p(neg,:) || p(pos,:) ||
p(neg,pos) || p(:,pos) || p(pos,pos) == 2
p(:,:) = 2;
end
image(p)
colormap([1,1,1;1,0,1])
end
I expected the matrix to just gradually become more magenta but nothing happens in the second one. I get this error for the third.
"Operands to the || and && operators must be convertible to logical scalar values."
I just have no idea what to do!
Cells do not heal
I assume that
Infected is 2, non-infected is 1;
An infected cell remains infected;
A non-infected cell becomes infected if any neighbour is.
A simple way to achieve this is using 2-D convolution:
n = 200;
p = (ceil(rand(n,n)*1.0005));
neighbourhood = [1 1 1; 1 1 1; 1 1 1]; % Moore plus own cell
for t = 1:356
p = (conv2(p-1, neighbourhood, 'same')>0) + 1; % update
image(p), axis equal, axis tight, colormap([.4 .4 .5; .8 0 0]), pause(.1) % plot
end
Cells heal after a specified time
To model this, it is better to use 0 for a non-infected cell and a positive integer for an infected cell, which indicated how long it has been infected.
A cell heals after it has been infected for a specified number of iterations (but can immediately become infeced again...)
The code uses convolution, as the previous one, but now already infected cells need to be dealt with separately from newly infected cells, and so a true Moore neighbourhood is used.
n = 200;
p = (ceil(rand(n,n)*1.0005))-1; % 0: non-infected. 1: just infected
T = 20; % time to heal
neighbourhood = [1 1 1; 1 0 1; 1 1 1]; % Moore
for t = 1:356
already_infected = p>0; % logical index
p(already_infected) = p(already_infected)+1; % increase time count for infected
newly_infected = conv2(p>0, neighbourhood, 'same')>0; % logical index
p(newly_infected & ~already_infected) = 1; % these just became infected
newly_healed = p==T; % logical index
p(newly_healed) = 0; % these are just healed
image(p>0), axis equal, axis tight, colormap([.4 .4 .5; .8 0 0]), pause(.1) % plot
% infected / non-infected state
end

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

What is the expectation of the number of times you need to roll

I'm interested to write something using Matlab to simulate the number of times you need to roll a dice. (Maybe the re-roll is only done once?)
I'll need to keep re-rolling the die, until a unique number appears.
Below is the code I have up to now.
Any help is appreciated.
% N: the max number a roll of the fair die can take
N = 6;
% M: number of trials. Each trial is a sequence of rolls, and it
% terminates once you see K N's in a row.
M = 1;
K = 1;
% initialize the trials vector. The m-th entry is going to store
% the number of rolls performed in the m-th trial.
trials = zeros(M,1);
% t0: record the start time of the simulation
t0 = clock();
% This for loop is to run the M trials.
for m = 1:M
% collection: sequence of rolls. It's initialized with K
% samples drawn from a uniformly distributed integer random
% variable, because the minimal length of collection has to
% be K.
% Here begins the loop to roll the die until all 6 numbers appear
% If any number is repeated, re-roll until a unique number appears & move on to the next number
collection = randi(N,K,1);
collection(:,2) = randi(N,K,1);
if collection(:,2)~=collection(:,1)
collection(:,3) = randi(N,K,1)
else collection(:,2) = randi(N,K,1)
end
if collection(:,3)~=(collection(:,1) && collection(:,2))
collection(:,4) = randi(N,K,1)
else collection(:,3) = randi(N,K,1)
end
if collection(:,4)~=(collection(:,1)&& collection(:,2) && collection(:,3))
collection(:,5) = randi(N,K,1)
else collection(:,4) = randi(N,K,1)
end
if collection(:,5)~=(collection(:,1)&& collection(:,2) && collection(:,3) && collection(:,4))
collection(:,6) = randi(N,K,1)
else collection(:,5) = randi(N,K,1)
end
if collection(:,6)=(collection(:,1)&& collection(:,2) && collection(:,3) && collection(:,4) && collection(:,5))
collection(:,6) = randi(N,K,1)
end
% now that the last K rolls are all N's, we take note of the number
% of rolls performed in this trial
trials(m) = length(collection);
end
% we measure how much time the simulation has spent by
% computing the time difference between now and t0
elapsed_time = etime(clock(), t0)
% the Monte Carlo estimate, which should be close to your analytical
% solution.
mean(trials)
Here is how I would do it
function trials = diceExperiment( M )
trials = zeros(1,M);
for i = 1:M
missingNum = true(1,6); % None of the six numbers are seen yet
while (any(missingNum))
currentNum = randi(6,1);
trials(i) = trials(i)+1;
missingNum(currentNum) = false;
end
end
end % End of function
This would run this experiment for M times and the output trial would tell me how many rolls of the dice did it take each time to get all six numbers. You can add your clock stuff around this to measure time.

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?

MeanShift Clustering on dataset

I have a numeric dataset and I want to cluster data with a non-parametric algorithm. Basically, I would like to cluster without specifying the number of clusters for the input. I am using this code that I accessed through the MathWorks File Exchange network which implements the Mean Shift algorithm. However, I don't Know how to adapt my data to this code as my dataset has dimensions 516 x 19.
function [clustCent,data2cluster,cluster2dataCell] =MeanShiftCluster(dataPts,bandWidth,plotFlag)
%UNTITLED2 Summary of this function goes here
% Detailed explanation goes here
%perform MeanShift Clustering of data using a flat kernel
%
% ---INPUT---
% dataPts - input data, (numDim x numPts)
% bandWidth - is bandwidth parameter (scalar)
% plotFlag - display output if 2 or 3 D (logical)
% ---OUTPUT---
% clustCent - is locations of cluster centers (numDim x numClust)
% data2cluster - for every data point which cluster it belongs to (numPts)
% cluster2dataCell - for every cluster which points are in it (numClust)
%
% Bryan Feldman 02/24/06
% MeanShift first appears in
% K. Funkunaga and L.D. Hosteler, "The Estimation of the Gradient of a
% Density Function, with Applications in Pattern Recognition"
%*** Check input ****
if nargin < 2
error('no bandwidth specified')
end
if nargin < 3
plotFlag = true;
plotFlag = false;
end
%**** Initialize stuff ***
%[numPts,numDim] = size(dataPts);
[numDim,numPts] = size(dataPts);
numClust = 0;
bandSq = bandWidth^2;
initPtInds = 1:numPts
maxPos = max(dataPts,[],2); %biggest size in each dimension
minPos = min(dataPts,[],2); %smallest size in each dimension
boundBox = maxPos-minPos; %bounding box size
sizeSpace = norm(boundBox); %indicator of size of data space
stopThresh = 1e-3*bandWidth; %when mean has converged
clustCent = []; %center of clust
beenVisitedFlag = zeros(1,numPts,'uint8'); %track if a points been seen already
numInitPts = numPts %number of points to posibaly use as initilization points
clusterVotes = zeros(1,numPts,'uint16'); %used to resolve conflicts on cluster membership
while numInitPts
tempInd = ceil( (numInitPts-1e-6)*rand) %pick a random seed point
stInd = initPtInds(tempInd) %use this point as start of mean
myMean = dataPts(:,stInd); % intilize mean to this points location
myMembers = []; % points that will get added to this cluster
thisClusterVotes = zeros(1,numPts,'uint16'); %used to resolve conflicts on cluster membership
while 1 %loop untill convergence
sqDistToAll = sum((repmat(myMean,1,numPts) - dataPts).^2); %dist squared from mean to all points still active
inInds = find(sqDistToAll < bandSq); %points within bandWidth
thisClusterVotes(inInds) = thisClusterVotes(inInds)+1; %add a vote for all the in points belonging to this cluster
myOldMean = myMean; %save the old mean
myMean = mean(dataPts(:,inInds),2); %compute the new mean
myMembers = [myMembers inInds]; %add any point within bandWidth to the cluster
beenVisitedFlag(myMembers) = 1; %mark that these points have been visited
%*** plot stuff ****
if plotFlag
figure(12345),clf,hold on
if numDim == 2
plot(dataPts(1,:),dataPts(2,:),'.')
plot(dataPts(1,myMembers),dataPts(2,myMembers),'ys')
plot(myMean(1),myMean(2),'go')
plot(myOldMean(1),myOldMean(2),'rd')
pause
end
end
%**** if mean doesnt move much stop this cluster ***
if norm(myMean-myOldMean) < stopThresh
%check for merge posibilities
mergeWith = 0;
for cN = 1:numClust
distToOther = norm(myMean-clustCent(:,cN)); %distance from posible new clust max to old clust max
if distToOther < bandWidth/2 %if its within bandwidth/2 merge new and old
mergeWith = cN;
break;
end
end
if mergeWith > 0 % something to merge
clustCent(:,mergeWith) = 0.5*(myMean+clustCent(:,mergeWith)); %record the max as the mean of the two merged (I know biased twoards new ones)
%clustMembsCell{mergeWith} = unique([clustMembsCell{mergeWith} myMembers]); %record which points inside
clusterVotes(mergeWith,:) = clusterVotes(mergeWith,:) + thisClusterVotes; %add these votes to the merged cluster
else %its a new cluster
numClust = numClust+1 %increment clusters
clustCent(:,numClust) = myMean; %record the mean
%clustMembsCell{numClust} = myMembers; %store my members
clusterVotes(numClust,:) = thisClusterVotes;
end
break;
end
end
initPtInds = find(beenVisitedFlag == 0); %we can initialize with any of the points not yet visited
numInitPts = length(initPtInds); %number of active points in set
end
[val,data2cluster] = max(clusterVotes,[],1); %a point belongs to the cluster with the most votes
%*** If they want the cluster2data cell find it for them
if nargout > 2
cluster2dataCell = cell(numClust,1);
for cN = 1:numClust
myMembers = find(data2cluster == cN);
cluster2dataCell{cN} = myMembers;
end
end
This is the test code I am using to try and get the Mean Shift program to work:
clear
profile on
nPtsPerClust = 250;
nClust = 3;
totalNumPts = nPtsPerClust*nClust;
m(:,1) = [1 1];
m(:,2) = [-1 -1];
m(:,3) = [1 -1];
var = .6;
bandwidth = .75;
clustMed = [];
%clustCent;
x = var*randn(2,nPtsPerClust*nClust);
%*** build the point set
for i = 1:nClust
x(:,1+(i-1)*nPtsPerClust:(i)*nPtsPerClust) = x(:,1+(i-1)*nPtsPerClust:(i)*nPtsPerClust) + repmat(m(:,i),1,nPtsPerClust);
end
tic
[clustCent,point2cluster,clustMembsCell] = MeanShiftCluster(x,bandwidth);
toc
numClust = length(clustMembsCell)
figure(10),clf,hold on
cVec = 'bgrcmykbgrcmykbgrcmykbgrcmyk';%, cVec = [cVec cVec];
for k = 1:min(numClust,length(cVec))
myMembers = clustMembsCell{k};
myClustCen = clustCent(:,k);
plot(x(1,myMembers),x(2,myMembers),[cVec(k) '.'])
plot(myClustCen(1),myClustCen(2),'o','MarkerEdgeColor','k','MarkerFaceColor',cVec(k), 'MarkerSize',10)
end
title(['no shifting, numClust:' int2str(numClust)])
The test script generates random data X. In my case. I want to use the matrix D of size 516 x 19 but I am not sure how to adapt my data to this function. The function is returning results that are not agreeing with my understanding of the algorithm.
Does anyone know how to do this?