function imaqcalc
%IMAQCALC Create an image acquisition calculator.
%
% IMAQCALC creates an interface for calculating the approximate image
% acqusition rate you can expect based on the image and acquisition
% parameters you desire.
%
% In most cases, how fast you can acquire image data is dependent on
% various parameters. In certain cases, the acquisition rate will be
% limited by the bandwidth of the bus being used. In other cases, how
% fast you can stream image data to memory will be limited by the
% hardware's pixel clock, the image resolution and bit depth, and the
% amount of memory available on your system.
%
% The interface created consists of different panels that help you
% calculate the different parameters associated with acquiring image
% data. These panels are:
%
% Hardware Parameters - allows you to select the bus type you wish
% to use for the acquisition, as well as the
% maximum pixel clock supported by the hardware.
% Image Parameters - defines the charactersitics of the image data
% you wish to acquire.
% Frames To Buffer - used to determine the number of image frames
% you can acquire into memory.
% Target Data Rate - allows you to specify the desired data rate
% you wish to achieve during the acquisition.
% Target Pixel Clock - allows you to specify the desired pixel clock
% for the acquisition.
% Target Frame Rate - allows you to specify the desired acquisition
% frame rate you want to achieve.
%
% There are 3 types of messages IMAQCALC will display for each panel:
%
% "...OK" - the desired acquisition setting can be
% met with the given hardware, image, and
% acquisition parameters.
% "...too high" - the desired acquisition settings are too
% high given the hardware, image, and
% acquisition parameters specified. This
% requires some adjustments be made to the
% image or acquisition settings.
% "...bandwidth exceeded" - the desired acquisition settings may
% exceed the bandwidth limitations of the
% bus. If the hardware uses compression or
% on-board memory to manage the data
% transfer, the specified acquisition
% settings may be sustainable.
%
% Note, all calculations are based on transferring raw, uncompressed
% image data.
%
% Memory availability is determined using the IMAQMEM function provided
% by the Image Acquisition Toolbox. If the Image Acquisition Toolbox is
% not available, the Frames To Buffer panel will not be updated.
%
% See also IMAQMEM, TIMER.
% CP 4-13-04
% Copyright 2004 The MathWorks, Inc.
% Search for an existing figure.
[fig, figName] = localFindFigure;
if ~isempty(fig)
figure(fig);
return;
end
% Constants.
% 1 MB = 1,048,576 bytes
% Bus rates => MB = (MHz*bits) * 1 byte/8 bits
constants.bytesPerMb = 1048576;
constants.maxMbPerSecond = {...
'Ethernet (T10)', 1.25, ...
'USB 1.x', 1.5, ...
'Ethernet (T100)', 12.5, ...
'FireWire (IEEE-1394)', 50, ...
'USB 2.0', 60, ...
'Gigabit Ethernet', 125, ...
'PCI (33MHz / 32bit)', 132, ...
'PCI (66MHz / 32bit)', 264, ...
'PCI (66MHz / 64bit)', 528, ...
'PCI-X (133MHz / 64bit)', 1064, ...
};
% Need to create the base figure.
figProps.CreateFcn = {@movegui, 'center'};
figProps.DeleteFcn = @localTimerMngr;
figProps.MenuBar = 'none';
figProps.Name = figName;
figProps.NumberTitle = 'off';
figProps.Tag = strrep(figName, ' ', '');
figProps.Units = 'normalized';
figProps.Userdata = constants;
fig = figure(figProps);
figColor = get(fig, 'Color');
% Create the different panels.
xEdgeOffset = 0.01;
yEdgeOffset = 0.01;
localCreateHWParamsPanel(xEdgeOffset, yEdgeOffset);
localCreateIMParamsPanel(xEdgeOffset, yEdgeOffset);
localCreateBufferPanel(xEdgeOffset, yEdgeOffset);
localCreateDataRatePanel(xEdgeOffset, yEdgeOffset);
localCreatePxlClockPanel(xEdgeOffset, yEdgeOffset);
localCreateFPSPanel(xEdgeOffset, yEdgeOffset);
% Configure generic settings for UI panels and controls.
uips = findobj(fig, 'Type', 'uipanel');
uitext = findobj(fig, 'Type', 'uicontrol', 'Style', 'text');
uiedits = findobj(fig, 'Type', 'uicontrol', 'Style', 'edit');
set([uips;uitext], 'BackgroundColor', figColor)
set(uiedits, 'BackgroundColor', 'white')
set(uips, 'TitlePosition', 'centertop');
% Initialize values and hide the figure once
% all the UI controls have been added.
localInitUI(fig);
set(fig, 'HandleVisibility', 'off');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIGURE UI CALLBACKS:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localInitUI(fig)
handles = guihandles(fig);
% Configure the callbacks for all the uicontrols
% the user might change.
set(handles.BusType, 'Callback', @localIMParamsCallback)
set(handles.MaxBoardClock, 'Callback', @localIMParamsCallback)
set(handles.Width, 'Callback', @localIMParamsCallback)
set(handles.Height, 'Callback', @localIMParamsCallback)
set(handles.BitsPerPixel, 'Callback', @localIMParamsCallback)
set(handles.FPSFramesPerSecond, 'Callback', @localFPSCallback)
set(handles.DataRateMbPerSecond, 'Callback', @localDataRateCallback)
set(handles.PixelClock, 'Callback', @localPixelClockCallback)
set(handles.FramesToBuffer, 'Callback', @localBufferCallback)
% Once the callbacks are set up, initialize all
% controls to their default values.
set(handles.MaxBoardClock, 'String', '25')
set(handles.Width, 'String', '640')
set(handles.Height, 'String', '480')
set(handles.BitsPerPixel, 'String', '24')
set(handles.FPSFramesPerSecond, 'String', '30')
set(handles.DataRateMbPerSecond, 'String', '50')
set(handles.PixelClock, 'String', '25')
set(handles.FramesToBuffer, 'String', '10')
% Configure the timer object so we
% can update the Buffer panel.
localTimerMngr(fig);
% Trigger all the callbacks to calculate
% the different values for the panels based
% on the defaults we just configured.
localIMParamsCallback(fig, []);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localTimerMngr(obj, event)
% Create or clean up the timer object used to
% update the Buffer panel.
if nargin==2,
% Need to clean up the timer.
t = timerfind('Tag', get(obj, 'Name'));
if ~isempty(t)
stop(t);
delete(t);
end
else
handles = guihandles(obj);
if exist('imaqmem')==2
% Create a timer to update the memory status.
t = timer('Tag', get(obj, 'Name'), 'ExecutionMode', 'fixedSpacing', ...
'TimerFcn', {@localTimerCallback, handles.MemoryAvailable, ...
handles.MaxFrames, handles.MbPerFrame});
start(t)
else
warning('MATLAB:imaqcalc:noimaq', ...
'The Image Acquisition Toolbox IMAQMEM function is unavailable.\nThe Frames To Buffer panel will not be updated.');
set(handles.FramesToBuffer, 'String', '0', 'Enable', 'off')
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localTimerCallback(obj, event, memField, maxFramesField, mbFrameField)
% Executed by the timer object to update the buffer
% panel with the current memory information.
if isvalid(obj),
mbMemory = imaqmem('AvailPhys')/1000000;
set(memField, 'String', mbMemory);
mbFrame = str2num(get(mbFrameField, 'String'));
set(maxFramesField, 'String', floor(mbMemory/mbFrame));
localBufferCallback(memField, event);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localIMParamsCallback(obj, event)
% Callback for the ImageParameters panel.
handles = guihandles(obj);
height = str2num(get(handles.Height, 'String'));
width = str2num(get(handles.Width, 'String'));
bitsPerPixel = str2num(get(handles.BitsPerPixel, 'String'));
% Update the panel values.
set(handles.PixelsPerFrame, 'String', height*width)
set(handles.BitsPerFrame, 'String', height*width*bitsPerPixel)
set(handles.BytesPerFrame, 'String', height*width*bitsPerPixel/8)
set(handles.MbPerFrame, 'String', height*width*bitsPerPixel/8/1048576)
% Notify all other callbacks.
localFPSCallback(obj, event);
localDataRateCallback(obj, event);
localPixelClockCallback(obj, event);
localBufferCallback(obj, event);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localBufferCallback(obj, event)
% Callback for the Buffer panel.
handles = guihandles(obj);
toBuffer = str2num(get(handles.FramesToBuffer, 'String'));
% Check limits.
maxFrames = str2num(get(handles.MaxFrames, 'String'));
failed = toBuffer>maxFrames;
localUpdateMsg(0, handles.FramesToBufferMsg, ...
failed, 'The number of frames to buffer ');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localDataRateCallback(obj, event)
% Callback for the DataRate panel.
handles = guihandles(obj);
mbs = str2num(get(handles.DataRateMbPerSecond, 'String'));
mbFrame = str2num(get(handles.MbPerFrame, 'String'));
% Update the panel values.
desFPS = mbs/mbFrame;
set(handles.DataRateFramesPerSecond, 'String', desFPS)
% Check limits.
maxClock = str2num(get(handles.MaxBoardClock, 'String'));
pixelsPerFrame = str2num(get(handles.PixelsPerFrame, 'String'));
failed = desFPS*pixelsPerFrame/1000000>maxClock;
localUpdateMsg(mbs, handles.DataRateMsg, failed, 'Your data rate ');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localPixelClockCallback(obj, event)
% Callback for the PixelClock panel.
handles = guihandles(obj);
pixelClock = str2num(get(handles.PixelClock, 'String'));
pixelsPerFrame = str2num(get(handles.PixelsPerFrame, 'String'));
bytesPerFrame = str2num(get(handles.BytesPerFrame, 'String'));
% Update the panel values.
set(handles.SecondsPerFrame, 'String', pixelsPerFrame/(pixelClock*1000000))
secFrame = str2num(get(handles.SecondsPerFrame, 'String'));
fps = 1/secFrame;
set(handles.PixelClockFramesPerSecond, 'String', fps)
set(handles.PixelClockMbPerSecond, 'String', fps*bytesPerFrame/1000000)
% Check limits.
maxClock = str2num(get(handles.MaxBoardClock, 'String'));
failed = pixelClock>maxClock;
mbs = str2num(get(handles.PixelClockMbPerSecond, 'String'));
localUpdateMsg(mbs, handles.PixelClockMsg, failed, 'Your pixel clock ');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localFPSCallback(obj, event)
% Callback for the FramesPerSecond panel.
handles = guihandles(obj);
fps = str2num(get(handles.FPSFramesPerSecond, 'String'));
pixelsPerFrame = str2num(get(handles.PixelsPerFrame, 'String'));
bytesPerFrame = str2num(get(handles.BytesPerFrame, 'String'));
% Update the panel values.
equivClock = fps*pixelsPerFrame/1000000;
set(handles.EquivalentPixelClock, 'String', equivClock)
set(handles.FPSMbPerSecond, 'String', fps*bytesPerFrame/1000000)
% Check limits.
maxClock = str2num(get(handles.MaxBoardClock, 'String'));
failed = equivClock>maxClock;
mbs = str2num(get(handles.FPSMbPerSecond, 'String'));
localUpdateMsg(mbs, handles.FPSMsg, failed, 'Your frame rate ');
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIGURE UI PANELS:
%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateHWParamsPanel(xEdgeOffset, yEdgeOffset)
% Create the HardwareParameters panel and controls.
pnlPos = [0+xEdgeOffset 0.88+yEdgeOffset 1-(2*xEdgeOffset) 0.12-(2*yEdgeOffset)];
uipanel('Title', 'HARDWARE PARAMETERS', 'Position', pnlPos);
% Create a hidden panel so the edit fields are
% created with respect to it.
pnlPos = [0+xEdgeOffset 0.90+yEdgeOffset 0.5-(2*xEdgeOffset) 0.10-(2*yEdgeOffset)];
pnl = uipanel('Position', pnlPos, 'Visible', 'off');
localAddTextList(pnl, {'Bus Type:'});
constants = get(get(pnl, 'Parent'), 'Userdata');
uic = uicontrol('Style', 'popupmenu', 'Tag', 'BusType', ...
'String', constants.maxMbPerSecond(1:2:end), ...
'Units', 'normalized', 'BackGroundColor', 'white',...
'FontWeight', 'bold', 'Parent', pnl, 'Value', 7, ...
'Position', [1/3, 0.05, 2/3, 1/2]);
% Create a hidden panel so the edit fields are
% created with respect to it.
pnlPos = [0.5+xEdgeOffset 0.90+yEdgeOffset 0.5-(2*xEdgeOffset) 0.10-(2*yEdgeOffset)];
pnl = uipanel('Position', pnlPos, 'Visible', 'off');
localAddTextList(pnl, {'Maximum Pixel Clock (MHz):'});
localAddEditFieldList(pnl, {'MaxBoardClock', true});
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateIMParamsPanel(xEdgeOffset, yEdgeOffset)
% Create the ImageParameters panel and controls.
pnlPos = [0+xEdgeOffset 0.22+yEdgeOffset 0.5-(2*xEdgeOffset) 0.66-(2*yEdgeOffset)];
pnl = uipanel('Title', 'IMAGE PARAMETERS', 'Position', pnlPos);
localAddTextList(pnl, ...
{'Width (pixels):', 'Height (lines):', 'Bits / Pixel:', ...
'Pixels / Frame:', 'Bits / Frame:', 'Bytes / Frame:', 'MB / Frame:'});
localAddEditFieldList(pnl, ...
{'Width', true, 'Height', true, 'BitsPerPixel', true, ...
'PixelsPerFrame', false, 'BitsPerFrame', false, ...
'BytesPerFrame', false, 'MbPerFrame', false});
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateBufferPanel(xEdgeOffset, yEdgeOffset)
% Create the Buffer panel and controls.
pnlPos = [0+xEdgeOffset 0+yEdgeOffset 0.5-(2*xEdgeOffset) 0.29-yEdgeOffset];
pnl = uipanel('Title', 'FRAMES TO BUFFER', 'Position', pnlPos);
localAddTextList(pnl, ...
{'Number of Frames to Buffer:', 'Memory Available (MB):', 'Maximum Number of Frames:'});
fieldSpacing = localAddEditFieldList(pnl, ...
{'FramesToBuffer', true, 'MemoryAvailable', false, 'MaxFrames', false});
uicontrol('Style', 'text', 'Units', 'normalized', ...
'String', 'The number of frames to buffer is OK.', ...
'Parent', pnl, 'Tag', 'FramesToBufferMsg', ...
'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateDataRatePanel(xEdgeOffset, yEdgeOffset)
% Create the DataRate panel and controls.
pnlPos = [0.5+xEdgeOffset 0.63+yEdgeOffset 0.5-(2*xEdgeOffset) 0.25-(2*yEdgeOffset)];
pnl = uipanel('Title', 'TARGET DATA RATE', 'Position', pnlPos);
localAddTextList(pnl, {'MB / Second:', 'Frames / Second:'});
fieldSpacing = localAddEditFieldList(pnl, ...
{'DataRateMbPerSecond', true, 'DataRateFramesPerSecond', false});
uicontrol('Style', 'text', 'String', 'Your data rate is OK.', ...
'Units', 'normalized', 'Parent', pnl, 'Tag', 'DataRateMsg', ...
'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreatePxlClockPanel(xEdgeOffset, yEdgeOffset)
% Create the PixelClock panel and controls.
pnlPos = [0.5+xEdgeOffset 0.29+yEdgeOffset 0.5-(2*xEdgeOffset) 0.34-yEdgeOffset];
pnl = uipanel('Title', 'TARGET PIXEL CLOCK', 'Position', pnlPos);
localAddTextList(pnl, {'Pixel Clock (MHz):', 'Seconds / Frame:', ...
'Frames / Second:', 'MB / Second:'});
fieldSpacing = localAddEditFieldList(pnl, ...
{'PixelClock', true, 'SecondsPerFrame', false, ...
'PixelClockFramesPerSecond', false, 'PixelClockMbPerSecond', false});
uicontrol('Style', 'text', 'String', 'Your pixel clock is OK.', ...
'Units', 'normalized', 'Tag', 'PixelClockMsg', 'Parent', pnl, ...
'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateFPSPanel(xEdgeOffset, yEdgeOffset)
% Create the FramesPerSecond panel and controls.
pnlPos = [0.5+xEdgeOffset 0+yEdgeOffset 0.5-(2*xEdgeOffset) 0.29-yEdgeOffset];
pnl = uipanel('Title', 'TARGET FRAME RATE', 'Position', pnlPos);
localAddTextList(pnl, ...
{'Frames / Second:', 'Equivalent Pixel Clock (MHz):', 'MB / Second:'});
fieldSpacing = localAddEditFieldList(pnl, {'FPSFramesPerSecond', true, ...
'EquivalentPixelClock', false, 'FPSMbPerSecond', false});
uicontrol('Style', 'text', 'String', 'Your frame rate is OK.', ...
'Units', 'normalized', 'Tag', 'FPSMsg', 'Parent', pnl, ...
'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIGURE UI HELPERS:
%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localAddTextList(pnl, names)
% Add the list of text fields passed in as
% an evenly spaced, vertical list of text uicontrols.
xFieldOffset = 0.05;
yEdgeOffset = 0.015;
% If only one name needs to be added,
% allow it to take up extra room.
nNames = length(names);
if nNames>1
fieldSpacing = 1/(nNames+1);
else
fieldSpacing = 1/nNames;
end
% Iterate through each text string we need to add.
for orderNum=1:nNames
xOffset = xFieldOffset;
yOffset = 1 - (orderNum*fieldSpacing);
width = 2/3;
height = fieldSpacing/2.5;
uic = uicontrol('Style', 'text', 'String', names{orderNum}, ...
'Units', 'normalized', 'Parent', pnl, 'HorizontalAlignment', 'left', ...
'Position', [xOffset, yOffset, width, height]);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function fieldSpacing = localAddEditFieldList(pnl, entries)
% Add the list of edit controls as an evenly spaced,
% vertical list of edit uicontrols.
% Each control has a Tag name and a corresponding logical
% indicating if the edit uicontrol should be enabled or not.
xFieldOffset = 0.05;
yEdgeOffset = 0.015;
% If only one name needs to be added,
% allow it to take up extra room.
nNames = length(entries)/2;
if nNames>1
fieldSpacing = 1/(nNames+1);
else
fieldSpacing = 1/nNames;
end
% Iterate through each edit control we need to add.
for orderNum=1:nNames
xOffset = 2/3;
yOffset = 1 - (orderNum*fieldSpacing);
width = 1/3 - xFieldOffset;
height = fieldSpacing/2;
name = entries{2*orderNum-1};
editable = entries{2*orderNum};
if editable
uic = uicontrol('Style', 'edit', 'Tag', name, 'Units', 'normalized', ...
'Parent', pnl, 'Position', [xOffset, yOffset, width, height], ...
'String', '0', 'FontWeight', 'bold');
else
uic = uicontrol('Style', 'edit', 'Tag', name, 'Units', 'normalized', ...
'Enable', 'off', 'String', '0', 'FontWeight', 'bold', ...
'Parent', pnl, 'Position', [xOffset, yOffset, width, height]);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localUpdateMsg(mbs, msgHandle, failed, msg)
% Determine what message needs to be displayed.
fig = localFindFigure;
handles = guihandles(fig);
% If the current state of our checks is not failed,
% check the current bus limitations.
if ~failed
% Check bus limit.
constants = get(fig, 'Userdata');
busLimit = constants.maxMbPerSecond{2*get(handles.BusType, 'Value')};
if mbs>busLimit
msg = ['Bus bandwidth (', num2str(busLimit), ' MB/s) exceeded.'];
color = 'black';
else
msg = [msg 'is OK.'];
color = 'blue';
end
else
msg = [msg 'is too high.'];
color = 'red';
end
set(msgHandle, 'String', msg, 'FontWeight', 'bold', 'ForegroundColor', color);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [fig, figName] = localFindFigure
% Locate the top level figure.
figName = 'Image Acquisition Calculator';
fig = findobj(findall(0), 'Type', 'figure', 'Name', figName);
if ~isempty(fig)
fig = fig(1);
end