Projects STRLCPY wirelesscomm Commits 092082d4
🤬
  • ■ ■ ■ ■ ■
    readme.md
    skipped 77 lines
    78 78   * Lecture: [[PDF]](./lectures/Unit08_Beamforming.pdf) [[PPT]](./lectures/Unit08_Beamforming.pptx)
    79 79   * Demo: Visualizing and simualting arrays [[PDF]](./unit08_bf/demoBF.pdf) [[Matlab Live]](./unit08_bf/demoBF.mlx)
    80 80   * Demo: Pattern multiplication and mutual coupling [[PDF]](./unit08_bf/mutualCoupling.pdf) [[Matlab Live]](./unit08_bf/mutualCoupling.mlx)
     81 + * Lab: Simulating beamforming on a 28 GHz channel [[PDF]](./unit08_bf/labPartial/labBF.pdf) [[Matlab Live]](./unit08_bf/labPartial/labBF.pdf)
    81 82   * Problems: [[PDF]](./unit08_bf/prob/prob_bf.pdf) [[Latex]](./unit08_bf/prob/prob_bf.tex)
    82 83  * Unit 9. Beam Tracking and Directional Estimation
    83 84  * Unit 10. Introduction to MIMO
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    unit08_bf/labPartial/ArrayPlatform.m
     1 +classdef ArrayPlatform < matlab.System
     2 + % ArrayWithAxes. 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 +
     60 +
     61 + % TODO: Create the gridded interpolant object
     62 + % for element gain
     63 + % obj.elemGainInterp = griddedInterpolant(...);
     64 +
     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 +
     75 + 
     76 + % TODO: Get the steering vectors
     77 + % Sv0 = obj.svObj(...);
     78 +
     79 +
     80 + % TODO: Compute un-normalized spatial signature
     81 + % by multiplying the steering vectors with the element gain
     82 + % SvNoNorm = ...
     83 +
     84 +
     85 + % TODO: Compute the normalization matrix by integrating the
     86 + % un-normalized steering vectors
     87 + % Q = ...
     88 +
     89 + % Ensure matrix is Hermitian
     90 + Q = (Q+Q')/2;
     91 +
     92 + % TODO: Save the inverse matrix square root of Q
     93 + % obj.Qinv = ...
     94 +
     95 + end
     96 +
     97 + function alignAxes(obj,az,el)
     98 + % Aligns the axes to given az and el angles
     99 +
     100 + % Set the axesAz and axesEl to az and el
     101 + obj.axesAz = az;
     102 + obj.axesEl = el;
     103 +
     104 + % Creates axes aligned with az and el
     105 + obj.axesLoc = azelaxes(az,el);
     106 + end
     107 +
     108 + function dop = doppler(obj,az,el)
     109 + % Computes the Doppler shift of a set of paths
     110 + % The angles of the paths are given as (az,el) pairs
     111 + % in the global frame of reference.
     112 +
     113 + % Finds unit vectors in the direction of each path
     114 + npath = length(el);
     115 + [u1,u2,u3] = sph2cart(deg2rad(az),deg2rad(el),ones(1,npath));
     116 + u = [u1; u2; u3];
     117 +
     118 + % Compute the Doppler shift of each path via an inner product
     119 + % of the path direction and velocity vector.
     120 + vcos = obj.vel*u;
     121 + vc = physconst('lightspeed');
     122 + dop = vcos*obj.fc/vc;
     123 +
     124 + end
     125 +
     126 + function releaseSV(obj)
     127 + % Creates the steering vector object if it has not yet been
     128 + % created. Otherwise release it. This is needed since the
     129 + % sv object requires that it takes the same number of
     130 + % inputs each time.
     131 + if isempty(obj.svObj)
     132 + obj.svObj = phased.SteeringVector('SensorArray',obj.arr);
     133 + else
     134 + obj.svObj.release();
     135 + end
     136 +
     137 + end
     138 +
     139 + function n = getNumElements(obj)
     140 + % Gets the number of elements
     141 + n = obj.arr.getNumElements();
     142 +
     143 + end
     144 +
     145 + function elemPosGlob = getElementPos(obj)
     146 + % Gets the array elements in the global reference frame
     147 +
     148 + % Get the element position in the local reference frame
     149 + elemPosLoc = obj.arr.getElementPosition();
     150 +
     151 + % Convert to the global reference frame
     152 + elemPosGlob = local2globalcoord(elemPosLoc, 'rr', ...
     153 + zeros(3,1), obj.axesLoc) + reshape(obj.pos,3,1);
     154 + end
     155 +
     156 + end
     157 +
     158 + methods (Access = protected)
     159 +
     160 + function setupImpl(obj)
     161 + % setup: This is called before the first step.
     162 + obj.computeNormMatrix();
     163 +
     164 +
     165 + end
     166 +
     167 + function releaseImpl(obj)
     168 + % release: Called to release the object
     169 + obj.svObj.release();
     170 + end
     171 +
     172 + function [Sv, elemGain] = stepImpl(obj, az, el, relSV)
     173 + % Gets normalized steering vectors and element gains for a set of angles
     174 + % The angles az and el should be columns vectors along which
     175 + % the outputs are to be computed.
     176 + % If the relSV == true, then the steering vector object is
     177 + % released. This is needed in case the dimensions of the past
     178 + % call are the different from the past one
     179 +
     180 + % Release the SV
     181 + if nargin < 4
     182 + relSV = true;
     183 + end
     184 + if relSV
     185 + obj.releaseSV();
     186 + end
     187 +
     188 + % TODO: Convert the global angles (az, el) to local
     189 + % angles (azLoc, elLoc). Use the
     190 + % global2localcoord() method with the 'ss' option.
     191 +
     192 +
     193 + % TODO: Get the SV in the local coordinates
     194 + % Sv0 = obj.svObj(...)
     195 +
     196 +
     197 + % TODO: Get the directivity gain of the element from the
     198 + % local angles.
     199 + % elemGain = obj.elem.step(...)
     200 +
     201 +
     202 + % TODO: Compute the normalized steering vectors
     203 + % Sv = ...
     204 +
     205 +
     206 +
     207 + end
     208 + 
     209 + end
     210 +
     211 +
     212 +end
     213 + 
  • ■ ■ ■ ■ ■ ■
    unit08_bf/labPartial/FDMIMOChan.m
     1 +classdef FDMIMOChan < matlab.System
     2 + % Frequency-domain MIMO multipath channel
     3 + properties
     4 + % Configuration
     5 + carrierConfig; % Carrier configuration
     6 + waveformConfig; % Waveform parameters
     7 +
     8 + % Path parameters
     9 + gain; % Relative path gain in dB
     10 + dly; % Delay of each path in seconds
     11 + aodAz, aodEl; % Angle of departure of each path in degrees
     12 + aoaAz, aoaEl; % Angle of arrival of each path in degrees
     13 +
     14 + % Derived path parameters
     15 + fd; % Doppler shift for each path
     16 + gainComplex; % Complex gain of each path
     17 + svTx, svRx; % Steering vectors for each path
     18 + elemGainTx, elemGainRx; % Element gains
     19 +
     20 + % Other parmaters
     21 + fc = 28e9; % Carrier freq in Hz
     22 + rxVel = [30,0,0]'; % RX velocity vector in m/s
     23 + txVel = [0,0,0]'; % TX velocity vector in m/s
     24 + Enoise = 0; % Noise energy per sample in dBmJ
     25 +
     26 + % Symbol times
     27 + symStart; % symStart(i) = start of symbol i relative to subframe
     28 +
     29 + % TX and RX array platforms
     30 + txArrPlatform = [];
     31 + rxArrPlatform = [];
     32 +
     33 + end
     34 + methods
     35 + function obj = FDMIMOChan(carrierConfig, varargin)
     36 + % Constructor
     37 +
     38 + % Save the carrier configuration
     39 + obj.carrierConfig = carrierConfig;
     40 +
     41 + % Set parameters from constructor arguments
     42 + if nargin >= 1
     43 + obj.set(varargin{:});
     44 + end
     45 +
     46 + % Check all the required fields are specified
     47 + fields = {'txArrPlatform', 'rxArrPlatform', 'gain', 'dly', ...
     48 + 'aoaAz', 'aodAz', 'aoaEl', 'aoaAz' };
     49 + nfields = length(fields);
     50 + for i = 1:nfields
     51 + fstr = fields{i};
     52 + if isempty(obj.(fstr))
     53 + e = MException('FDMIMOChan:missingParam', ...
     54 + 'Parameter %s not speficied', fstr);
     55 + throw(e);
     56 + end
     57 + end
     58 +
     59 + % Complex gain for each path using a random initial phase
     60 + % The gains are normalized to an average of one
     61 + npath = length(obj.gain);
     62 + phase = 2*pi*rand(npath, 1);
     63 + obj.gainComplex = db2mag(obj.gain).*exp(1i*phase);
     64 +
     65 + % Symbol times relative to the start of the subframe
     66 + obj.waveformConfig = nrOFDMInfo(obj.carrierConfig);
     67 + nsym = obj.waveformConfig.SymbolLengths;
     68 + obj.symStart = nsym/obj.waveformConfig.SampleRate;
     69 + obj.symStart = cumsum([0 obj.symStart]');
     70 +
     71 + % Get Doppler shift for RX
     72 + vc = physconst('Lightspeed');
     73 + [ux, uy, uz] = sph2cart(deg2rad(obj.aoaAz), deg2rad(obj.aoaEl), 1);
     74 + obj.fd = [ux uy uz]*obj.rxVel*obj.fc/vc;
     75 +
     76 + % Get Doppler shift for TX
     77 + [ux, uy, uz] = sph2cart(deg2rad(obj.aodAz), deg2rad(obj.aodEl), 1);
     78 + obj.fd = obj.fd + [ux uy uz]*obj.txVel*obj.fc/vc;
     79 + end
     80 +
     81 + function computePathSV(obj)
     82 + % Computes the element gains and steering vectors of each path
     83 +
     84 + % Call the array platform objects to get the steering vectors
     85 + % and element gains
     86 + [obj.svTx, obj.elemGainTx] = ...
     87 + obj.txArrPlatform.step(obj.aodAz, obj.aodEl);
     88 + [obj.svRx, obj.elemGainRx] = ...
     89 + obj.rxArrPlatform.step(obj.aoaAz, obj.aoaEl);
     90 +
     91 + end
     92 +
     93 +
     94 + end
     95 + methods (Access = protected)
     96 +
     97 +
     98 + function [chanGrid, noiseVar] = stepImpl(obj, frameNum, slotNum)
     99 + % Applies a frequency domain channel and noise
     100 + %
     101 + % Parameters
     102 + % ----------
     103 + % frameNum: The index of the frame (1 frame = 10ms)
     104 + % slotNum: The index of the slot in the frame
     105 + % This should be 0,...,waveformConfig.SlotsPerFrame
     106 + %
     107 + % Outputs
     108 + % -------
     109 + % chanGrid: Grid of the channel values
     110 + % noiseVar: Noise variance
     111 +
     112 + % Compute the steering vectors and element gains
     113 + obj.computePathSV();
     114 +
     115 + % Get the number of TX and RX elements
     116 + ntx = obj.txArrPlatform.getNumElements();
     117 + nrx = obj.rxArrPlatform.getNumElements();
     118 +
     119 + % Get the number of sub-carriers
     120 + nscPerRB = 12;
     121 + nsc = obj.carrierConfig.NSizeGrid * nscPerRB;
     122 + nsym = obj.carrierConfig.SymbolsPerSlot;
     123 +
     124 + % Compute the frequency of each carrier
     125 + f = (0:nsc-1)'*obj.carrierConfig.SubcarrierSpacing*1e3;
     126 +
     127 + % Compute slot in sub-frame and sub-frame index
     128 + sfNum = floor(slotNum / obj.waveformConfig.SlotsPerSubframe);
     129 + slotNum1 = mod(slotNum, obj.waveformConfig.SlotsPerSubframe);
     130 +
     131 + % Compute the time for each symbol
     132 + framePeriod = 0.01;
     133 + sfPeriod = 1e-3;
     134 + t = frameNum*framePeriod + sfPeriod*sfNum + ...
     135 + obj.symStart(slotNum1+1:slotNum1+nsym);
     136 +
     137 + % Initialize the channel grid to zero
     138 + chanGrid = zeros(nrx, ntx, nsc, nsym);
     139 + npath = length(obj.gain);
     140 +
     141 + 
     142 + % TODO: Set the channel:
     143 + %
     144 + % chanGrid(j,k,n,t) = MIMO channel matrix from
     145 + % RX antenna j, TX antenna k, sub-carrier n,
     146 + % symbol t.
     147 + %
     148 + % This should be a sum of the paths
     149 + %
     150 + % chanGrid(j,k,:,:)
     151 + % = \sum_i exp(1i*phase)*svRx(j,i)*svTx(k,i)
     152 + %
     153 + % where
     154 + %
     155 + % phase = 2*pi*(f*obj.dly(i) + t'*obj.fd(i));
     156 +
     157 +
     158 + % Compute noise variance
     159 + noiseVar = db2pow(obj.Enoise);
     160 +
     161 +
     162 + end
     163 +
     164 + end
     165 +end
     166 + 
     167 + 
  • unit08_bf/labPartial/labBF.mlx
    Binary file.
  • unit08_bf/labPartial/labBF.pdf
    Binary file.
  • unit08_bf/mutualCoupling.mlx
    Binary file.
Please wait...
Page is in error, reload to recover