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

Update firstOrderDMA.m to accept and return column vectors for signals and...

Update firstOrderDMA.m to accept and return column vectors for signals and positions (the number of elements is always the second dimension)
parent ace9b679
No related branches found
No related tags found
1 merge request!8Convert project to use column vectors
......@@ -3,35 +3,34 @@
% Author: Achilles Kappis
% e-mail: axilleaz@protonmail.com
%
% Date: 05/11/2023 (DD/MM/YYYY)
% Date: 29/09/2024 (DD/MM/YYYY)
%
% Copyright: MIT
% --------------------------------------------------
% Functionality: Calculate the output of a first order
% Differential Microphone Array.
% Functionality: Calculate the output of a first order Differential
% Microphone Array.
% --------------------------------------------------
% Input
%
% input [numeric]: The input to the array. 3D array/matrix with dimensions
% [M x measurements x frequency], where M represents the
% number of microphones and must be even. Each pair is
% treated as a first order DMA. "Measurements" are the
% observations (or measurements) made with the array and
% "frequency" is the number of frequencies of interest.
% IxMxF, where I is the number of measurments (or length
% of signals), M represents the number of microphones and
% must be even and F is the number of frequencies of
% interest. Each pair microphone is treated as a first
% order DMA.
%
% freq [numeric]: The frequencies of interest. A 1D vector with number of
% elements matching the third dimension of "input"
% freq [numeric]: The frequencies of interest. A vector with number of
% elements matching the third dimension of the "input"
% parameter.
%
% posVec [numeric]: The position vectors of the DMA elements. This must be
% a 3x2 matrix whose rows will represent the Cartesian
% pos [numeric]: The position vectors of the DMA elements. This must be a
% 3xM matrix whose rows will represent the Cartesian
% coordinates and the columns the DMA elements.
%
% polarPattern [string/char/numeric] (Optional): The sought out
% beam-pattern. It can be
% either a string (or
% character cell) from one
% of the following (not case
% pPattern [string/char/numeric] (Optional): The sought out beam-pattern.
% It can be either a string (or
% character cell) from one of
% the following (not case
% sensitive):
% - Omni, Omnidirectional,
% Monopole
......@@ -39,37 +38,34 @@
% - Cardioid
% - Hypercardioid
% - Supercardioid
% It can also be a numeric
% value representing the
% angle for which the
% response is specified
% (input parameter
% "betaParam") in degrees.
% It can also be a numeric value
% representing the angle for
% which the response is
% specified (input parameter
% "beta") in degrees.
% [Default: Dipole]
%
% betaParam [numeric] (Optional): The (normalised to unity) response at
% the angle specified with teh parameter
% "polarPattern". If "polarPattern" is
% given as string/char the appropriate
% value is automatically set, and
% "betaParam" is ignored. [Default: 0]
% beta [numeric] (Optional): The (normalised to unity) response at the
% angle specified with teh parameter "pPattern".
% If "pPattern" is given as string/char the
% appropriate value is automatically set, and
% this argument is ignored. [Default: 0]
%
% --------------------------------------------------
% Output
%
% output [numeric]: The output of the array. It has the same dimensions as
% the "input" parameter except for the first dimension
% which is equal to M/2 where M is the number of
% microphone elements provided.
% the "input" parameter except for the second dimension
% which is equal to M/2.
%
% h [numeric]: This [2 x F] filter is the filter that results in the
% h [numeric]: This 2xF filter is the filter that results in the
% beam-pattern of interest and F is the number of frequencies.
%
% --------------------------------------------------
% Notes
%
% --------------------------------------------------
function [output, h] = firstOrderDMA(input, freq, d, polarPattern, betaParam)
function [output, h] = firstOrderDMA(input, freq, d, pPattern, beta)
% ====================================================
% Check for number of arguments
% ====================================================
......@@ -86,8 +82,8 @@ function [output, h] = firstOrderDMA(input, freq, d, polarPattern, betaParam)
% ====================================================
validateattributes(input, {'numeric'}, {'3d', 'nonnan', 'finite', 'nonempty'}, mfilename, 'Input', 1);
if mod(size(input, 1), 2) ~= 0
error("First dimension of 'input' parameter must have even length.")
if mod(size(input, 2), 2) ~= 0
error("Second dimension of 'input' parameter must have even length.")
end
validateattributes(freq, {'numeric'}, {'real', 'nonnan', 'finite', 'nonempty', 'vector', 'numel', size(input, 3)}, mfilename, 'Frequencies', 2);
......@@ -95,20 +91,20 @@ function [output, h] = firstOrderDMA(input, freq, d, polarPattern, betaParam)
% Check beta
if nargin > 4
validateattributes(betaParam, {'numeric'}, {'scalar', 'real', 'finite', 'nonempty', 'nonnan', '<=', 1, '>=', 0}, mfilename, "Beta", 5)
validateattributes(beta, {'numeric'}, {'scalar', 'real', 'finite', 'nonempty', 'nonnan', '<=', 1, '>=', 0}, mfilename, "Beta", 5)
else
betaParam = 0;
beta = 0;
end
% Check alpha (angle of null)
if nargin > 3
if isstring(polarPattern) || ischar(polarPattern)
validateattributes(polarPattern, {'char', 'string'}, {'scalartext', 'nonempty'}, mfilename, 'Polar pattern', 4);
elseif isnumeric(polarPattern)
validateattributes(polarPattern, {'numeric'}, {'scalar', 'real', 'nonnan', 'finite', 'nonempty'}, mfilename, 'Angle of null', 4);
if isstring(pPattern) || ischar(pPattern)
validateattributes(pPattern, {'char', 'string'}, {'scalartext', 'nonempty'}, mfilename, 'Polar pattern', 4);
elseif isnumeric(pPattern)
validateattributes(pPattern, {'numeric'}, {'scalar', 'real', 'nonnan', 'finite', 'nonempty'}, mfilename, 'Angle of null', 4);
end
else
polarPattern = "dipole";
pPattern = "dipole";
end
......@@ -125,35 +121,35 @@ function [output, h] = firstOrderDMA(input, freq, d, polarPattern, betaParam)
% Calculate parameters
% ====================================================
% Calculate the correct "null" angles based on given polar pattern
if ~isnumeric(polarPattern)
switch convertStringsToChars(lower(polarPattern))
if ~isnumeric(pPattern)
switch convertStringsToChars(lower(pPattern))
case {'omni', 'omnidirectional', 'monopole'}
polarPattern = pi;
betaParam = 1;
pPattern = pi;
beta = 1;
case {'dipole', 'figure-of-eight'}
polarPattern = pi/2;
betaParam = 0;
pPattern = pi/2;
beta = 0;
case 'cardioid'
polarPattern = pi;
betaParam = 0;
pPattern = pi;
beta = 0;
case 'hypercardioid'
polarPattern = (2 * pi/3);
betaParam = 0;
pPattern = (2 * pi/3);
beta = 0;
case 'supercardioid'
polarPattern = (3 * pi/4);
betaParam = 0;
pPattern = (3 * pi/4);
beta = 0;
otherwise
error("Unsupported polar pattern");
end
else
polarPattern = deg2rad(polarPattern);
pPattern = deg2rad(pPattern);
end
% Calculate filter(s)
for freqIdx = length(freq):-1:1
arrManMat = [arrMan(0, d, freq(freqIdx), 343), arrMan(polarPattern, d, freq(freqIdx), 343)];
h(:, freqIdx) = (arrManMat')\[1; betaParam];
arrManMat = [arrMan(0, d, freq(freqIdx), 343), arrMan(pPattern, d, freq(freqIdx), 343)];
h(:, freqIdx) = (arrManMat')\[1; beta];
end
......@@ -164,7 +160,7 @@ function [output, h] = firstOrderDMA(input, freq, d, polarPattern, betaParam)
for freqIdx = length(freq):-1:1
for pairIdx = size(input, 1)/2:-1:1
% Multiply the array filter with the input
output(pairIdx, :, freqIdx) = h(:, freqIdx)' * input(pairIdx * 2 - 1:pairIdx * 2, :, freqIdx);
output(:, pairIdx, freqIdx) = h(:, freqIdx)' * input(:, pairIdx * 2 - 1:pairIdx * 2, freqIdx);
end
end
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment