Efficient way to update plot data - matlab

I'd like to improve the efficiency of my GUI in app designer, even if it involves frontloading figure generation once so as to save time in subsequent views/updates.
I'm trying to update a UIAxes which includes 4 patch() handles, and approximately 10 plot3() handles referencing approximately 30 lines. The goal is to generate the figure, and then have the ability to update the location of all of the data over 120 different timepoints. ("Play" through the results)
The problem is that it takes approximately 1.5seconds to update the figure once. Updating the patch() handles is approximately an order of magnitude faster than the plot3() handles. While my code doesn't need to run instantly, I was hoping it might update much faster (< 0.5 seconds per timepoint).
I'm using the following syntax to update (as an example) one of my plot3 handles, which includes 3 distinct line objects (thus the cell referencing of {'XData'}):
set(p1.foo1,{'XData'},num2cell([foo1.fem.nds(:,1,1) foo1.tib.nds(:,1,1)],2));
set(p1.foo1,{'YData'},num2cell([foo1.fem.nds(:,2,1) foo1.tib.nds(:,2,1)],2));
set(p1.foo1,{'ZData'},num2cell([foo1.fem.nds(:,3,1) foo1.tib.nds(:,3,1)],2));
This takes approximately 0.3 seconds to run, and is only 1 of 5 plot3 handles. I've also tried running the set() command inside a loop to avoid the num2cell call as I assumed it was slower. Unfortunately that slowed things down even more.
So I'm wondering if anyone is familiar with another solution to either:
1) Updating the plot data in a faster more efficient way than I've described here.
2) Frontloading all of these figure assemblies (120 time points, 120 figures), and maybe just placing them into my GUI one at a time as I play through my time series by adding and removing each individual figure from my UIAxes as I cycle through the 120 points. I realize this will take more memory, but I'd rather more memory than more time.
I hope this was clear, any suggestions would be appreciated.

It seems as if you're asking for general advice. If you'd like more specific answers, try creating a minimum reproducible example.
Otherwise, some general tips:
Don't store data in cells. The set() method for line objects can be used with standard numeric arrays: primative line documentation
Struct in MATLAB has some overhead associated with it. It looks like you have multiple nested structs holding numeric arrays. Retrieving this data from that struct might be slow. You can always use tic/toc to see how slow it is. But in general, avoid structs when possible and store the numeric data as its own variable. For more info, see some advice on arrays of structs vs. structs of arrays.

Related

matlab cell array size much larger than actual data

I recently discovered an strange behavour of MATLAB cell arrays that was not happening before.
If I create a cell array with
a=cell(1,4)
its size is 32 bytes.
If then I put something inside, e.g.
a{2}='abcd'
its size becomes 144 bytes. But if I remove this content by putting
a{2}=[]
the size becomes 132 bytes and so on. What is the problem?
Simply put, the Matlab cell array needs some internal data structures to keep track of what is stored within.
As it seems, Matlab allocates memory as needed, and thus extends the storage needed by the cell array as you insert data.
Removing the data doesn't mean that matlab can return the now unused memory to the OS or internal memory pool -- that might either be something that is impossible with the internal storage structure, or something that would be unwise with respect to performance, because cell arrays from which data is removed are (speaking over all use cases of cell arrays) be structures that get updated often, so that "prematurely" returning memory just to acquire it back again a few instructions later would be pretty CPU-intense.
As a general note: Matlab has pretty terrible storage approaches for nearly everything but matrices and sparse matrices (vectors of course being special cases of matrices). That's because it's not Matlab's job to be e.g. a string parser etc.
If memory becomes a problem, it might be worth considering implementing the math core of your problem in Matlab and doing the rest in other, more generally usable programming languages and somehow interfacing your Matlab code with that -- I haven't tried that myself, but Mathworks has a Matlab engine for python, and I'd take writing python for things like storing arbitrary data over using Matlab every day; with that engine, you can call Matlab to do your dirty math work, and use python to do your everyday scripting/programming work.
Notice that my bottom line here is that Matlab has great Math routines and impressive documentation, but if you want to actually develop software, using a general purpose tool/language is much more likely to be satisfying quickly.
I'd even go as far as saying that it's probably worth your time to learn python, just to be able to circumvent having to deal with things that Matlab wasn't designed for (and cell arrays are a prime example of what Matlab is really complicated about and what's extremely easy in python).
You use
a{2}=[]
to 'kill' the data in that field. In reality you actually do access the data, that is you leave a non-empty cell entry with an empty double array. (Thanks to matlab for representing empty cells as empty doubles...)
but if you use (no curly braces, but parentheses):
a(2) = cell(1,1)
then the cell array size is back to "empty" = 32 bytes.

Bootstrapping in Matlab - how many original data points are used?

I have data sets for two groups, with one being much smaller than the other. For that reason, I am using the MatLab bootstrapping function to estimate the performance of the smaller group. I have code that draws on my original data, and it generates 1000 'new' means. However, it is not clear as to how many of the original data points are used each time. Obviously, if all the original data was used, the same mean would continue to be generated.
Can anyone help me out with this?
Bootstrapping comes from sampling with replacement. You'll use the same number of points as the original data, but some of them will be repeated. There are some variants of bootstrapping which work slightly differently, however. See https://en.wikipedia.org/wiki/Bootstrapping_(statistics).

Implementing runtime-constant persistent "LUT"s in MATLAB functions

I am implementing (for class, so no built-ins!) a variant of the Hough Transform to detect circles in an image. I have a working product, and I get correct results. In other words, I'm done with the assignment! However, I'd like to take it one step further and try to improve the performance a little bit. Also, to forestall any inevitable responses, I know MATLAB isn't exactly the most performance-based language, and I know that the Hough transform isn't exactly performance-based either, but hear me out.
When generating the Hough accumulation space, I end up needing to draw a LOT of circles (approximately 75 for every edge pixel in the image; one for each search radius). I wrote a nifty function to do this, and it's already fairly optimized. However, I end up recalculating lots of circles of the same radius (expensive) at different locations (cheap).
An easy way for me to optimize this was precalculate a circle of each radius centered at zero once, and just select the proper circle and shift it into the correct position. This was easy, and it works great!
The trouble comes when trying to access this lookup table of circles.
I initially made it a persistent variable, as follows:
[x_subs, y_subs] = get_circle_indices(circ_radius, circ_x_center, circ_y_center)
persistent circle_lookup_table;
% Make sure the table's already been generated; if not, generate it.
if (isempty(circle_lookup_table))
circle_lookup_table = generate_circles(100); %upper bound circ size
end
% Get the right circle from the struct, and center it at the requested center
x_subs = circle_lookup_table(circ_radius).x_coords + circ_x_center;
y_subs = circle_lookup_table(circ_radius).y_coords + circ_y_center;
end
However, it turns out this is SLOW!
Over 200,000 function calls, MATLAB spent on average 9 microseconds each call just to establish that the persistent variable exists! (Not the isEmpty() call, but the actual variable declaration). This is according to MATLAB's built-in profiler.
This added back most of the time gained from implementing the lookup table.
I also tried implementing it as a global variable (similar time to check if the variable is declared) or passing it in as a variable (made the function call much more expensive).
So, my question is this:
How do I provide fast access inside a function to runtime-constant data?
I look forward to some suggestions.
It is NOT runtime-constant data, since your function has the ability of generating the table. So your main problem is to discard this instruction from the function. Before all the calls of this critical function, make sure that this array is generated elsewhere outside the function.
However, there is a nice trick I've read from Matlab's files, and more specifically bwmorph. For each functionality of this particuliar function which requires a LUTs, they have created a function which returns the LUT itself (the LUT is written explicitely in the file). They also add an instruction coder.inline('always') to ensure that this function will be inlined. It seems to be quite efficient!

MATLAB figure export is very slow compared to R

I regularly have to export many figures (hundreds) into a single file. Currently I use
print('-dpsc2', outfile, '-append');
My code uses a single hidden figure that is being re-used for each new figure.
Now, the problem is that I can achieve a maximum export speed of around 8 figures per second. In R, you can easily plot around 200 figures per second. Does anyone have any suggestions how to (substantially) speed up MATLAB's exporting capabilities?
Jan
I feel your pain. This issue is also why the getframe function for generating movies is so inefficient. The only way I know around it is to write a simpler function that calls the low-level hardcopy function. Here's an example of this for image-based graphics along with some caveats. The hardcopy function supports both the 'dpsc2' and 'append' options that print does:
hardcopy(gcf,'outfile.ps','-dpsc2','-append');
Whereas print(gcf,'-dpsc2', 'outfile.ps', '-append'); takes about 0.12 seconds, the above takes only 0.004 seconds on my machine!
If you do help hardcopy you won't get very much information. However, if you need to reverse engineer anything you can read the code for print (edit print) or the various private functions it calls (e.g., edit private/render, edit private/paperfig, edit private/ghostscript).

Collect more than 10,000 data points from a Tektronix oscilloscope?

I am building a MATLAB GUI to do data collection from a Tektronix DPO4104 oscilloscope (MATLAB driver here).
I am playing around with tmtool and with my GUI code and have found that the driver can only collect 10,000 data points, regardless of if the oscilloscope is set to show more than 10k points. I found this post on in CCSM but it hasn't been terribly helpful. (I'm the last post on there if you care to read it.) I am using the DPO4104 driver, whereas this post discusses use of the DPO4100 driver, I believe.
As far as I can tell, the steps are:
Edit driver's readwaveform function to account for the current recordLength - in my case, 100,000 points, say.
Manually edit the driver's MaxNumberPoint from 10,000 to 100,000. (In my case, the default number was 0.. I changed this to 100,000).
Manually edit EndingPoint. I set this to 100,000 also.
Before creating a device object, set(interfaceObj, 'InputBufferLength', 2.5*recordLength), that is, make sure the input buffer can fit more than 100,000 points. It's recommended to use at least double the expected buffer. I used 2.5 just because.
Build device object and waveform object, connect() to it, and readwaveform. Profit.
I am still unable to collect more than 10,000 points, either through tmtool or through my GUI. Any help would be appreciated.
I got ahold of a Tektronix engineer; he basically told me just to use the SCPI commands directly and skip the driver. While annoying, this might be the simplest solution.
Is it possible for you to collect the data points 10,000 at a time, then save them somewhere, collect the next 10,000, append them to the saved points, repeat?
It's a work-around, sure.
I figured it out! I think. Taking a couple weeks to step back and refresh really helped. Here's what I did:
1) Edit the driver's init function to configure a larger buffer size. Complete init code:
function init(obj)
% This method is called after the object is created.
% OBJ is the device object.
% End of function definition - DO NOT EDIT
% Extract the interface object.
interface = get(obj, 'Interface');
fclose(interface);
% Configure the buffer size to allow for waveform transfer.
set(interface, 'InputBufferSize', 12e6);
set(interface, 'OutputBufferSize', 12e6); % Originally is set to 50,000
I originally tried to set the the buffer sizes to 22e6 (I wanted to get 10 million points) but I got out-of-memory errors. Supposedly the buffer should be a little more than double what you expect to get out, plus space for headers. I probably don't need 2 million points worth of "header", but eh.
2) Edit the driver's readwaveform() to first query what the user-settable number of points to collect should be. Then, write SCPI commands to the scope to ensure that the number of data points to be transferred is equal to the number of points the user desires. The following snippet will do the trick in readwaveform:
try
% Specify source
fprintf(interface,['DATA:SOURCE ' trueSource]);
%----------BEGIN CODE TO HANDLE MORE THAN 10k POINTS----------
recordLength = query(interface, 'HORizontal:RECordlength?');
fprintf(interface, 'DATA:START 1');
fprintf(interface, 'DATA:STOP %d', str2num(recordLength));
%----------END CODE TO HANDLE MORE THAN 10k POINTS----------
% Issue the curve transfer command.
fprintf(interface, 'CURVE?');
raw = binblockread(interface, 'int16');
% Tektronix scopes send and extra terminator after the binblock.
fread(interface, 1);
3) In the user code, set a SCPI command to change the record size to the underlying interface object:
% interfaceObj is a VISA object.
fprintf(interfaceObj, 'HORizontal:RECordlength 5000000');
There you have it. Hopefully this helps out anyone else that's trying to figure out this issue.
Here's a bad idea. Start collecting 10,000 points. When you get to 5000 points, start collecting data again (you might need to run that in a new thread). Keep going back and forth until all the data you need are stored in 20 some data structures. Then, combine the structures into one structure by lining up the data points. This might be more work than calling the SCPI commands directly and might have some nasty caveats I haven't thought of. But as I said, it's a bad idea...