Projects STRLCPY wirelesscomm Commits 7d38d416
🤬
  • ■ ■ ■ ■ ■ ■
    unit10_directional/ArrayPlatform.m
     1 +classdef ArrayPlatform < matlab.System
     2 + % ArrayPlatform. Class containing an antenna array and axes.
     3 + properties
     4 +
     5 + fc = 28e9; % Carrier frequency
     6 +
     7 + % Element within each array.
     8 + elem = [];
     9 +
     10 + % Gridded interpolant object for the element gain in linear scale
     11 + elemGainInterp = [];
     12 +
     13 + % Antenna array.
     14 + arr = [];
     15 +
     16 + % Steering vector object
     17 + svObj = [];
     18 +
     19 + % Azimuth and elevation angle of the element peak directivity
     20 + axesAz = 0;
     21 + axesEl = 0;
     22 +
     23 + % Axes of the element local coordinate frame of reference
     24 + axesLoc = eye(3);
     25 +
     26 + % Velocity vector in 3D in m/s
     27 + vel = zeros(1,3);
     28 +
     29 + % Position in m
     30 + pos = zeros(1,3);
     31 +
     32 + % Normalization matrix
     33 + Qinv = [];
     34 + end
     35 +
     36 + methods
     37 + function obj = ArrayPlatform(varargin)
     38 + % Constructor
     39 +
     40 + % Set key-value pair arguments
     41 + if nargin >= 1
     42 + obj.set(varargin{:});
     43 + end
     44 + end
     45 +
     46 +
     47 +
     48 + function computeNormMatrix(obj)
     49 + % The method performs two key tasks:
     50 + % * Measures the element pattern and creates a gridded
     51 + % interpolant object to interpolate the values at other
     52 + % angles
     53 + % * Compute the normalization matrix to account for mutual
     54 + % coupling
     55 +
     56 + % TODO: Get the pattern for the element using the elem.pattern
     57 + % method
     58 + % [elemGain,az,el] = obj.elem.pattern(...);
     59 + [elemGain,az,el] = obj.elem.pattern(obj.fc,'Type', 'Directivity');
     60 +
     61 + % TODO: Create the gridded interpolant object
     62 + % for element gain
     63 + % obj.elemGainInterp = griddedInterpolant(...);
     64 + obj.elemGainInterp = griddedInterpolant({el,az},elemGain);
     65 +
     66 + % Get a vector of values with the elements az(i) and el(j).
     67 + [azMat, elMat] = meshgrid(az, el);
     68 + azVal = azMat(:);
     69 + elVal = elMat(:);
     70 + elemGainVal = elemGain(:);
     71 + 
     72 + % TODO: Create a steering vector object with the array
     73 + % obj.svObj = phased.SteeringVector(...);
     74 + obj.svObj = phased.SteeringVector('SensorArray', obj.arr);
     75 + 
     76 + % TODO: Get the steering vectors
     77 + % Sv0 = obj.svObj(...);
     78 + Sv0 = obj.svObj(obj.fc, [azVal elVal]');
     79 +
     80 + % TODO: Compute un-normalized spatial signature
     81 + % by multiplying the steering vectors with the element gain
     82 + % SvNoNorm = ...
     83 + SvNoNorm = Sv0.*db2mag(elemGainVal)'; % corrected
     84 +
     85 + % TODO: Compute the normalization matrix by integrating the
     86 + % un-normalized steering vectors
     87 + % Q = ...
     88 + nang = length(elVal);
     89 + cosel = cos(deg2rad(elVal));
     90 + Q = (1/nang)*(SvNoNorm.*cosel')*(SvNoNorm') / mean(cosel);
     91 + 
     92 + % Ensure matrix is Hermitian
     93 + Q = (Q+Q')/2;
     94 +
     95 + % TODO: Save the inverse matrix square root of Q
     96 + % obj.Qinv = ...
     97 + obj.Qinv = inv(sqrtm(Q));
     98 + end
     99 +
     100 + function alignAxes(obj,az,el)
     101 + % Aligns the axes to given az and el angles
     102 +
     103 + % Set the axesAz and axesEl to az and el
     104 + obj.axesAz = az;
     105 + obj.axesEl = el;
     106 +
     107 + % Creates axes aligned with az and el
     108 + obj.axesLoc = azelaxes(az,el);
     109 + end
     110 +
     111 + function dop = doppler(obj,az,el)
     112 + % Computes the Doppler shift of a set of paths
     113 + % The angles of the paths are given as (az,el) pairs
     114 + % in the global frame of reference.
     115 +
     116 + % Finds unit vectors in the direction of each path
     117 + npath = length(el);
     118 + [u1,u2,u3] = sph2cart(deg2rad(az),deg2rad(el),ones(1,npath));
     119 + u = [u1; u2; u3];
     120 +
     121 + % Compute the Doppler shift of each path via an inner product
     122 + % of the path direction and velocity vector.
     123 + vcos = obj.vel*u;
     124 + vc = physconst('lightspeed');
     125 + dop = vcos*obj.fc/vc;
     126 +
     127 + end
     128 +
     129 + function releaseSV(obj)
     130 + % Creates the steering vector object if it has not yet been
     131 + % created. Otherwise release it. This is needed since the
     132 + % sv object requires that it takes the same number of
     133 + % inputs each time.
     134 + if isempty(obj.svObj)
     135 + obj.svObj = phased.SteeringVector('SensorArray',obj.arr);
     136 + else
     137 + obj.svObj.release();
     138 + end
     139 +
     140 + end
     141 +
     142 + function n = getNumElements(obj)
     143 + % Gets the number of elements
     144 + n = obj.arr.getNumElements();
     145 +
     146 + end
     147 +
     148 + function elemPosGlob = getElementPos(obj)
     149 + % Gets the array elements in the global reference frame
     150 +
     151 + % Get the element position in the local reference frame
     152 + elemPosLoc = obj.arr.getElementPosition();
     153 +
     154 + % Convert to the global reference frame
     155 + elemPosGlob = local2globalcoord(elemPosLoc, 'rr', ...
     156 + zeros(3,1), obj.axesLoc) + reshape(obj.pos,3,1);
     157 + end
     158 +
     159 + end
     160 +
     161 + methods (Access = protected)
     162 +
     163 + function setupImpl(obj)
     164 + % setup: This is called before the first step.
     165 + obj.computeNormMatrix();
     166 +
     167 +
     168 + end
     169 +
     170 + function releaseImpl(obj)
     171 + % release: Called to release the object
     172 + obj.svObj.release();
     173 + end
     174 +
     175 + function [Sv, elemGain] = stepImpl(obj, az, el, relSV)
     176 + % Gets normalized steering vectors and element gains for a set of angles
     177 + % The angles az and el should be columns vectors along which
     178 + % the outputs are to be computed.
     179 + % If the relSV == true, then the steering vector object is
     180 + % released. This is needed in case the dimensions of the past
     181 + % call are the different from the past one
     182 +
     183 + % Release the SV
     184 + if nargin < 4
     185 + relSV = true;
     186 + end
     187 + if relSV
     188 + obj.releaseSV();
     189 + end
     190 +
     191 + % TODO: Convert the global angles (az, el) to local
     192 + % angles (azLoc, elLoc). Use the
     193 + % global2localcoord() method with the 'ss' option.
     194 + uglobal = [az el ones(length(az),1)]';
     195 + ulocal = global2localcoord(uglobal, 'ss', zeros(3,1), obj.axesLoc);
     196 + azLoc = ulocal(1,:);
     197 + elLoc = ulocal(2,:);
     198 +
     199 + % TODO: Get the SV in the local coordinates
     200 + % Sv0 = obj.svObj(...)
     201 + Sv0 = obj.svObj(obj.fc, [azLoc; elLoc]);
     202 +
     203 + % TODO: Get the directivity gain of the element from the
     204 + % local angles.
     205 + % elemGain = obj.elem.step(...)
     206 + elemGain = obj.elemGainInterp(elLoc,azLoc)'; % corrected
     207 +
     208 + % TODO: Compute the normalized steering vectors
     209 + % Sv = ...
     210 + Sv = obj.Qinv*(Sv0.*db2mag(elemGain'));
     211 +
     212 +
     213 + end
     214 + 
     215 + end
     216 +
     217 +
     218 +end
     219 + 
  • ■ ■ ■ ■ ■ ■
    unit10_directional/DataMapper.m
     1 +classdef DataMapper < matlab.mixin.SetGet
     2 + % Class for mapping data for a grid
     3 +
     4 + properties
     5 + posStep; % Grid spacing in each direction
     6 +
     7 + % Data at position n will be mapped to grid point
     8 + % (posInd(n,1), posInd(n,2))
     9 + posInd; % Index of the
     10 +
     11 + % Number of steps in each axis
     12 + nsteps;
     13 +
     14 + % Position along each axis
     15 + posx, posy;
     16 +
     17 + end
     18 +
     19 + methods
     20 + function obj = DataMapper(pos, posStep)
     21 + % Constructor
     22 + %
     23 + % pos is a n x 2 list of all possible positions.
     24 + % posStep is the 1 x 2 grid spacing in each direction
     25 +
     26 + % Compute the indices that each position gets mapped to
     27 + posMin = min(pos);
     28 + posMax = max(pos);
     29 + obj.posStep = posStep;
     30 + obj.nsteps = (posMax - posMin)./posStep + 1;
     31 + obj.posInd = round((pos-posMin)./posStep)+1;
     32 +
     33 + % Compute the x and y positions for the imagesc function
     34 + obj.posx = posMin(1) + (0:obj.nsteps(1)-1)*posStep(1);
     35 + obj.posy = posMin(2) + (0:obj.nsteps(2)-1)*posStep(2);
     36 + end
     37 +
     38 + function plot(obj, data, options)
     39 + % Plots data with the positions
     40 + %
     41 + % Data is a vector of size n x 1. The function will then
     42 + % plot the value of data(i) in pos(i,1), pos(i,2).
     43 + %
     44 + % It can also optionally create dummy legend labels that can
     45 + % then be displayed with the legend command
     46 + arguments
     47 + obj
     48 + data
     49 + options.legendValues = []
     50 + options.legendLabels = []
     51 + options.plotHold logical = false
     52 + options.addLegend logical = false
     53 + options.legendLocation string = 'southeast'
     54 + options.noDataValue = 0
     55 + end
     56 +
     57 +
     58 + % Create an image array for the data
     59 + posImage = repmat(options.noDataValue, ...
     60 + obj.nsteps(2), obj.nsteps(1));
     61 + for i = 1:length(data)
     62 + posImage(obj.posInd(i,2), obj.posInd(i,1)) = data(i);
     63 + end
     64 +
     65 + % Plot the data
     66 + imagesc(obj.posx, obj.posy, posImage);
     67 + hold on;
     68 +
     69 + % Plot a dummy rectangle for each color
     70 + if ~isempty(options.legendLabels)
     71 + nlabels = length(options.legendLabels);
     72 + colorArr = parula(nlabels);
     73 + for i = 1:nlabels
     74 + fill([1,1],[1,1], colorArr(i,:), 'DisplayName', ...
     75 + options.legendLabels{i});
     76 + end
     77 + end
     78 +
     79 + % Turn off the plot hold if not requested
     80 + if ~options.plotHold
     81 + hold off;
     82 + end
     83 +
     84 + % Create the legend
     85 + if options.addLegend
     86 + legend('Location', options.legendLocation);
     87 + end
     88 + end
     89 + end
     90 +end
     91 + 
     92 + 
  • ■ ■ ■ ■ ■ ■
    unit10_directional/DirSearchSim.m
     1 +classdef DirSearchSim < matlab.mixin.SetGetExactNames
     2 + properties
     3 + % TX and RX multi-array platforms
     4 + tx, rx;
     5 +
     6 + % Search parameters
     7 + NFFT; % FFT size
     8 + txPow; % TX power in dBm
     9 + fsamp; % Sample rate
     10 + noiseFig; % Noise figure in dB
     11 +
     12 + % Path parameters
     13 + aoaAz, aoaEl;
     14 + aodAz, aodEl;
     15 + pl;
     16 + txPos;
     17 + rxPos;
     18 + dly;
     19 +
     20 + % Angular search parameters
     21 + nangScan = 360; % Number of scan angles
     22 + azScan, elScan; % Scan angles
     23 + rxCwScan; % RX codewords for scanning
     24 + npaths = 5; % Maximum number of paths to detect
     25 +
     26 + % Number of samples in delay to scan on each side of the max
     27 + % delay
     28 + dlyWin = 5;
     29 +
     30 + % Scan correlation
     31 + rho;
     32 + end
     33 +
     34 + methods
     35 + function obj = DirSearchSim(param)
     36 + arguments
     37 + param.NFFT = 1024
     38 + param.tx MultiArrayPlatform
     39 + param.rx MultiArrayPlatform
     40 + param.txPow double = 23;
     41 + param.fsamp double = 4e8;
     42 + param.noiseFig double = 7;
     43 + param.nangScan = 360;
     44 + end
     45 +
     46 + % Set the parameters
     47 + obj.NFFT = param.NFFT;
     48 + obj.tx = param.tx;
     49 + obj.rx = param.rx;
     50 + obj.txPow = param.txPow;
     51 + obj.fsamp = param.fsamp;
     52 + obj.noiseFig = param.noiseFig;
     53 + obj.nangScan = param.nangScan;
     54 +
     55 + end
     56 +
     57 + function setPathParams(obj, pathData, ind)
     58 + % Set path parameters from the path data structure
     59 + obj.txPos = pathData.txPos;
     60 + obj.rxPos = pathData.rxPos(ind,:)';
     61 + np = pathData.npaths(ind);
     62 + obj.aoaAz = pathData.aoaAz(ind,1:np)';
     63 + obj.aoaEl = pathData.aoaEl(ind,1:np)';
     64 + obj.aodAz = pathData.aodAz(ind,1:np)';
     65 + obj.aodEl = pathData.aodEl(ind,1:np)';
     66 + obj.pl = pathData.pl(ind,1:np)';
     67 + obj.dly = pathData.dly(ind,1:np)';
     68 +
     69 + end
     70 +
     71 + function h = chanResp(obj, params)
     72 + % Compute the channel response with noise
     73 + %
     74 + % Returns an array h of size NFFT x nantRx x narrRx x ncwTx
     75 + % where h(t,i,j,k) is the channel response at time sample t
     76 + % RX antenna i, RX array j, and TX codeword k
     77 + arguments
     78 + obj
     79 + params.txCwInd = 'all';
     80 + end
     81 +
     82 + % Get dimensions
     83 + nantRx = obj.rx.getNumElements();
     84 + narrRx = obj.rx.getNumArrays();
     85 + if strcmp(params.txCwInd,'all')
     86 + ncwTx = obj.tx.getNumCW();
     87 + else
     88 + ncwTx = length(params.txCwInd);
     89 + end
     90 +
     91 + % Initialize response array
     92 + h = zeros(obj.NFFT,nantRx, narrRx, ncwTx);
     93 +
     94 + % Exit if there are no paths
     95 + np = length(obj.pl);
     96 + if np == 0
     97 + return
     98 + end
     99 +
     100 + % Compute the complex path gains on the TX paths for
     101 + % beamforming
     102 + gainTx = obj.tx.cwGain(obj.aodAz, obj.aodEl, ...
     103 + params.txCwInd);
     104 + ncwTx = size(gainTx,2);
     105 +
     106 + % Omni RX energy per sample per path
     107 + Erx = obj.txPow - obj.pl - pow2db(obj.fsamp);
     108 + phase = unifrnd(0,2*pi,np,1);
     109 + gainOmni = db2mag(Erx).*exp(1i*phase);
     110 +
     111 + % Compute the RX spatial signature on the RX paths
     112 + SvRx = obj.rx.step(obj.aoaAz, obj.aoaEl);
     113 +
     114 + % Compute the delay in samples. There is a random
     115 + % offset due to timing
     116 + dlySamp = obj.dly*obj.fsamp + unifrnd(0,obj.NFFT,1,1);
     117 + dlySamp = mod(dlySamp, obj.NFFT);
     118 +
     119 + % Add the paths
     120 + t = (0:obj.NFFT-1)';
     121 + for i = 1:np
     122 +
     123 + ht = sinc(t-dlySamp(i));
     124 + ht = reshape(SvRx(:,i,:),1,nantRx,narrRx,1)...
     125 + .*reshape(ht,obj.NFFT,1,1,1)...
     126 + .*reshape(gainTx(i,:),1,1,1,ncwTx);
     127 + h = h + ht*gainOmni(i);
     128 + end
     129 +
     130 + % Add noise
     131 + Enoise = db2pow(-174 + obj.noiseFig);
     132 + h = h + sqrt(Enoise/2)*...
     133 + (randn(size(h)) + 1i*randn(size(h)));
     134 +
     135 + end
     136 +
     137 + function hrx = chanRespRxCw(obj, h)
     138 + % Finds the channel response along each RX codeword direction
     139 + %
     140 + % The input, h, is of size NFFT x nantRx x narrRx x ncwTx
     141 + % where h(t,i,j,k) is the channel response at time sample t
     142 + % RX antenna i, RX array j, and TX codeword k. The output is
     143 + % an array hrx(t,i,k) of the channel response at time sample t,
     144 + % RX codeword i and TX codeword k.
     145 +
     146 + % Beam search along each TX and RX direction
     147 + nantRx = size(h,2);
     148 + ncwTx = size(h,4);
     149 + ncwRx = obj.rx.getNumCW();
     150 + hrx = zeros(obj.NFFT,ncwRx,ncwTx);
     151 +
     152 + for i = 1:ncwRx
     153 + j = obj.rx.cwArrInd(i); % Array for this RX codeword
     154 + w = obj.rx.codeWord(:,i);
     155 + hi = sum(h(:,:,j,:).*reshape(w,1,nantRx,1,1), 2);
     156 + hrx(:,i,:) = reshape(hi,obj.NFFT,1,ncwTx);
     157 + end
     158 + end
     159 +
     160 + function createScanCodebook(obj)
     161 + % Creates the fine codewords for the angular scan
     162 +
     163 + % Set the angular scan. Right now, we only search in the
     164 + % azimuth direction
     165 + obj.azScan = linspace(-179,180,obj.nangScan)';
     166 + obj.elScan = zeros(obj.nangScan,1);
     167 +
     168 + % Get the steering vectors for each scan angle
     169 + SvRx = obj.rx.step(obj.azScan , obj.elScan);
     170 + SvRx = permute(SvRx, [1 3 2]);
     171 +
     172 + % Normalize
     173 + SvNorm = sqrt(sum(abs(SvRx).^2,[1 2]));
     174 + obj.rxCwScan = conj(SvRx)./SvNorm;
     175 +
     176 + end
     177 +
     178 + function pathEst = estimatePaths(obj, h, hrx)
     179 + % Estimates path parameters
     180 + %
     181 + % h is the channel response from the chanResp() method
     182 + % hrx is the channel response from the chanRespRxCw() method
     183 +
     184 + % Create the scan codebook
     185 + if isempty(obj.rxCwScan)
     186 + obj.createScanCodebook();
     187 + end
     188 +
     189 + % Find the delay with the max energy
     190 + [nfft, ncwRx, ncwTx] = size(hrx);
     191 + hmagd = reshape(abs(hrx), nfft, ncwRx*ncwTx);
     192 + [~, idly] = max(max(hmagd, [], 2));
     193 +
     194 + % Extract the components of the channel response around
     195 + % the max delay
     196 + i1 = max(1, idly-obj.dlyWin);
     197 + i2 = min(nfft, idly+obj.dlyWin);
     198 + hd = h(i1:i2,:,:,:);
     199 +
     200 + % Reshape the channel response to nelem*narr x ndly*ncwTx
     201 + [ndly, nelem, narr, ncwTx] = size(hd);
     202 + H = permute(hd, [2,3,1,4]);
     203 + H = reshape(H, nelem*narr, ndly*ncwTx);
     204 +
     205 + % Take the SVD to find the low-rank decompositions
     206 + % along the RX spatial directions
     207 + [U, S, V] = svd(H, 'econ');
     208 +
     209 + % Reshape the arrays back
     210 + lam = diag(S).^2;
     211 + r = size(U,2);
     212 + U = reshape(U, nelem, narr, r);
     213 + V = reshape(V, ndly, ncwTx, r);
     214 +
     215 + % Set path parameters
     216 + pathEst.aoaAz = zeros(obj.npaths,1);
     217 + pathEst.aodAz = zeros(obj.npaths,1);
     218 + pathEst.aoaEl = zeros(obj.npaths,1);
     219 + pathEst.aodEl = zeros(obj.npaths,1);
     220 + pathEst.dly = zeros(obj.npaths,1);
     221 + pathEst.snr = zeros(obj.npaths,1);
     222 + pathEst.peakFrac = zeros(obj.npaths,1);
     223 +
     224 + % Get the average variance
     225 + hvar = mean(abs(h).^2, 'all');
     226 +
     227 + % Loop over paths
     228 + for i = 1:obj.npaths
     229 +
     230 + % Find the correlation across the RX codewords in
     231 + % each array
     232 + rhoi = sum(obj.rxCwScan .*reshape(U(:,:,i), nelem, narr, 1 ),1);
     233 +
     234 + % Add non-coherently across the arrays
     235 + rhoi = sum(abs(rhoi).^2, 2);
     236 + rhoi = squeeze(rhoi);
     237 +
     238 + % Find maximum along the RX direction
     239 + [rhoMax, im] = max(rhoi);
     240 + pathEst.snr(i) = rhoMax;
     241 + pathEst.aoaAz(i) = obj.azScan(im);
     242 + pathEst.aoaEl(i) = obj.elScan(im);
     243 +
     244 + % Find the maximum in the Tx and delay direction
     245 + [Vmax, im] = max(abs(V(:,:,i)), [], 'all', 'linear');
     246 + idly = mod(im-1,ndly)+1;
     247 + pathEst.dly(i) = idly;
     248 +
     249 + % Get the max TX angle
     250 + itx = floor((im-1) /ndly) + 1;
     251 + pathEst.aodAz(i) = obj.tx.azCw(itx);
     252 + pathEst.aodEl(i) = obj.tx.elCw(itx);
     253 +
     254 + % Convert to SNR
     255 + obj.rho(:,i) = pow2db(rhoi*lam(i)*abs(Vmax)^2/hvar);
     256 + pathEst.snr(i) = max(obj.rho(:,i));
     257 +
     258 + % Get the peakiness as a quality metric
     259 + pathEst.peakFrac(i) = max(rhoi)/mean(rhoi);
     260 + end
     261 +
     262 + % Subtract minimum delay
     263 + pathEst.dly = pathEst.dly - min(pathEst.dly);
     264 +
     265 + end
     266 +
     267 + end
     268 +end
  • ■ ■ ■ ■ ■ ■
    unit10_directional/MultiArrayPlatform.m
     1 +classdef MultiArrayPlatform < matlab.System
     2 + % MultiArrayPlatform. Class containing multiple arrays
     3 + %
     4 + % The class also has methods for supporting codebook design
     5 + properties
     6 +
     7 + % Cell array of array platforms
     8 + arrPlat;
     9 +
     10 + % Codebook parameters
     11 + azCw, elCw; % Angles for each codewords
     12 + cwArrInd; % CW i goes out over array cwArrInd(i)
     13 + codeWord; % nelem x ncw
     14 + cwGainMax; % Max gain over codewords in dBi
     15 + end
     16 +
     17 + methods
     18 + function obj = MultiArrayPlatform(param)
     19 + arguments
     20 + param.narr
     21 + param.elem
     22 + param.array
     23 + param.fc = 28e9
     24 + end
     25 +
     26 + % Create the cell array of platforms
     27 + obj.arrPlat = cell(param.narr,1);
     28 + for i = 1:param.narr
     29 + obj.arrPlat{i} = ArrayPlatform(...
     30 + 'elem', param.elem, 'arr', param.array, 'fc', param.fc);
     31 + obj.arrPlat{i}.computeNormMatrix();
     32 + end
     33 + end
     34 +
     35 + function alignAzimuth(obj, az0)
     36 + % Align the arrays across uniformly in the azimuth plane
     37 + %
     38 + % Array i is aligned to az0 + (i-1)*360/narr
     39 +
     40 + if nargin < 2
     41 + az0 = 0;
     42 + end
     43 +
     44 + % Compute the angles to align the arrays
     45 + narr = length(obj.arrPlat);
     46 +
     47 +
     48 + for i = 1:narr
     49 + az = mod(az0 + (i-1)*360/narr,360);
     50 + if (az > 180)
     51 + az = az - 360;
     52 + end
     53 + obj.arrPlat{i}.alignAxes(az, 0);
     54 + end
     55 +
     56 + end
     57 +
     58 + function nelem = getNumElements(obj)
     59 + nelem = obj.arrPlat{1}.getNumElements();
     60 + end
     61 +
     62 +
     63 + function createCodebook(obj, options)
     64 + % Creates a codebook.
     65 + % Right now, only a uniform layout in the azimuth direction is
     66 + % supported
     67 + arguments
     68 + obj
     69 + options.layout = 'azimuth'
     70 + options.numCodeWords = 0
     71 + end
     72 +
     73 + % Get the dimensions
     74 + narr = length(obj.arrPlat);
     75 + nelem = obj.arrPlat{1}.getNumElements();
     76 +
     77 + % Get the number of codewords
     78 + % By default, use the number of elements in the array
     79 + if (options.numCodeWords <= 0)
     80 + ncw = narr * nelem;
     81 + else
     82 + ncw = options.numCodeWords;
     83 + end
     84 +
     85 + % Get desired angle for each codeword
     86 + if strcmp(options.layout, 'azimuth')
     87 + obj.azCw = (1:ncw)'*360/ncw-180;
     88 + obj.elCw = zeros(ncw,1);
     89 + else
     90 + e = MException('MultiArrayPlatform',...
     91 + 'Unsupported layout %s', options.layout);
     92 + throw(e);
     93 + end
     94 +
     95 + % Get the steering vector in each direction from each
     96 + % array
     97 + Sv = obj.step(obj.azCw, obj.elCw);
     98 +
     99 + % Find the array with the maximum gain
     100 + gain = reshape(sum(abs(Sv).^2,1), ncw, narr);
     101 + [obj.cwGainMax, obj.cwArrInd] = max(gain, [], 2);
     102 + obj.cwGainMax = pow2db(obj.cwGainMax);
     103 +
     104 + % Get the codewords
     105 + obj.codeWord = zeros(nelem, ncw);
     106 + for i = 1:ncw
     107 + j = obj.cwArrInd(i);
     108 + obj.codeWord(:,i) = Sv(:,i,j);
     109 + obj.codeWord(:,i) = conj(obj.codeWord(:,i))/...
     110 + norm(obj.codeWord(:,i));
     111 +
     112 + end
     113 +
     114 + end
     115 +
     116 + function ncw = getNumCW(obj)
     117 + % Gets number of codewords
     118 + ncw = length(obj.azCw);
     119 + end
     120 +
     121 + function ncw = getNumArrays(obj)
     122 + % Gets number of codewords
     123 + ncw = length(obj.arrPlat);
     124 + end
     125 +
     126 + function gainComplex = cwGain(obj, az, el, cwInd, relSV)
     127 + arguments
     128 + obj
     129 + az
     130 + el
     131 + cwInd = 'all'
     132 + relSV logical = true
     133 + end
     134 + % Gets the gain of a vectors on codeword directions
     135 + %
     136 + % az, el: The angles of arrival to compute the gains
     137 + % cwInd: The codeword indices to compute the gains
     138 + if strcmp(cwInd, 'all')
     139 + ncw = size(obj.codeWord, 2);
     140 + cwInd = (1:ncw);
     141 + end
     142 +
     143 + % Get the steering vectors in the angles from all the arrays
     144 + Sv = obj.step(az, el, relSV);
     145 +
     146 + % Get the complex gains
     147 + ncw = length(cwInd);
     148 + nang = length(az);
     149 + gainComplex = zeros(nang, ncw);
     150 + for i = 1:ncw
     151 + j = obj.cwArrInd(i);
     152 + gainComplex(:,i) = sum(obj.codeWord(:,i).*Sv(:,:,j), 1);
     153 + end
     154 +
     155 +
     156 + end
     157 +
     158 + end
     159 +
     160 + methods (Access = protected)
     161 +
     162 + function setupImpl(obj)
     163 + % setup: This is called before the first step.
     164 + narr = length(obj.arrPlat);
     165 + for i = 1:narr
     166 + obj.arrPlat{i}.setup();
     167 + end
     168 + end
     169 +
     170 + function releaseImpl(obj)
     171 + % Release the object
     172 + narr = length(obj.arrPlat);
     173 + for i = 1:narr
     174 + obj.arrPlat{i}.release();
     175 + end
     176 + end
     177 +
     178 + function [Sv, elemGain] = stepImpl(obj, az, el, relSV)
     179 + % Gets normalized steering vectors and element gains for a set of angles
     180 + % The angles az and el should be columns vectors along which
     181 + % the outputs are to be computed.
     182 + % If the relSV == true, then the steering vector object is
     183 + % released. This is needed in case the dimensions of the past
     184 + % call are the different from the past one
     185 +
     186 + % Release the SV
     187 + if nargin < 4
     188 + relSV = true;
     189 + end
     190 +
     191 + % Get dimensions
     192 + narr = length(obj.arrPlat);
     193 + nelem = obj.arrPlat{1}.getNumElements();
     194 + nang = length(az);
     195 +
     196 +
     197 + % Get the SV and element gains for each array
     198 + Sv = zeros(nelem,nang,narr);
     199 + elemGain = zeros(nang,narr);
     200 + for i = 1:narr
     201 + [Sv(:,:,i), elemGain(:,i)] = obj.arrPlat{i}.step(az, el, relSV);
     202 + end
     203 +
     204 +
     205 + end
     206 +
     207 + end
     208 +
     209 +end
     210 + 
  • unit10_directional/beamSearchDemo.mlx
    Binary file.
  • unit10_directional/indoorDataDemo.mlx
    Binary file.
  • unit10_directional/roomPathData.mat
    Binary file.
Please wait...
Page is in error, reload to recover