Problem creating loop using data from imported table/array - how to analyse & save data from each cycle?

1 view (last 30 days)
Hi! I need urgent help - I am really new to Matlab, but am trying to create a script to analyse data from an exported waveform (*.txt). I have successfully imported the file & done the peak analysis for one example trial, incl. saving min and max peaks to (unfortunately, so far different) tables, etc. Now I need to execute the whole thing for each of the 82 trials (and later average some of them) and can't seem to find a solution neither in books, nor online. I have 82 rows = trials of 500 ms & 500 columns = signal amplitude @every millisec
The imported table is called TestSkript. I extracted from it only the data I need. Then tried and failed miserably to create a loop for the rest of the script. This is an example of my latest effort, mimicking sth. I found in a book (mind you, I still have to apply it to more commands - but I am first trying to make it work at all):
var=TestSkript(1:82,17:517);
openvar('var')
data=table2array(var)
T = zeros(1,501);
T(1) = data(1,1:501);
for i=0:82;
i=i+1;
T(i) = data(i,:)
end
figure
plot(T)
Please, help! Any advice on how I can create a loop and execute it for one data row at a time is deeply appreciated.
  2 Comments
Guillaume
Guillaume on 12 Jun 2018
If your data is truly in a table then it's possible that rowfun may be all that is needed. Although from your description it doesn't sound that the data should be in a table.
In any case, for us to help you more we need a much better description of what you're wanting to do with each row of your data. The code you've given us is complete gibberish that would result in many errors. and does not appear to do anything with the rows.
amberjade_bg
amberjade_bg on 12 Jun 2018
Thank you for your fast response!
You are right, it is not urgent in any sense of the word - it is just how my supervisor put it. Sorry for the drama qeeen bit!
I have a txt file from SR-LAB Software program - each row of this is a trial in an experiment that gives an amplitude at a given timepoint. I need to plot each of those trials (rows), analyse the minimum and maximum peaks, create a baseline at a specific time interval and then substract that from the peaks at a different specific time point to normalise them (in some trials). All the peak analysis needs to be saved as a table in a file (e.g. *.cvs, *.xcl or similar).
Here is my analysis of a single trial (= first row from the table) that worked (after importing the txt file = TestSkript):
var=TestSkript;
openvar('var');
i = 1;
while i < 82
i = i + 1;
y=var{i,17:517}
%figure % remove comment to see all trials plotted
plot(y)
end
time = [0:500];
amp = var{1,17:517}; % here for 1st row, i.e. first trial (Startle 120)
plot(time,amp)
findpeaks(amp) %finds & displays all peaks in figure
[pks,locs] = findpeaks(amp)
maxpeakamp=pks'
maxpeaktime=locs'
Tmax = table(maxpeaktime,maxpeakamp)
writetable(Tmax,'maxpeaktable1.xls')
amp_inverted = -amp;
[pks_minpeak,locs_minpeak] = findpeaks(amp_inverted)
minpeakamp=pks_minpeak'
minpeaktime=locs_minpeak'
Tmin = table(minpeaktime,minpeakamp)
writetable(Tmax,'minpeaktable1.xls')
figure
hold on
plot(time,amp)
plot(locs,amp(locs),'rv','MarkerFaceColor','r')
plot(locs_minpeak,amp(locs_minpeak),'bs','MarkerFaceColor','b')
xlabel('Time (ms)')
ylabel('Amplitude (mV)')
title('Peak Analysis')
grid on
amp_base=amp(150:200);
time_base=time(150:200);
figure
fig=figure
plot(time_base,amp_base)
findpeaks(amp_base,'MinPeakDistance',0.002)
[pks_base,locs_base] = findpeaks(amp_base,'MinPeakDistance',0.002) % -> this one returns all peaks & their time dimension, which are more than 2 ms apart to exclude noise
xlabel('Time (ms)')
ylabel('Amplitude (mV)')
title('Baseline Peak Analysis: 150 to 200 ms')
baseline=mean(pks_base)
dim = [0.2 0.5 0.3 0.3];
str = {'Baseline (mV)','=' baseline};
annotation('textbox',dim,'String',str,'FitBoxToText','on');
saveas(fig,'baseline1.png')
grid on
basepeaktime=locs_base';
basepeakamp=pks_base';
Tbaseline = table(basepeaktime,basepeakamp);
writetable(Tbaseline,'baselinepeaktable1.xls')
amp_startle=amp(200:280)
time_startle=time(200:280)
figure
fig=figure
plot(time_startle,amp_startle)
findpeaks(amp_startle,'MinPeakDistance',0.002)
[pks_startle,locs_startle] = findpeaks(amp_startle,'MinPeakDistance',0.002) % -> this one returns all peaks & their time dimension, which are more than 2 ms apart to exclude noise
xlabel('Time (ms)')
ylabel('Amplitude (mV)')
title('Startle Peak Analysis: 200 to 280 ms')
startlepeaktime=locs_startle';
startlepeakamp=pks_startle'-baseline
Tstartle = table(startlepeaktime,startlepeakamp)
writetable(Tbaseline,'baselinepeaktable1.xls') % saves all returned baseline positive peaks (time vs amplitude) as a table
% display textbox in figure to give baseline (mean, mV)
dim = [0.2 0.5 0.3 0.3];
str = {'ASR (mV)'};
annotation('textbox',dim,'String',str,'FitBoxToText','on');
saveas(fig,'startle1.png')
grid on
I hope that is enough for you to understand what I mean... I might be rubbish at explaining it, since I am new here. Please, ask if sth is unclear. Thanks in advance!

Sign in to comment.

Answers (2)

Bob Thompson
Bob Thompson on 12 Jun 2018
Couple of things here. First for T(1) = data(1,1:501) you can't assign a matrix to a single double array element. If you are trying to assign all of the values of the first row of data to T then use T = data(1,:).
Second, don't start a loop index at 0, it's just not a good coding practice IMO. Also, you don't need i = i+1, as your index, i, is advance automatically each time the loop runs.
Your current loop does advance through each data row. If you want to perform some kind of calculation to that row then include the calculation into the loop and have the results saved into the loop. The setup you have now looks good, as you are essentially trying to save each row of data into an element of T. The only problem I see with this is that T is already defined as an array of doubles (based on the zeros function you used earlier), and therefore cannot contain an array in and individual element. I would suggest removing the line T = zeros(1,501);.
  2 Comments
amberjade_bg
amberjade_bg on 12 Jun 2018
Except, what I get is:
In an assignment A(:) = B, the number of elements in A and B must be the same.
Error in loop_search (line 627)
T(i) = data(i,:);
I will need to perform peak analysis for each, so it will look something like this:
T = data(1,:)
for i = 1:82
T(i) = data(i,:);
time = [0:500];
amp = T(i);
plot(time,amp)
findpeaks(amp)
[pks,locs] = findpeaks(amp)
maxpeakamp=pks'
maxpeaktime=locs'
Tmax = table(maxpeaktime,maxpeakamp)
writetable(Tmax,'maxpeaktable1.xls') %here I will need to find a way to give it a name, corresponding to the current i
end
Thank you in advance!
Bob Thompson
Bob Thompson on 12 Jun 2018
You're getting the error because you're trying to define a single numeric value using an entire row of an array.
size(T) == 1x501 % As determined by T = data(1,:);
size(T(i)) == 1x1 % Putting a single index like this yields a single element
size(data(i,:) == 1x501 % Same as data(1,:)
The quickest solution to this is to simply define T = data(i,:) within the for loop. T will be overwritten each time, but it will retain the proper size. Alternatively, you can turn T into a cell matrix, which allows for other matrices to be stored within each cell.
For the file naming I would suggest creating a dynamically created string within the loop, and using this string as your file name.
title = ['maxpeaktable',num2str(i),'.xls'];
writetable(Tmax,title);

Sign in to comment.


Guillaume
Guillaume on 13 Jun 2018
Step 1: Wrap all your code for processing one single row into a function that takes your table and the row number as input. E.g.:
function processsignal(signals, signumber)
time = 0:500;
amp = signals{signumber, 17:517};
%your code from plot(time, amp) onwards ...
plot(time, amp);
...
end
Step 2: Modify the save functions to generate the filenames using the signal number. e.g.
writetable(Tmax,'maxpeaktable1.xls')
becomes
writetable(Tmax, compose('maxpeaktable%02d.xls', signumber));
Use a similar compose format for all your file names.
Step 3: write the script that calls your function for row of your table:
for row = 1:82
processsignal(var, row);
end
Miscellaneous notes:
a)
str = {'Baseline (mV)','=' baseline};
is not the way to create a string. Again, use compose:
str = compose('Baseline (mv) = %f', baseline);
b)
figure
fig=figure
Creates two figures in succession. The first one will never be used.

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!