Identify elements in a vector based on values from other vectors - matlab

I have time onsets for 8 events, called event1, event2, event3, ..., event8 (none of these events can occur simultaneously and thus each onset is unique). Each event is n x 1 double (n can vary from one event to another), like so:
event1 = [29.7; 38.4; 65.6; 149.6; 369.3]
event2 = [10.1; 11.8; 38.1; 142.2]
event3 = [5.5; 187.1; 200.1; 202.8; 236.7]
event4 = [15.3; 29.2; 54.5; 87.6; 100.4; 105.8; 120.9; 122.4]
...
event8 = [38.2; 66.7; 89.7; 100.5; 105.2; 168.9]
I want to find time points in event1 that are immediately preceded by either a time point in event2 or a time point in event4, meaning there cannot be another time point from a different event in between. For instance, the first time point in event 1 (i.e., 29.7) fits this criterion because it is preceded by the the second time point in event4 (i.e., 29.2). Similarly, time point 4 of event1 is preceded by time point 4 in event2. In contrast, the second time point in event1 (i.e., 38.4) doesn't qualify since it is preceded by the first time point in event8 (i.e., 38.2).
The result should be an index of event1 like this: index = [1;4]
Could anyone help me with this problem?

MATLAB's built-in functions might provide a cleaner solution, but I figured the following one is easy enough.
event1 = [29.7; 38.4; 65.6; 149.6; 369.3];
event2 = [10.1; 11.8; 38.1; 142.2];
event3 = [5.5; 187.1; 200.1; 202.8; 236.7];
event4 = [15.3; 29.2; 54.5; 87.6; 100.4; 105.8; 120.9; 122.4];
event8 = [38.2; 66.7; 89.7; 100.5; 105.2; 168.9];
event_agg = [event1; event2; event3; event4; event8]; % events vector, aggregate
eve_numb = [ones(length(event1),1); % event number vector
2*ones(length(event2),1);
3*ones(length(event3),1);
4*ones(length(event4),1);
8*ones(length(event8),1)];
EVENTS_IND = [event_agg, eve_numb]; % aggregate events with indices
EVENTS_SORT = sortrows(EVENTS_IND); % agg. events w/indices, sorted by event times
hits_array = []; % store the event times that meet the specified condition
for iter = 2:length(EVENTS_SORT)
if EVENTS_SORT(iter,2) == 1 % if the event time at iter comes from event #1
if EVENTS_SORT(iter-1,2) == 2 || EVENTS_SORT(iter-1,2) == 4 % if the event time at iter-1 come from events #2 or #4
hits_array = [hits_array EVENTS_SORT(iter,1)];
end
end
end

Related

Shift time series to start from zero H:M:S:MS (possibly in Matlab)

I have some ECG data for a number of subjects. For each subject, I can export an excel file with the RR interval, Heart Rate and other measures. The problem is that I have a timestamp starting at the time of recording (in this case 11:22:3:00).
I need to compare the date with other subjects and I want to automate the procedure in Matlab.
I need to flexibly compare, for instance, the first 3 minutes of subjects in condition 1 with those of sbj in condition 2. Or minutes 4 to 8 of condition 1 and 2 and so forth. To do this, I am thinking that the best way is to shift the time vector for each subject so that it starts from 0.
There are a couple of problems to note: I CANNOT create just one vector for all subjects. This would be inaccurate because the heart measures are variable for each individual.
So, IN SHORT I need to shift the time vector for each participant so that it starts at 0 and increases exactly like the original one. So, in this example:
H: M: S: MS RR HR
11:22:03:000 0.809 74.1
11:22:03:092 0.803 74.7
11:22:03:895 0.768 78.1
11:22:04:663 0.732 81.9
11:22:05:395 0.715 83.9
11:22:06:110 0.693 86.5
11:22:06:803 0.705 85.1
11:22:07:508 0.706 84.9
11:22:08:214 0.749 80.1
11:22:08:963 0.762 78.7
11:22:09:725 0.766 78.3
would become:
00:00:00:0000
00:00:00:092
00:00:00:895
00:00:01:663
and so forth...
I would like to do it in Matlab...
P.S.
I was working around the idea of extracting the info in 4 different variables.
Then, I could subtract the values for each cell from the first cell.
For instance:
11-11 = 0; 22-22=0; 03-03=0; ms: keep the same value
Maybe this could kind of work, except that it wouldn't if I have a subject that started, say, at 11:55:05:00
Thank you all for any help.
Gluce
Basic timestamp normalization just subtracts the minimum (or first, assuming they're properly ordered) time from the rest.
With MATLAB's datetime object, this is just subtraction, which yields a duration object:
ts = ["11:22:03:000", "11:22:03:092", "11:22:03:895", "11:22:04:663"];
% Convert to datetime & normalize
t = datetime(ts, 'InputFormat', 'HH:mm:ss:SSS');
t.Format = 'HH:mm:ss:SSS';
nt = t - t(1);
% Reformat & display
nt.Format = 'hh:mm:ss.SSS';
Which returns:
>> nt
nt =
1×4 duration array
00:00:00.000 00:00:00.092 00:00:00.895 00:00:01.663
Alternatively, you can normalize the datetime array itself:
ts = ["11:22:03:000", "11:22:03:092", "11:22:03:895", "11:22:04:663"];
t = datetime(ts, 'InputFormat', 'HH:mm:ss:SSS');
t.Format = 'HH:mm:ss:SSS';
[h, m, s] = hms(t);
[t.Hour, t.Minute, t.Second] = deal(h - h(1), m - m(1), s - s(1));
Which returns the same:
>> t
t =
1×4 datetime array
00:00:00:000 00:00:00:092 00:00:00:895 00:00:01:663

partial Distance Based RDA - Centroids vanished from Plot

I am trying to fir a partial db-RDA with field.ID to correct for the repeated measurements character of the samples. However including Condition(field.ID) leads to Disappearance of the centroids of the main factor of interest from the plot (left plot below).
The Design: 12 fields have been sampled for species data in two consecutive years, repeatedly. Additionally every year 3 samples from reference fields have been sampled. These three fields have been changed in the second year, due to unavailability of the former fields.
Additionally some environmental variables have been sampled (Nitrogen, Soil moisture, Temperature). Every field has an identifier (field.ID).
Using field.ID as Condition seem to erroneously remove the F1 factor. However using Sampling campaign (SC) as Condition does not. Is the latter the rigth way to correct for repeated measurments in partial db-RDA??
set.seed(1234)
df.exp <- data.frame(field.ID = factor(c(1:12,13,14,15,1:12,16,17,18)),
SC = factor(rep(c(1,2), each=15)),
F1 = factor(rep(rep(c("A","B","C","D","E"),each=3),2)),
Nitrogen = rnorm(30,mean=0.16, sd=0.07),
Temp = rnorm(30,mean=13.5, sd=3.9),
Moist = rnorm(30,mean=19.4, sd=5.8))
df.rsp <- data.frame(Spec1 = rpois(30, 5),
Spec2 = rpois(30,1),
Spec3 = rpois(30,4.5),
Spec4 = rpois(30,3),
Spec5 = rpois(30,7),
Spec6 = rpois(30,7),
Spec7 = rpois(30,5))
data=cbind(df.exp, df.rsp)
dbRDA <- capscale(df.rsp ~ F1 + Nitrogen + Temp + Moist + Condition(SC), df.exp); ordiplot(dbRDA)
dbRDA <- capscale(df.rsp ~ F1 + Nitrogen + Temp + Moist + Condition(field.ID), df.exp); ordiplot(dbRDA)
You partial out variation due to ID and then you try to explain variable aliased to this ID, but it was already partialled out. The key line in the printed output was this:
Some constraints were aliased because they were collinear (redundant)
And indeed, when you ask for details, you get
> alias(dbRDA, names=TRUE)
[1] "F1B" "F1C" "F1D" "F1E"
The F1? variables were constant within ID which already was partialled out, and nothing was left to explain.

View start time of Matlab timer object

How do you view and amend the start time of a timer object in Matlab? The closest I can get is the "StartDelay" element of the timer object :
all_timers = get(timerfind);
where each element of the returned structure array is one timer object. The various elements of the structure are (for example):
AveragePeriod: NaN
BusyMode: 'drop'
ErrorFcn: ''
ExecutionMode: 'singleShot'
InstantPeriod: NaN
Name: 'timer-1'
ObjectVisibility: 'on'
Period: 1
Running: 'on'
StartDelay: 7.200175000000000e+003
StartFcn: ''
StopFcn: ''
Tag: ''
TasksExecuted: 0
TasksToExecute: Inf
TimerFcn: #myFcn
Type: 'timer'
UserData: []
According to:
http://www.mathworks.co.uk/help/matlab/ref/timer-class.html
"StartDelay" is: Number greater than or equal to 0 that specifies the delay, in seconds, between the start of the timer and the first execution of the function specified in TimerFcn.
but unless I know when the timer object was started/created/initiated, the StartDelay is no real help?
The startFun can be used to evaluate a function on timer start, which could store the start time in the userData of the timer
Most simple
Define a function such as;
function myStartFcn(hTimer,~)
hTimer.UserData = now;
end
and set this to be the startFcn of the timer
hTimer = timer();
hTimer.StartFcn = #myStartFcn
A better? example
userData is a useful field we may want to use it for many things, in which case making it a structure and setting this as a field would be better. also now gives datenum format which may not be ideal, clock is another possibility;
function myStartFcn(hTimer,~)
tempStruct = hTimer.UserData;
tempStruct.startTime = clock;
hTimer.UserData = tempStruct;
end
Also it may be worth clearing this when the timer is stopped and storing the last run time in seconds
function myStopFcn(hTimer,~)
tempStruct = hTimer.UserData;
tempStruct.lastRunTime = etime(clock,tempStruct.startTime)
tempStruct.startTime = []
hTimer.UserData = tempStruct;
end

DJing with MATLAB (Low-Level I/O)

Alrighty everybody, it's the time of the week where I learn how to do weird things with MATLAB. This week it's DJing. What I need to do is figure out how to make my function output the name of the song whose length is closest to the time left. For instance, if I'm showing off my DJing skills and I have 3:22 left, I have to pick a song whose length is closest to the time left (can be shorter or longer). I'm given a .txt file to choose from.
Test Case
song1 = pickSong('Funeral.txt', '3:13')
song1 => 'Neighborhood #2 (Laika)'
The file for this looks like:
1. Neighborhood #1 (Tunnels) - 4:48
2. Neighborhood #2 (Laika) - 3:33
3. Une annee sans lumiere - 3:40
4. Neighborhood #3 (Power Out) - 5:12
5. Neighborhood #4 (7 Kettles) - 4:49
6. Crown of Love - 4:42
7. Wake Up - 5:39
8. Haiti - 4:07
9. Rebellion (Lies) - 5:10
10. In the Backseat - 6:21
I have most of it planned out, what I'm having an issue with is populating my cell array. It only puts in the last song, and then changes it to a -1 after my loop runs. I've tried doing it three different ways, the last one being the most complex (and gross looking sorry). Once I get the cell array into it's proper form (as the full song list and not just -1) I should be in the clear.
function[song] = pickSong(file_name,time_remain)
Song_list = fopen(file_name, 'r'); %// Opens the file
Song_names = fgetl(Song_list); %// Retrieves the lines, or song names here
Songs_in = ''; %// I had this as a cell array first, but tried to populate a string this time
while ischar(Songs) %// My while loop to pull out the song names
Songs_in = {Songs_in, Songs};
Songs = fgetl(Song_list);
if ischar(Songs_in) %//How I was trying to populate my string
song_info = [];
while ~isempty(Songs_in)
[name, time] = strtok(Songs_in);
song_info = [song_info {name}];
end
end
end
[songs, rest] = strtok(Songs, '-');
[minutes, seconds] = strtok(songs, ':');
[minutes2, seconds2] = strtok(time_remain, ':')
all_seconds = (minutes*60) + seconds; %// Converting the total time into seconds
all_seconds2 = (minutes2*60) + seconds2;
song_times = all_seconds;
time_remain = all_seconds2
time_remain = min(time_remain - song_times);
fclose(file_name);
end
Please and thank you for the help :)
A troublesome case:
song3 = pickSong('Resistance.txt', '3:57')
song3 => 'Exogenesis: Symphony Part 2 (Cross-Pollination)'
1. Uprising - 5:02
2. Resistance - 5:46
3. Undisclosed Desires - 3:56
4. United States of Eurasia (+Collateral Damage) - 5:47
5. Guiding Light - 4:13
6. Unnatural Selection - 6:54
7. MK ULTRA - 4:06
8. I Belong to You (+Mon Coeur S'ouvre a Ta Voix) - 5:38
9. Exogenesis: Symphony Part 1 (Overture) - 4:18
10. Exogenesis: Symphony Part 2 (Cross-Pollination) - 3:57
11. Exogenesis: Symphony Part 3 (Redemption) - 4:37
Here is my implementation:
function song = pickSong(filename, time_remain)
% read songs file into a table
t = readSongsFile(filename);
% query song length (in seconds)
len = str2double(regexp(time_remain, '(\d+):(\d+)', ...
'tokens', 'once')) * [60;1];
% find closest match
[~,idx] = min(abs(t.Duration - len));
% return song name
song = t.Title(idx);
end
function t = readSongsFile(filename)
% read the whole file (as a cell array of lines)
fid = fopen(filename,'rt');
C = textscan(fid, '%s', 'Delimiter',''); C = C{1};
fclose(fid);
% parse lines of the form: "0. some name - 00:00"
C = regexp(C, '^(\d+)\.\s+(.*)\s+-\s+(\d+):(\d+)$', 'tokens', 'once');
C = cat(1, C{:});
% extract columns and create a table
t = table(str2double(C(:,1)), ...
strtrim(C(:,2)), ...
str2double(C(:,3:4)) * [60;1], ...
'VariableNames',{'ID','Title','Duration'});
t.Properties.VariableUnits = {'', '', 'sec'};
end
We should get the expected results on the test files:
>> pickSong('Funeral.txt', '3:13')
ans =
'Neighborhood #2 (Laika)'
>> pickSong('Resistance.txt', '3:57')
ans =
'Exogenesis: Symphony Part 2 (Cross-Pollination)'
Note: The code above uses MATLAB tables to store the data, which allows for easy manipulation. For example:
>> t = readSongsFile('Funeral.txt');
>> t.Minutes = fix(t.Duration/60); % add minutes column
>> t.Seconds = rem(t.Duration,60); % add seconds column
>> sortrows(t, 'Duration', 'descend') % show table sorted by duration
ans =
ID Title Duration Minutes Seconds
__ _____________________________ ________ _______ _______
10 'In the Backseat' 381 6 21
7 'Wake Up' 339 5 39
4 'Neighborhood #3 (Power Out)' 312 5 12
9 'Rebellion (Lies)' 310 5 10
5 'Neighborhood #4 (7 Kettles)' 289 4 49
1 'Neighborhood #1 (Tunnels)' 288 4 48
6 'Crown of Love' 282 4 42
8 'Haiti' 247 4 7
3 'Une annee sans lumiere' 220 3 40
2 'Neighborhood #2 (Laika)' 213 3 33
% find songs that are at least 5 minutes long
>> t(t.Minutes >= 5,:)
% songs with the word "Neighborhood" in the title
>> t(~cellfun(#isempty, strfind(t.Title, 'Neighborhood')),:)
I'm going to write an answer using most of what you have already written, instead of suggesting something completely different. Though regexp is a powerful too (and I like regular expressions), I find that it is too advanced for what you have learned so far, so let's scrap it for now.
This way, you get to learn what was wrong with your code, as well as how awesome of a debugger I am (just kidding). What you have when reading in the text file almost works. You made a good choice in creating a cell array to store all of the strings.
I'm also going to borrow MrAzzaman's logic in calculating the time in seconds through strtok (awesome job btw).
In addition, I'm going to change your logic a bit so that it makes sense to me on how I would do it. Here's the basic algorithm:
Open up the file and read the first line (song) as you did in your code
Initialize a cell array that contains the first song in the text file
Until we reach the end of the text file, read in the entire line and add it into the cell array. You've also noticed that as soon as you hit a -1, we don't have any more songs to read, so break out of the loop.
Now that we have our songs in a cell array, which include the track number, song and the time for each song, we are going to create two more cell arrays. The first one will store just the times of the songs as strings, with both the minutes and the seconds delimited by :. The next one will just contain the names of the songs themselves. Now, we go through each element in our cell array that we created from Step #3.
(a) To populate the first cell array, I use strfind to find all occurrences of where the - character occurs. Once I find where these occur, I choose the last location of where the - occurs. I use this to index into our song string, and skip over 2 characters to skip over the - character and the space character. We extract all of the characters from this point until the end of the line to extract our times.
(b) To populate the second cell array, I again use strfind, but then I figure out where the spaces occur, and choose the index of where the first space happens. This corresponds to the gap in between the song number and the track of the song. Using my result of the index from (a), I extract the song title by skipping one character from the index of the first space to the index two characters before the last - character to successfully get the song. This is because there will probably be a space in between the last word of the song title before the - character so we want to remove that space.
Next, for each song time in the first cell array computed in Step #4, I use strtok like you have used and split up the string by the :. MrAzzaman has used this as well and I'm going to borrow his logic on computing the total amount of seconds that each time takes.
Finally, we figure out which time is the closest to the time remaining. Note that we also need to convert the time remaining into seconds like we did in Step #5. As MrAzzaman has said, you can use the min function in MATLAB, and use the second output of the function. This tells you where in the array the minimum occurred. As such, we simply search for the minimum difference between the time remaining and the time elapsed for each song. Take note that you said you don't care whether or not you go over or under the time elapsed. You just want the closest time. In that case, you need to take the absolute value of the time differences. Let's say you had a song that took 3:59 and another song that was 6:00, and the time remaining was 4:00. Assuming that there is no song that is 4:00 long in your track, you would want to choose the song that is at 3:59. However, if you just subtract the time remaining from the longer track (6:00), you would get a negative difference, and min would return this track... not the song at 3:59. This is why you need to take the absolute value, so this will disregard whether you're over or under the time remaining.
Once we figure out which song to choose, return the song name that gives us the minimum. Make sure you close the file too!
Without further ado, here's the code:
function [song] = pickSong(file_name, time_remain)
% // Open up the file
fid = fopen(file_name, 'r');
%// Read the first line
song_name = fgetl(fid);
%// Initialize cell array
song_list = {song_name};
%// Read in the song list and place
%// each entry into a cell array
while ischar(song_name)
song_name = fgetl(fid);
if song_name == -1
break;
end
song_list = [song_list {song_name}];
end
%// Now, for each entry in our song list, find all occurrences of the '-'
%// with strfind, and choose the last index that '-' occurs at
%// Make sure you skip over by 2 spaces to remove the '-' and the space
song_times = cell(1,length(song_list));
song_names = cell(1,length(song_list));
for idx = 1 : length(song_list)
idxs = strfind(song_list{idx}, '-');
song_times{idx} = song_list{idx}(idxs(end)+2:end);
idxs2 = strfind(song_list{idx}, ' ');
%// Figure out the index of where the first space is, then extract
%// the string that starts from 1 over, to two places before the
%// last '-' character
song_names{idx} = song_list{idx}(idxs2(1)+1 : idxs(end)-2);
end
%// Now we have a list of times for each song. Tokenize by the ':' to
%// separate the minutes and times, then calculate the number of seconds
%// Logic borrowed by MrAzzaman
song_seconds = zeros(1,length(song_list));
for idx = 1 : length(song_list)
[minute_str, second_str] = strtok(song_times{idx}, ':');
song_seconds(idx) = str2double(minute_str)*60 + str2double(second_str(2:end));
end
%// Now, calculate how much time is remaining from the input
[minute_str, second_str] = strtok(time_remain, ':');
seconds_remain = str2double(minute_str)*60 + str2double(second_str(2:end));
%// Now, choose the song that is closest to the amount of time
%// elapsed
[~,song_to_choose] = min(abs(seconds_remain - song_seconds));
%// Return the song you want
song = song_names{song_to_choose};
%// Close the file
fclose(fid);
end
With your two example cases you've shown above, this is the output I get. I've taken the liberty in creating my own text files with your (awesome taste in) music:
>> song1 = pickSong('Funeral.txt', '3:13')
song1 =
Neighborhood #2 (Laika)
>> song2 = pickSong('Resistance.txt', '3:57')
song2 =
Exogenesis: Symphony Part 2 (Cross-Pollination)
You can manage this with textscan, as follows:
function[song,len] = pickSong(file_name,time_remain)
fid = fopen(filename);
toks = textscan(fid,'%[^-] - %d:%d');
songs = toks{1};
song_len = double(toks{2}*60 + toks{3});
[min_rem, sec_rem] = strtok(time_remain, ':');
time_rem = str2double(min_rem)*60 + str2double(sec_rem(2:end));
[len,i] = min(abs(time_rem - song_len));
song = songs{i};
Note that this will only work if none of your song names have a '-' character in them.
EDIT: Here's a solution that (should) work on any song titles:
function[song,len] = pickSong(file_name,time_remain)
file = fileread(file_name);
toks = regexp(file,'\d+. (.*?) - (\d+):(\d+)\n','tokens');
songs = cell(1,length(toks));
song_lens = zeros(1,length(toks));
for i=1:length(toks)
songs{i} = toks{i}{1};
song_lens(i) = str2double(toks{i}{2})*60 + str2double(toks{i}{3});
end
[min_rem, sec_rem] = strtok(time_remain, ':');
time_rem = str2double(min_rem)*60 + str2double(sec_rem(2:end));
[len,i] = min(abs(time_rem - song_lens));
song = songs{i};
regexp is a MATLAB function that runs regular expressions on a string (in this case your file of song names). The string '\d+. (.*?) - (\d+):(\d+)\n' scans each line extracting the name and length of each song. \d+ matches one or more digit, while .*? matches anything. The brackets are for grouping the output. So, we have:
match n digits, followed by a (string), followed by (n-digits):(n-digits)
Every thing in brackets is returned as a cell array to the toks variable. The for loop is just extracting the song names and lengths from the resulting cell array.

Using fixedRate timer in MATLAB with different data for each interval (trying to replace for loop with timer)

Is there a way to have a MATLAB timer pass different data on each subsequent call to the timer function? My goal is to cycle through intervals at a fixed rate, and the pause function inside a loop is not precise enough.
I have workng MATLAB code that uses a for loop to send data via serial ports, then wait a specified time before the next iteration of the loop. The serial communication varies in speed, so if I specify 300 seconds as the period, the loop actually executes every 340-360 seconds. Here is the existing code:
clear all;
testFile = input('What is the name of the test data file (with extension): ', 's');
measurementData = csvread(testFile);
intervalDuration = input('What is the measurement change period (seconds): ');
intervalNumber = size(measurementData,2);
% Set up the COM PORT communication
sensorComPort = [101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120];
controllerComPort = [121,122,123,124];
for j=1:intervalNumber
tic
fprintf('\nInterval # %2d\n',rem(j,24));
sensorMeasurementPS = [measurementData(1,j),measurementData(2,j),measurementData(3,j),measurementData(4,j),measurementData(5,j), measurementData(6,j),measurementData(7,j),measurementData(8,j),measurementData(9,j),measurementData(10,j), measurementData(11,j),measurementData(12,j),measurementData(13,j),measurementData(14,j),measurementData(15,j), measurementData(16,j),measurementData(17,j),measurementData(18,j),measurementData(19,j),measurementData(20,j)];
serialSensorObj = startsensorPSWithoutReset(sensorComPort, sensorMeasurementPS);
serialSensorObj = changeMeasurement(serialSensorObj, sensorMeasurementPS);
rc = stopsensorPS(serialSensorObj);
controllerMeasurementPS = [measurementData(21,j),measurementData(22,j),measurementData(23,j),measurementData(24,j)];
serialControllerObj = startControllerPSWithoutReset(controllerComPort, controllerMeasurementPS);
serialControllerObj = changeMeasurement(serialControllerObj, controllerMeasurementPS);
rc2 = stopControllerPS(serialControllerObj);
pause(intervalDuration);
t = toc;
fprintf('Elapsed time = %3.4f\n',t);
end
clear serialSensorObj;
clear serialControllerObj;
The serial functions are specified in other files and they are working as intended.
What I need to do is have the serial communication execute on a more precise 5-minute interval. (The actual timing of the commands inside the interval will still vary slightly, but the commands will kick off every 5 minutes over the course of 24 hours. The current version loses time and gets out of sync with another system that is reading the measurements I'm setting by serial port.)
My first thought is to use a MATLAB timer with the fixedRate execution mode, which queues the function at fixed intervals. However, it doesn't appear that I can send the timer function different data for each interval. I thought about having the timer function change a counter in the workspace, similar to j in my existing for loop, but I know that having functions interact with the workspace is not recommended.
Here's what I've come up with so far for the timer method:
function [nextJ] = changeMeasurement_fcn(obj,event,j,sensorComPort,controllerComPort)
tic
fprintf('\nInterval # %2d\n',rem(j,24));
sensorMeasurementPS = [measurementData(1,j),measurementData(2,j),measurementData(3,j),measurementData(4,j),measurementData(5,j), measurementData(6,j),measurementData(7,j),measurementData(8,j),measurementData(9,j),measurementData(10,j), measurementData(11,j),measurementData(12,j),measurementData(13,j),measurementData(14,j),measurementData(15,j), measurementData(16,j),measurementData(17,j),measurementData(18,j),measurementData(19,j),measurementData(20,j)];
serialSensorObj = startSensorPSWithoutReset(sensorComPort, sensorMeasurementPS);
serialSensorObj = changeMeasurement(serialSensorObj, sensorMeasurementPS);
rc = stopSensorPS(serialSensorObj);
controllerMeasurementPS = [measurementData(21,j),measurementData(22,j),measurementData(23,j),measurementData(24,j)];
serialControllerObj = startControllerPSWithoutReset(controllerComPort, controllerMeasurementPS);
serialControllerObj = changeMeasurement(serialControllerObj, controllerMeasurementPS);
rc2 = stopControllerPS(serialControllerObj);
t2 = toc;
fprintf('Elapsed time = %3.4f\n',t2);
and this is how I would call it from the main m file:
t = timer('TimerFcn',#changeMeasurement,'ExecutionMode','fixedRate','period',intervalDuration);
% then I need some code to accept the returned nextJ from the timer function
This feels a bit sloppy so I'm hoping there's a built-in way to have a timer cycle through a data set.
Another idea I had was to keep the for loop but change the pause function to use a value calculated based on how much time would add up to 5 minutes for the iteration.
To summarize my question:
a) Can I have a timer pass different data to the timer function on each iteration?
b) Is that a good way to go about cycling through the intervals in my data on a precise 5-minute interval?
Thanks!
I stumbled on this page: http://www.mathworks.com/company/newsletters/articles/tips-and-tricks-simplifying-measurement-and-timer-callbacks-with-nested-functions-new-online-support-features.html
and learned that timer callback functions can be nested inside other functions (but not regular scripts).
Using that information, I cut my scenario to the basics and came up with this code:
function timerTestMain_fcn
testFile = input('What is the name of the test data file (with extension): ', 's');
testData = csvread(testFile);
intervalDuration = input('What is the voltage change period (seconds): ');
intervalNumber = size(testData,2);
t = timer('ExecutionMode','fixedRate','period',intervalDuration,'TasksToExecute',intervalNumber);
t.TimerFcn = {#timerTest_fcn};
start(t);
wait(t);
delete(t);
function timerTest_fcn(obj,event)
tic
event_time = datestr(event.Data.time);
interval_id = t.TasksExecuted;
data_value = testData(1,interval_id);
txt1 = 'Interval ';
txt2 = num2str(interval_id);
txt3 = ' occurred at ';
txt4 = ' with data value of ';
txt5 = num2str(data_value);
msg = [txt1 txt2 txt3 event_time txt4 txt5];
disp(msg)
t2 = toc;
fprintf('Elapsed time = %3.4f\n',t2);
end
end
The test data file it requests must be a csv containing a row vector. For example, you could put the values 11,12,13,14,15 across the first row of the csv. The output message would then say 'Interval 1 occurred at [time] with data value of 11', 'Interval 2 occurred at [time] with data value of 12', etc.
The key is that by nesting the functions, the timer callback can reference both the test data and the timer attributes contained in the outer function. The TasksExecuted property of the timer serves as the counter.
Thanks to anyone who thought about my question. Comments welcome.