Skip to content
Snippets Groups Projects
Commit 40586023 authored by Achilles Kappis's avatar Achilles Kappis
Browse files

Add function to calculate signals from ideal point sources in the time domain

parent 24581519
No related branches found
No related tags found
1 merge request!3Update to v0.2.3
%% Signal generated by point sources in the time-domain
% --------------------------------------------------
% Author: Achilles Kappis
% e-mail: axilleaz@protonmail.com
%
% Date: 13/09/2024 (DD/MM/YYYY)
%
% Copyright: MIT
% --------------------------------------------------
% Functionality: Calculate the signals generated by ideal point sources in
% the time-domain.
% --------------------------------------------------
% Input
%
% sPos [numeric]: The Cartesian coordinates of the source positions. This
% must be an Nx3 matrix where N is the number of sources.
%
% rPos [numeric]: The Cartesian coordinates of the receiver positions. This
% must be an Mx3 matrix where M is the number of receivers.
%
% fs [numeric]: The sampling frequency. This is required in order to
% calculate the time-of-flight in samples and must be a
% positive real scalar.
%
% Q [numeric] (Optional): The source signals. This can be either an IxNxJ
% array, where I is the length of the source
% signals in samples and J is the number of
% trials/sound field realisations, or a real
% positive integer denoting the length of the
% source signals. In case the length of the source
% signals is given, the generated signals are
% zero-mean, (approximately) uniformly distributed
% and normalised to unity. [Default: 128].
%
% nTrials [numeric] (Optional): This is the number of trials/sound field
% realisations that will be generated. If "Q"
% is provided, this argument is ignored. It
% must be a positive real scalar.
% [Default: 1]
%
% c [numeric] (Optional): The speed of sound. [Default: 343].
%
% --------------------------------------------------
% Output
%
% rSig [numeric]: The signals at the receiver positions for all
% trials/sournd field realisations. This is an IxMxJ array.
%
% rSigMean [numeric]: The signals at the receiver positions averaged over
% all trials/sound field realisations. This is an IxM
% matrix.
%
% rSigMtx [numeric]: The signals at each receiver position due to each
% source for each trial/sound field realisation. This is
% an IxMxNxJ array.
%
% rSigMtxMean [numeric]: The signals at each receiver position due to each
% source averaged over the trials/sound field
% realisations. This is an IxMxN array.
%
% --------------------------------------------------
% Notes
%
% - It is the responsibility of the user to pick (or provide) adequately
% long source signals
%
% --------------------------------------------------
function [rSig, rSigMean, rSigMtx, rSigMtxMean] = ptSrcFieldTD(sPos, rPos, fs, Q, nTrials, c)
% ====================================================
% Check for number of arguments
% ====================================================
narginchk(3, 6);
nargoutchk(0, 4);
% ====================================================
% Validate input arguments
% ====================================================
% Validate mandatory arguments
validateattributes(sPos, "numeric", {'2d', 'real', 'nonnan', 'nonempty', 'finite', 'ncols', 3}, mfilename, "Cartesian coordinates of the source positions", 1);
validateattributes(rPos, "numeric", {'2d', 'real', 'nonnan', 'nonempty', 'finite', 'ncols', 3}, mfilename, "Cartesian coordinates of the receiver positions", 2);
validateattributes(fs, "numeric", {'scalar', 'real', 'nonnan', 'nonempty', 'finite', 'positive'}, mfilename, "The sampling frequency", 3);
% Validate optional arguments
if nargin > 3 && ~isempty(Q)
if isscalar(Q)
validateattributes(Q, "numeric", {'scalar', 'real', 'nonnan', 'nonempty', 'finite', 'positive', 'integer'}, mfilename, "Length of source signals in samples", 4);
else
validateattributes(Q, "numeric", {'3d', 'real', 'nonnan', 'nonempty', 'finite', 'ncols', size(sPos, 1)}, mfilename, "Source signals", 4);
nTrials = size(Q, 3);
end
else
Q = 128;
end
if nargin > 4 && ~isempty(nTrials) && isscalar(Q)
validateattributes(nTrials, "numeric", {'scalar', 'positive', 'nonnan', 'nonempty', 'finite'}, mfilename, "Number of trials/sound field realisations", 5);
elseif nargin > 4 && isempty(nTrials)
nTrials = 1;
end
if nargin > 5 && ~isempty(c)
validateattributes(c, "numeric", {'scalar', 'nonempty', 'nonnan', 'finite', 'real', 'positive'}, mfilename, "The speed of sound", 6);
else
c = 343;
end
% ====================================================
% Pre-process data
% ====================================================
% Generate source signals
if isscalar(Q)
Q = rand(Q, size(sPos, 1), nTrials);
Q = Q - mean(Q);
Q = Q./max(abs(Q));
end
% Calculate source-receiver distances
dist = twoPtDist(sPos, rPos); % Distances
del = dist/c; % Delays in seconds
% ====================================================
% Calculate signals
% ====================================================
% Go through the trials/sound field realisations
for jIdx = size(Q, 3):-1:1
% Go through the sources (calculate for all receivers in one go)
for sIdx = size(dist, 1):-1:1
rSigMtx(:, :, sIdx, jIdx) = (1./dist(sIdx, :)) .* delayseq(Q(:, sIdx, jIdx), del(sIdx, :), fs);
end
end
% Sum source signals at each receiver position
rSig = squeeze(sum(rSigMtx, 3));
% ====================================================
% Calculate output arguments
% ====================================================
% Mean receiver signal over all trials/sound field realisations
if nargout > 1
rSigMean = squeeze(mean(rSig, 3));
end
% Mean receiver signal due to each source over all trials/sound field realisations
if nargout > 3
rSigMtxMean = squeeze(mean(rSigMtx, 4));
end
end
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment