I would like to control a piezo driven z-stage (for microscopy) through a simple analog output (0-10V) by using a NI DAQ board and the Matlab session-based interface. This works so far but I need to dynamically update the z-postion very rapidly (best under 20 ms). However queuing and executing an updated voltage value takes over 150 ms right now. Is there any way to optimize this? Thanks!
Here is my code:
%% initialize DAQ, specify output channels and refreshrate
devices = daq.getDevices
s = daq.createSession('ni');
s.addAnalogOutputChannel('Dev1', 'ao0', 'Voltage');
s.Rate = 1000; %1ms refreshrate
%define output data (I only define one data point as DAQ board keeps that voltage until changed)
zVol = 4.8; % range of stage is 100 um => 10um/V
%Queue output data
s.queueOutputData(zVol);
%output signal
s.startBackground();
Related
I am trying to plot real-time data from a sensor that has a frequency of 25 Hz. I read data from the sensor using TCPIP protocol, parse it and then plot the data. However, the plotting part is not very fast and starts to lag after some time. So for e.g. if I move the sensor, I see the response 5 seconds later. I used Serial Plotter in Arduino (which has much less specifications than my laptop) but it is able to plot real-time data without any delays / problems.
My code looks a bit like the following
IMUData = nan(1500,6);
InterfaceObject = tcpip('my_ip_address',50001);
InterfaceObject.BytesAvailableFcn ={#PlotSensorData};
And the PlotSensorData function looks like
function PlotSensorData(~,~)
RecievedData = fscanf(InterfaceObject,'%s');
Identifier = RecievedData(6); % 6th byte is the sensor identifier
DataStartIdx = 28; % For each sensor, data start position is common
if Identifier == 'I'
DataEndIdx = DataEndPosition(RecievedData, 1);
SlicedData = RecievedData(DataStartIdx:DataEndIdx);
ParsedData = textscan(SlicedData,'%f', 'Delimiter',',');
% Append new data to IMUData matrices
prevval = IMUData;
val = [prevval(2:end,:); ParsedData{1}'];
IMUData = val;
set(PlotHandle{1},'ydata',val(:,3));
set(TopAxes,'ylim',[-15 15]);
drawnow limitrate;
end
end
Also, instead using plot, I have already tried animatedLine. It seems faster initially as it plots very fast, but after sometime, it starts to lag as well and the lag is more than 10 Sec.
So my questions are
What can be done to speed up the real-time data in MATLAB.
Also, I have already tried plotting the data after a certain number of samples (say 10, 20) are received instead of plotting after every received sample, but the results are still lagging and the GUI hangs as well. Is there any other strategy that I can use? In Python I used Multi-threading, but can I use it here as well? Or is there a better approach to handle this data rate?
I understand that Arduino is only running one script but the computer has a lot of overhead, but how is Arduino able to plot the data so fast while MATLAB just hangs up?
Thanks
Reading Data Asynchronously instead of continuously solved my problem.
I currently have NI BNC-2110 connect to the NI USB-6255 which is then connected to my computer.
My goal is to generate a digital output through the NI BNC-2110 and then read the output on an analog input on the same NI BNC-2110. (The purpose of this is to make sure that I know how to properly output a digital signal and can input an analog signal, and I figured this would just check both things simultaneously.)
The setup works when generating a digital signal and reading an analog when I use the software NI MAX, my problem is when I try and do the same thing in Matlab.
Here is my current code in Matlab:
d = daq.getDevices
s = daq.createSession('ni');
addAnalogInputChannel(s,'dev1', 'ai0', 'Voltage');
s.Rate = 8000;
q = daq.createSession('ni');
addDigitalChannel(q,'dev1','Port2/Line0:0','OutputOnly');
for p = 1:1:100
outputSingleScan(q,1)
pause(0.1)
data = s.inputSingleScan;
data
outputSingleScan(q,0)
pause(0.1)
data = s.inputSingleScan;
data
end
My current results are an analog input of ~0 Volts, and what I expect is a square wave from my analog input.
Any help on this would be much appreciated.
I am expecting something with a syntax in Matlab with port to be the problem, but not to sure.
I'm trying to record my microphone input and process it at the same time.
I tried with a loop with this inside:
recordblocking(recorder, 1);
y = getaudiodata(recorder);
% any processing on y
But while I'm doing something with y, I'm losing information since not recording continuously.
Is there something I could do to continuously record sound coming in my microphone, store it in some kind of buffer, and process chunks of it at the same time?
A delay isn't a problem, but I really need the recording and processing done simultaneously.
Thanks in advance for any help.
I think that you should use Stream processing like this:
% Visualization of audio spectrum frame by frame
Microphone = dsp.AudioRecorder;
Speaker = dsp.AudioPlayer;
SpecAnalyzer = dsp.SpectrumAnalyzer;
tic;
while(toc<30)
audio = step(Microphone);
step(SpecAnalyzer,audio);
step(Speaker, audio);
end
you can find more information here and also in this presentation
You can try the block processing framework in LTFAT
http://ltfat.github.io/doc/demos/demo_blockproc_basicloop_code.html
Edit:
This is the main gist of the code:
% Basic Control pannel (Java object)
p = blockpanel({
{'GdB','Gain',-20,20,0,21},...
});
% Setup blocktream
fs = block('playrec','loadind',p);
% Set buffer length to 30 ms
L = floor(30e-3*fs);
flag = 1;
%Loop until end of the stream (flag) and until panel is opened
while flag && p.flag
gain = blockpanelget(p,'GdB');
gain = 10^(gain/20);
% Read the block
[f,flag] = blockread(L);
% Play the block and do the processing
blockplay(f*gain);
end
blockdone(p);
Note that it is possible to specify input and output devices and their channels by passing additional arguments to the block function. List of available audio devices can be obtained by calling blockdevices.
I'm using Matlab's Data Acquisition Toolbox for interfacing with a National Instruments ADC. Unfortunately, I only have access to the hardware in my lab for limited parts of the day, but I'd like to be able to develop and test my code when I don't have access. Does anyone know of a way that I can collect some sample data, then feed it into the DAQ toolbox from a file instead of from the actual hardware? It needs to be input over time, same as it would with the NI hardware.
Current code:
s = daq.createSession('ni');
s.addAnalogInputChannel('Dev1',0,'Voltage');
s.Rate = 250;
s.DurationInSeconds = 30;
lh = s.addlistener('DataAvailable', #(src,event)myfunction(src,event));
s.NotifyWhenDataAvailableExceeds = 1000;
s.startBackground();
s.wait();
delete(lh);
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 ...