Matlab: exactly timed getsnapshot for real-time event analyzing - matlab

I got a camera triggered by external source at a constant rate of 1/0.14s, and Matlab for-loop is used to take timed pictures for real-time measurements. However, the elapsed time for 1 execution of "getsnapshot" is so different each time. Sometimes I get 1 picture with less than 0.14s and
sometimes it takes 0.5s to take a picture. Is there anyway to synchronize the "getsnapshot"
with the external trigger? or at least make the "getsnapshot" exactly timed?
The following is my code:
vid = videoinput('camera');
preview(vid);
for i=1:100
data=getsnapshot(vid);
%...data processing...
%....
clear data
end

First, delete the preview(vid) line, this is probably why the rep. rate you are getting is weird. When you take data you don't need this preview option on, as it takes resources from your cpu.
Then, you may need to set the camera properties on the imaq toolbox to be in triggered mode. For example, for a gentl camera type this might look something like:
triggerconfig(vid, 'hardware', 'DeviceSpecific', 'DeviceSpecific');
src = getselectedsource(vid);
src.FrameStartTriggerMode = 'On';
src.FrameStartTriggerActivation = 'RisingEdge';
src.FrameStartTriggerDelayAbs = 0;
src.FrameStartTriggerSource = 'Line1';
src.FrameStartTriggerOverlap = 'Off';
Then, with some camera's you can read their trigger out, that is whenever the camera is exposing, it sends a ttl to some output. Matlab way to define it is something like:
src.SyncOut1SyncOutPolarity = 'Normal';
src.SyncOut1SyncOutSource = 'Exposing';
Again, you'll need to play with your camera's options in the imaq tool.
Also, the data processing step that you take afterwards may take some time, so benchmark it to see you can take data and analyze it on the fly without bottlenecks happening.
Last, you can use getdata instead of getsnapshot (read the documentation to see their difference) , and in the form: [img, time, metadata] = getdata(vid);
This will give you timestamps for each image taken, so you can see what's happening. Also, instead of clear data use flushdata(vid) to keep the vid object from completely filling the memory buffer (though if you only run 100 iterations in a loop, you should be fine).

Related

How to control the figure which appears in bayesopt function?

bayesopt draws figures like this:
How to access such figures in order to modify title or something? If I use gcf it is not guaranteed I get the correct figure because I could change focus to another figure window during execution.
Apparently bayesopt does not allow you to return a figure handle. So I suggest that on the line directly after your call to bayesopt you call h=gcf;, thus forcing your program to return the figure handle to h, which can then be modified at any desired time, even when moving to other figures.
results = bayesopt(fun,vars,Name,Value); % execute bayesian optimisation
h = gcf; % directly after optimisation grab a figure handle
Now you can modify properties in h, e.g. for the title you'd simply do
h.CurrentAxes.Title.String = 'Your plot title'
The reason this works is that MATLAB does not display figures until the full code has finished running. At least that's the case for my script, where I generate a figure, perform a few minutes of optimisation, then generate another figure. Both figures get displayed at the same time, i.e. when MATLAB has finished running the full program. There's thus no way you can click other figures when the code is running, since they are simply not there. If you happen to have older figures open (from other scripts), focus gets shifted to the latest created figure anyway, the moment it's created in the code (so not when it's displayed), thus you'd need to click a figure in the few milliseconds between the bayesopt call finished and the gcf call, which I'd say is so improbable that it's not worth considering, especially since it requires manual intervention.
As was pointed out in comments by Cris Luengo and Dev-iL, the figures are tagged and can thus be found using findobj:
h1 = findobj(0,'tag','bayesopt.MinObjective')

(Matlab) Option to turn pause on and off from output callback of system(string)?

For an aerospace course aerelasticity I am doing an assignment with Nastran in Matlab (by using system(command) and bdf as input file).
I have attached a piece of my code as explanation. In this case the program Nastran produces a punch file (text) with displacements.
Currently the problem is that Matlab disregards the time Nastran needs for analysis to produce this punch file and continues on with the loop, however this punch file is not created yet so matlab turns out an error saying it does not exist and stops the loop.
I "have" a workaround for this by setting the pause times manually found from running it manually for increasing mesh sizes, this gives me at least some data on mesh convergence, however this is not a suitable method to use the rest of the assignment as it will take way too much time, therefore it must be automated.
I was thinking of setting a condition temporarily pausing the loop if the punch file does not exist and turning on again if it exists, however I got stuck with using a pause condition inside a while loop alltogether, it does not seem a solution to me.
Do you have any suggestions / ideas on what I could use / do how to get around this problem
or
know if there is a way to sent a callback from system(nastran) which i can use to create a condition to control the loop or something in that direction?
The following is a piece of code of the created function which turns out the Residual Mean squared error of the mesh which I use to see if the mesh converges:
%% Run Nastran
system('"C:\Users\$$$$\AppData\Roaming\MSC.Software\MSC_Nastran_Student_Edition\2014\Nastran\bin\nastranw.exe" nastranfile.bdf mem=1gb'); % Run the created bdf file
pause(15);
%% Read results and save all relevant results
fpc = fopen('nastranfile.pch','r')
line = 0;
for j=1:6;
line = line+1;
fgets(fpc);
end
line;
counter=0;
data = [];
while ~feof(fpc)
counter= counter+1;
str = fgets(fpc);
line=line+1;
str = str(61:73);
data(counter) = str2num(str)
fgets(fpc);
line=line+1;
end
line;
fclose(fpc);
% Find RMSE
mdl = fitlm(1:length(data),data);
RMEA = mdl.Rsquared.Adjusted;
RMSE = mdl.RMSE;

Parallel image processing with MATLAB

I have written a MATLAB program which performs calculations on a video. I think it is a perfect candidate to adapt to multiple cpu cores as there is a lot of averaging done. I am just sturggling with the first bit of sending each section of frames to each lab. Say (for simplicity) it is a 200 frame file. I have read some guides and using SPMD gotten this.
spmd
limitA = 1;
limitB = 200;
a = floor(((limitB-limitA)/numlabs)*(labindex-1)+limitA);
b = floor((((limitB-limitA)/numlabs)*(labindex-1)+limitA)+(((limitB-limitA)/numlabs)));
fprintf (1,'Lab %d works on [%f,%f].\n',labindex,a,b);
end
It successfully outputs that each worker will work on their respective section (Eg Lab 1 works on 1:50, Lab 2 50:100 etc).
Now where I am stuck is how do actually make my main body of code work on each Lab's section of frames. Is there a tip or an easy way to now edit my main code so it knows what frames to work on based on labindex? Adding spmd to the loop results in an error hence my question.
Thanks
Following on from what you had, don't you simply need something like this:
spmd
% each lab has its own different values for 'a' and 'b'
for idx = a:b
frame = readFrame(idx); % or whatever
newFrame = doSomethingWith(frame);
writeFrame(idx, newFrame);
end
end
Of course, if that's the sort of thing you're doing, you may need to serialize the frame writing (i.e. make sure only one process at a time is writing).

Force a Specific Camera Aquisition Framerate in a realtime Matlab Loop

I have a function running in real time controlling hardware timing, etc. I want to be able to record video as well, so I've created a global video object in matlab, and set the triggering to manual. Right now, I have it so that each iteration of the realtime loop I record a frame and write it to disk. I'm changing it so that Ill record to memory till I hit some limit, and then writing to disk. However, I'd like to guarantee no matter how fast the real time loop is running, I only capture 15 frames per second.
Thinking about though, how can I make it so that I capture the 15 frames not so dramatically close to each other? If the real time loop is running lightning fast, the 15 frames will just be gathered at the "beginning" and capture almost no change that has occurred during that second. In other words, the faster real time loop is, the more my sampling will act like 1 frame per second (which has 14 other copies made).
For example,
% Main File
function start()
global vid;
global myLogger;
vid = videoinput('winvideo', 1, 'MJPG_160x120');
src = getselectedsource(vid);
triggerconfig(vid, 'manual');
vid.FramesPerTrigger = 1;
vid.LoggingMode = 'disk&memory';
imaqmem(512000000); % 512 MB
myLogger = VideoWriter('C:\Users\myname\Desktop\output.avi', 'Motion JPEG AVI');
myLogger.Quality = 50;
myLogger.FrameRate = 15;
vid.DiskLogger = myLogger;
src.FrameRate = '15.0000';
vid.ReturnedColorspace = 'grayscale';
start(vid);
open(myLogger);
initiateFastLoop();
close(myLogger);
stop(vid);
end
The real time piece:
function initiateFastLoop
global vid;
global myLogger;
while(flag)
% perform lightning fast stuff
frame = getsnapshot(vid);
writeVideo(myLogger, frame);
end
end
The video generated is much higher framerate, and I don't want to capture a frame every single time realtime loop runs, and I don't want to set a simple upper limit because of the problem described above. Any help would be great!

Can you synchronize the data acquisition toolbox and the image acquisition toolbox of Matlab?

I'd like to simultaneously get data from a camera (i.e. an image) and an analog voltage using matlab. For the camera I use the imaq toolbox, for reading the voltage I use the daq toolbox (reading NI-USB device), with a following code:
clear all
% Prepare camera
vid = videoinput('gentl', 1, 'Mono8');
src = getselectedsource(vid);
vid.FramesPerTrigger = 1;
vid.TriggerRepeat = Inf;
triggerconfig(vid, 'hardware', 'DeviceSpecific', 'DeviceSpecific');
src.FrameStartTriggerMode = 'On';
src.FrameStartTriggerActivation = 'RisingEdge';
% prepare DAQ
s=daq.createSession('ni');
s.addAnalogInputChannel('Dev1','ai1','Voltage');
fid = fopen('log.txt','w');
lh = s.addlistener('DataAvailable',#(src,event)SaveData(fid,event));
s.IsContinuous = true;
% Take data
s.startBackground();
start(vid)
N=10;
for ii=1:N
im(:,:,ii)=getsnapshot(vid);
end
% end code
delete(lh );
fclose('all');
stop(vid)
delete(vid)
where the function SaveData is:
function SaveData(fid,event)
time = event.TimeStamps;
data = event.Data;
fprintf(fid, '%f,%f\n ', [time data]);
end
I do get images and a log.txt file with the daq trace (time and data), but how can I use the external triggering (that trigger the camera) or some other clock to synchronize the two?
For this example, the daq reads the camera triggering TTL signal (# 50 Hz), so I want to assign each TTL pulse to an image.
Addendum:
I've been searching and have found a few discussions (like this one) on the subject, and read the examples that are found in the Mathworks website, but haven't found an answer. The documentation shows how to Start a Multi-Trigger Acquisition on an External Event, but the acquisition discussed is only relevant for the DAQ based input, not a camera based input (it is also working in the foreground).
This will not entirely solve your problem, but it might be good enough. Since the synchronization signal you are after in at 50 Hz, you can use clock in order to create time stamps for both types of your data (camera image and analog voltage). Since the function clock takes practically no time (i.e. below 1e-7 sec), you can try edit to your SaveData function accordingly:
fprintf(fid, '%f,%f\n ', [clock time data]);
And in the for loop add:
timestamp(i,:)=clock;
Can you use the sync to trigger the AD board? From the USB-6009 manual...
Using PFI 0 as a Digital Trigger--
When an analog input task is defined, you can configure PFI 0 as a digital trigger input. When the digital trigger is enabled, the AI task waits for a rising or falling edge on PFI 0 before starting the acquisition. To use AI Start Trigger (ai/StartTrigger) with a digital source, specify PFI 0 as the source and select a rising or falling edge.
My experience suggests that delay between trigger and AQ is very short
I'm sorry I use Python or C for this, so I can't give you MatLab code, but you want to look at functions like.
/* Select trigger source */
Select_Signal(deviceNumber, ND_IN_START_TRIGGER, ND_PFI_0, ND_HIGH_TO_LOW);
/* specify that a start trigger is to be used */
DAQ_Config(deviceNumber, startTrig, extConv); // set startTrig = 1
/* start the acquisition */
DAQ_Start(deviceNumber, …)
If you want to take this route you could get more ideas from:
http://www.ni.com/white-paper/4326/en
Hope this helps,
Carl
This is yet no complete solution, but some thoughts that might be useful.
I do get images and a log.txt file with the daq trace (time and data), but how can I use the external triggering (that trigger the camera) or some other clock to synchronize the two?
Can you think of a way to calibrate your setup? I.e. modify your experiment and create a distinct event in both your image stream and voltage measurements, which can be used for synchronization? Just like this ...