Code covered by the BSD License  

Highlights from
Sonar Demo

image thumbnail
from Sonar Demo by Robert Bemis
Sonic distance measurement using Windows sound card for data acquisition.

tof(varargin)
function varargout = tof(varargin)
% TOF demonstrates sound ranging (sonar) between PC
%   speaker and microphone (up to 6m away).
%
% This demo requires:
%   - Data Acquisition Toolbox,
%   - Signal Processing Toolbox
%   - Windows sound card
%   - files: sonar_anal.m tof.fig tof.m (this file)
%
% How does it work?
%   A pulse wave (chirp) is generated from the speaker,
%   which travels through air at the speed of sound.  
%   At the same time the microphone records the received
%   wave (plus possible reflections depending on room
%   acoustics).  The propagation time delay (sec) is 
%   measured and converted to distance (m).

% Copyright 2001-2010 The MathWorks, Inc.

% TOF Application M-file for tof.fig
%    FIG = TOF launch tof GUI.
%    TOF('callback_name', ...) invoke the named callback.

% Last Modified by GUIDE v2.0 18-Oct-2001 17:27:18

% Updated by R.Bemis July 5, 2007
%   * Removed hard coded calibrations - less accurate, more robust

if nargin == 0  % LAUNCH GUI

	fig = openfig(mfilename,'reuse');

	% Use system color scheme for figure:
	set(fig,'Color',get(0,'defaultUicontrolBackgroundColor'));

	% Generate a structure of handles to pass to callbacks, and store it. 
	handles = guihandles(fig);
	guidata(fig, handles);

    %sonar_setup(handles,0.0087)  % set up audio I/O
    sonar_setup(handles,0)      % set up audio I/O
    
	if nargout > 0
		varargout{1} = fig;
	end

elseif ischar(varargin{1}) % INVOKE NAMED SUBFUNCTION OR CALLBACK

	try
		if (nargout)
			[varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
		else
			feval(varargin{:}); % FEVAL switchyard
		end
	catch
		disp(lasterr);
	end

end


%| ABOUT CALLBACKS:
%| GUIDE automatically appends subfunction prototypes to this file, and 
%| sets objects' callback properties to call them through the FEVAL 
%| switchyard above. This comment describes that mechanism.
%|
%| Each callback subfunction declaration has the following form:
%| <SUBFUNCTION_NAME>(H, EVENTDATA, HANDLES, VARARGIN)
%|
%| The subfunction name is composed using the object's Tag and the 
%| callback type separated by '_', e.g. 'slider2_Callback',
%| 'figure1_CloseRequestFcn', 'axis1_ButtondownFcn'.
%|
%| H is the callback object's handle (obtained using GCBO).
%|
%| EVENTDATA is empty, but reserved for future use.
%|
%| HANDLES is a structure containing handles of components in GUI using
%| tags as fieldnames, e.g. handles.figure1, handles.slider2. This
%| structure is created at GUI startup using GUIHANDLES and stored in
%| the figure's application data using GUIDATA. A copy of the structure
%| is passed to each callback.  You can store additional information in
%| this structure at GUI startup, and you can change the structure
%| during callbacks.  Call guidata(h, handles) after changing your
%| copy to replace the stored original so that subsequent callbacks see
%| the updates. Type "help guihandles" and "help guidata" for more
%| information.
%|
%| VARARGIN contains any extra arguments you have passed to the
%| callback. Specify the extra arguments by editing the callback
%| property in the inspector. By default, GUIDE sets the property to:
%| <MFILENAME>('<SUBFUNCTION_NAME>', gcbo, [], guidata(gcbo))
%| Add any extra arguments after the last argument, before the final
%| closing parenthesis.



% --------------------------------------------------------------------
function varargout = Single_Callback(h, eventdata, handles, varargin)

set(handles.Repeat,'enable','off')      % disable Repeat button
sonar_once(handles.figure1)             % take one measurement



% --------------------------------------------------------------------
function varargout = Repeat_Callback(h, eventdata, handles, varargin)

set(h,'enable','off')                   % disable Repeat button
set(handles.Single,'enable','off')      % disbale Single button
set(handles.Stop,'enable','on')         % enable Stop button
sonar_run(handles.figure1)              % measure repeatedly



% --------------------------------------------------------------------
function varargout = Stop_Callback(h, eventdata, handles, varargin)

set(h,'enable','off')                   % disable Stop button
set(handles.Repeat,'enable','on')       % enable Repeat button
set(handles.Single,'enable','on')       % enable Single button
sonar_stop(handles.figure1)             % stop repeats



% --------------------------------------------------------------------
function sonar_setup(handles,cal_dist)

fig = handles.figure1;  % figure handle

if nargin<2
  cal_dist = 0; 
end

% physics
c = 330;            % speed of sound (m/sec)
d = 50;             % max distance (m)
Td = d/c;           % max return time (sec)
pw = 0.01;          % pulse width (sec)
Tmax = Td+pw;       % total response time (sec)

% DAQ parameters
ai = analoginput('winsound');               % create AI object
addchannel(ai,1);                           % single channel (mono)
Fs = setverify(ai,'samplerate',44100);      % sample rate (Hz)
N = 2^ceil(log2(Tmax*Fs));                  % buffer size (samples)
ao = analogoutput('winsound');              % create AO object
addchannel(ao,1);                           % single channel (mono)
ao.SampleRate=Fs;                           % output Fs same as input

% excitation chirp
f0 = 4e3;                       % low freq (Hz)
f1 = 8e3;                       % high freq (Hz) 
t = (0:(1/Fs):pw)';             % time index (sec)
n = length(t);                  % pulse length (samples)
pulse = chirp(t,f0,pw,f1);      % chrip waveform (short)
pulse = pulse.*hanning(n);      % pulse envelope
pad = zeros(N-n,1);             % silence trailing chirp
x = [pulse; pad];               % excitation (zero padded)

% response waveform
ai.SamplesPerTrigger = N;           % total samples to acquire
ai.TriggerDelayUnits = 'sec';
ai.TriggerDelay = cal_dist/c;       % calibration lag (sec)
ai.SamplesAcquiredFcnCount = N;
ai.SamplesAcquiredFcn = ['sonar_anal(' num2str(fig) ')'];

% user data
ud.ai = ai;                 % audio input
ud.ao = ao;                 % audio output
ud.c = c;                   % wave speed in air
ud.x = x;                   % excitation waveform
ud.h = handles;             % guide figure handles
set(fig,'userdata',ud)      % store bundle with figure



% --------------------------------------------------------------------
function sonar_once(fig)

% user data
ud = get(fig,'userdata');       % user data fields
ai = ud.ai;                     % audio input
ao = ud.ao;                     % audio output
x = ud.x;                       % excitation chirp pulse
ai.samplesacquiredfcn = '';     % don't repeat measurement
putdata(ao,x)                   % arm audio output
start([ai ao])                  % start measurement
sonar_anal(fig)                 % manually analyze data



% --------------------------------------------------------------------
function sonar_run(fig)

% user data
ud = get(fig,'userdata');   % user data fields
ai = ud.ai;                 % audio input
ao = ud.ao;                 % audio output
x = ud.x;                   % excitation chirp pulse

% callback function to analyze when done acquiring data
ai.samplesacquiredfcn = ['sonar_anal(' num2str(fig) ')'];
% NOTE: sonar_anal will rearm output and repeat measurement

putdata(ao,x)       % arm audio output
start([ai ao])      % start measuring (will repeat)



% --------------------------------------------------------------------
function sonar_stop(fig)

% user data
ud = get(fig,'userdata');       % user data fields
ai = ud.ai;                     % audio input
ai.samplesacquiredfcn = '';     % stop repeating



% --------------------------------------------------------------------
function sonar_cleanup(fig)

% user data
ud = get(fig,'userdata');     % user data fields
ai = ud.ai; delete(ai)        % remove audio input
ao = ud.ao; delete(ao)        % remove audio output



% --------------------------------------------------------------------
function varargout = figure1_CloseRequestFcn(h, eventdata, handles, varargin)

sonar_stop(handles.figure1)         % stops if still repeating
sonar_cleanup(handles.figure1)      % remove audio objects
delete(handles.figure1)             % remove figure window

Contact us at files@mathworks.com