Measure Impact of Sub-THz Hardware Impairments on 6G Waveforms
This example shows how to explore the impact of hardware impairments at sub-THz frequencies on a candidate 6G waveform. The hardware impairments are: phase noise, power amplifier (PA) nonlinearity, and a filter to limit spectral emissions outside of the channel bandwidth. The example measures the complementary cumulative distribution function (CCDF) of the waveform power, adjacent channel power ratio (ACPR) and error vector magnitude (EVM) of the impaired waveform to demonstrate the impact of impairments.
Set System Parameters
This example models a pre-6G OFDM or DFT-s-OFDM (Discrete Fourier Transform spread Orthogonal Frequency Division Multiplexing) waveform with system parameters defined in Hexa-X Deliverable D2.3 Table 5-7 [1] to investigate the impact of hardware impairments on candidate 6G waveforms. DFT-s-OFDM is a technique used in the uplink of 5G NR to spread symbols in the frequency domain to reduce the peak to average power ratio (PAPR) compared to OFDM.
carrierFrequency = 140; % GHz bandwidth = 2160; % MHz - transmission bandwidth and guardbands subcarrierSpacing = 3840; % kHz waveform = "OFDM"; % Waveform modulation
Set the bandwidth occupancy. This is the ratio between the transmission bandwidth and channel bandwidth. A lower bandwidth occupancy increases the size of guardbands, reducing spectral emissions at the cost of reduced spectral efficiency.
bandwidthOccupancy = 0.8; % Ratio of transmission bandwidth to channel bandwidth
Create a carrier configuration. Calculate the transmission bandwidth and required number of resource blocks (NSizeGrid
) given the bandwidth occupancy.
carrier = pre6GCarrierConfig; carrier.SubcarrierSpacing = subcarrierSpacing; channelBandwidth = bandwidth*1e6; % Bandwidth of RBs and guard carriers in Hz carrier.NSizeGrid = floor((channelBandwidth/(carrier.SubcarrierSpacing*1e3)*bandwidthOccupancy)/12); % 12 subcarriers per RB transmissionBandwidth = carrier.SubcarrierSpacing*1e3*carrier.NSizeGrid*12; % Bandwidth of RBs in Hz
This example creates a time division duplex (TDD) waveform consisting of a pattern of downlink slots followed by uplink slots with a specified period. Set the length of the waveform and TDD parameters.
numSubframes = 0.5; % Number of subframes to simulate tddConfig.TDDPeriod = 10; % TDD period in slots tddConfig.NumDownlinkSlots = 9; % Number of slots in TDD period containing PDSCH numSlots = numSubframes*carrier.SlotsPerSubframe; tddConfig.SlotAllocation = 0:tddConfig.NumDownlinkSlots-1; % Assume downlink slots at start of TDD period disp("Simulating "+numSlots+" slots")
Simulating 128 slots
visualizeTDDAllocation(tddConfig);
Configure a physical downlink shared channel (PDSCH) for full resource block (RB) allocation and enable the phase tracking reference signal (PT-RS).
pdsch = pre6GPDSCHConfig; pdsch.PRBSet = 0:(carrier.NSizeGrid-1); pdsch.Modulation = "16QAM"; pdsch.EnablePTRS = true;
Generate Waveform
Create a resource grid containing a PDSCH transmission, demodulation reference signal (DM-RS), and PT-RS in appropriate TDD slots. Transform precoding is applied if you set waveform
to "DFT-s-OFDM"
. Note that the DM-RS is not transform precoded.
waveGrid = []; % Store resource grid to transmit for nSlot = 0:(numSlots-1) carrier.NSlot = nSlot; txSlotGrid = hpre6GResourceGrid(carrier,pdsch.NumLayers); % Generate content if slot allocated to PDSCH if isSlotActive(carrier.NSlot,tddConfig) [pdschInd,indInfo] = hpre6GPDSCHIndices(carrier,pdsch); % Generate and map PDSCH for a random codeword cw = randi([0 1],indInfo.G,1); pdschSym = hpre6GPDSCH(carrier,pdsch,cw); txSlotGrid(pdschInd) = pdschSym; % Generate and map PT-RS ptrsInd = hpre6GPDSCHPTRSIndices(carrier,pdsch); ptrsSym = hpre6GPDSCHPTRS(carrier,pdsch); txSlotGrid(ptrsInd) = ptrsSym; if waveform=="DFT-s-OFDM" txSlotGrid = transformPrecode(pdsch,txSlotGrid,pdschInd,ptrsInd); end % Generate and map DM-RS dmrsInd = hpre6GPDSCHDMRSIndices(carrier,pdsch); dmrsSym = hpre6GPDSCHDMRS(carrier,pdsch); txSlotGrid(dmrsInd) = dmrsSym; end waveGrid = [waveGrid txSlotGrid]; end
OFDM-modulate the resource grid with an oversampling factor. Oversample the waveform to measure spectral emissions outside of the channel bandwidth. The example sets the FFT size such that it spans the specified oversampled channel bandwidth and is an integer multiple of 128 for a normal cyclic prefix length.
% OFDM-modulate with specified oversampling factor oversamplingFactor = 3; % Multiple of the channel bandwidth carrier.NSlot = 0; % OFDM-modulate from slot 0 nFFTWaveform = ceil((channelBandwidth/(carrier.SubcarrierSpacing*1e3))*oversamplingFactor/128)*128; [txWaveform,ofdmInfo] = hpre6GOFDMModulate(carrier,waveGrid,Nfft=nFFTWaveform); % Normalize waveform to maximum amplitude for PA modeling txWaveform = txWaveform/max(abs(txWaveform),[],"all"); % Prepend slot to the waveform to allow for filter delay waveformLength = height(txWaveform); slotLength = waveformLength/numSlots; txWaveform = [txWaveform(end-slotLength+1:end,:); txWaveform];
Add Impairments
In this section, you model phase noise and power amplifier (PA) nonlinearity impairments, and apply a filter to limit spectral emissions outside of the channel bandwidth.
Phase Noise
Introduce phase noise distortion. This example uses a phase noise model defined in Hexa-X Deliverable D2.3 Section 4.2.1.1, scaled to 140 GHz as specified in Hexa-X Deliverable D2.3 Table 5-7. This Hexa-X model is based on measurements of 20 GHz wideband RF synthesizer TI LMX2596. Set the minimum frequency offset the phase noise model uses to compute the phase noise spectrum mask. By default, this example uses a 1 MHz minimum frequency offset, therefore the phase noise level below 1 MHz does not match the Hexa-X model. Simulating with a lower minimum frequency offset will more accurately model the low frequency phase noise of the Hexa-X model but result in a longer time to design the phase noise filter.
impariredWaveform = txWaveform; enablePN = true; % Enable phase noise model if enablePN minimumFrequencyOffset = 1e6; % Hz mdl = "HexaX Model 2"; phaseNoise = hpre6GPhaseNoise(carrierFrequency*1e9,ofdmInfo.SampleRate, ... MinFrequencyOffset=minimumFrequencyOffset,Model=mdl, ... RandomStream="mt19937ar with seed"); visualize(phaseNoise); % Show phase noise PSD impariredWaveform = phaseNoise(impariredWaveform); % Apply phase noise model end
Low-Pass Filter
Filter the baseband waveform to limit emissions outside the channel bandwidth. If the current passband and stopband frequencies, PassbandFrequency
and StopbandFrequency
, result in high EVM values, use a wider filter by increasing PassbandFrequency
and StopbandFrequency
. To use a narrower filter, reduce PassbandFrequency
and StopbandFrequency
. You can also modify the PassbandRipple
and the StopbandAttenuation
.
enableLPF = true; % Enable low-pass filter if enableLPF % Create low-pass filter object LPF = dsp.LowpassFilter; LPF.SampleRate = ofdmInfo.SampleRate; LPF.FilterType = "IIR"; LPF.PassbandFrequency = (transmissionBandwidth + 24*carrier.SubcarrierSpacing*1e3)/2; LPF.StopbandFrequency = channelBandwidth/2; % TransmissionBandwidth and guards LPF.PassbandRipple = 0.2; LPF.StopbandAttenuation = 40; figure; freqz(LPF); % Plot the response of the low-pass filter % Filter the waveform impariredWaveform = LPF(impariredWaveform); release(LPF); end
Power Amplifier
Apply a PA impairment model. This example applies a memoryless GaN PA model as described in Hexa-X Deliverable D2.3 Table 5-7 and Hexa-X Deliverable D2.2 Section 3.6.6.1 [2]. This model assumes the ACPR characteristic with respect to PA output power shift according to the expected downscaling of maximum PA output power when increasing frequency.
Set the model backoff to reduce the amplitude of the input signal and reduce distortion.
enablePA = true; % Enable power amplifier model if enablePA backoff = 6; % In dB impariredWaveform = db2mag(-backoff)*impariredWaveform; % Apply PA backoff visualizeAMAMCharacteristic(@paMemorylessGaN,"GaN"); impariredWaveform = paMemorylessGaN(impariredWaveform); end
Measure ACPR
Measure the ACPR to study spectral regrowth caused by the nonlinear PA model.
measureACPR = true; if measureACPR % Calculate the number of adjacent channels which can be measured given % the sample rate numAdjacentChannels = floor((ofdmInfo.SampleRate/channelBandwidth-1)/2); if numAdjacentChannels>0 sa = spectrumAnalyzer; sa.SampleRate = ofdmInfo.SampleRate; sa.ChannelMeasurements.Type = "acpr"; sa.ChannelMeasurements.Enabled = true; sa.ChannelMeasurements.Span = transmissionBandwidth; sa.ChannelMeasurements.NumOffsets = numAdjacentChannels; sa.ChannelMeasurements.AdjacentBW = transmissionBandwidth; sa.ChannelMeasurements.ACPROffsets = (1:numAdjacentChannels)*channelBandwidth; sa(impariredWaveform); else warning("Sample rate too low to measure ACPR, increase oversamplingFactor") end end
Measure CCDF
Measure the CCDF to evaluate the PAPR of the waveform.
measureCCDF = true; if measureCCDF pm = powermeter(ComputeCCDF=true); averagePower = pm(impariredWaveform); disp("Average power: "+averagePower+" dBm") figure; plotCCDF(pm,GaussianReference=true) end
Average power: 11.0304 dBm
Measure EVM
Perform the following steps to measure the EVM:
Synchronize the received waveform
OFDM-demodulate the received waveform
Perform channel estimation
Equalize the PDSCH symbols
Perform transform de-precoding
Estimate and compensate the common phase error (CPE)
Compute PDSCH EVM
Show the equalized PDSCH symbols for each slot.
% Ignore transients in first part of waveform rxWaveform = impariredWaveform; rxWaveform(1:slotLength,:) = []; % Timing synchronization refSlotGrid = waveGrid(:,1:carrier.SymbolsPerSlot,:); refWaveform = hpre6GOFDMModulate(carrier,refSlotGrid,Nfft=ofdmInfo.Nfft); offset = timingEstimate(rxWaveform,refWaveform); rxWaveform = rxWaveform(1+offset:end,:); % Demodulate and measure EVM of each slot rxWaveGrid = hpre6GOFDMDemodulate(carrier,rxWaveform,Nfft=ofdmInfo.Nfft); % Setup constellation diagram constDiagram = comm.ConstellationDiagram; constDiagram.ShowReferenceConstellation = true; L = carrier.SymbolsPerSlot; numRxSlots = floor(size(rxWaveGrid,2)/L); if numRxSlots<1 error("Not enough data to measure EVM, increase numSubframes") end evGrid = []; % Store error vector for each resource element evm = []; % Store EVM measurement for each slot containing PDSCH cpe = []; for nSlot = 0:(numRxSlots-1) carrier.NSlot = nSlot; evSlotGrid = NaN*hpre6GResourceGrid(carrier,pdsch.NumLayers); % Store error vector if isSlotActive(nSlot,tddConfig) % Extract slot from grid rxSlotGrid = rxWaveGrid(:,nSlot*L+(1:L),:); % Estimate channel pdschDMRSInd = hpre6GPDSCHDMRSIndices(carrier,pdsch); pdschDMRSSymbols = hpre6GPDSCHDMRS(carrier,pdsch); [hest,nVar] = hpre6GChannelEstimate(carrier,rxSlotGrid,pdschDMRSInd,pdschDMRSSymbols,CDMLengths=pdsch.DMRS.CDMLengths); % Equalize PDSCH and PT-RS [pdschInd,pdschIndInfo] = hpre6GPDSCHIndices(carrier,pdsch); ptrsInd = hpre6GPDSCHPTRSIndices(carrier,pdsch); ind = [pdschInd; ptrsInd]; [rxSym,rxSymHest] = nrExtractResources(ind,rxSlotGrid,hest); eqSym = nrEqualizeMMSE(rxSym,rxSymHest,nVar); eqSlotGrid = hpre6GResourceGrid(carrier,pdsch.NumLayers); eqSlotGrid(ind) = eqSym; if waveform=="DFT-s-OFDM" eqSlotGrid = transformDeprecode(pdsch,eqSlotGrid,pdschInd,ptrsInd); end % Correct common phase error eqSlotGrid = correctCPE(carrier,pdsch,pdschIndInfo,eqSlotGrid); % Demap, decode, and re-modulate to obtain layer demapped equalized % symbols (rxSym) and reference symbols (refSym) for EVM % measurement. pdschEqSym = eqSlotGrid(pdschInd); [cw,rxSym] = hpre6GPDSCHDecode(carrier,pdsch,pdschEqSym,nVar); expectedCW = cw{1}<0; % LLR<0 is bit 1, otherwise bit 0 expectedPDSCHSym = hpre6GPDSCH(carrier,pdsch,expectedCW); [~,refSym] = hpre6GPDSCHDecode(carrier,pdsch,expectedPDSCHSym,0); % Show equalized PDSCH constellation constDiagram.ReferenceConstellation = unique(refSym{1}); constDiagram.Title = "Equalized PDSCH slot "+num2str(nSlot); constDiagram(rxSym{1}); % Calculate error vector and EVM slotEVM = measureEVM(refSym{1},rxSym{1}); fprintf("Slot %d PDSCH EVM, RMS: %0.3f%% Peak: %0.3f%%\n",nSlot,slotEVM.RMS*100,slotEVM.Peak*100); evm = [evm slotEVM]; % Store error vector in grid evSlotGrid = NaN(size(rxSlotGrid)); evSlotGrid(pdschInd) = slotEVM.EV; end evGrid = [evGrid evSlotGrid]; %#ok<*AGROW> end
Slot 0 PDSCH EVM, RMS: 3.755% Peak: 16.844% Slot 1 PDSCH EVM, RMS: 3.100% Peak: 15.873% Slot 2 PDSCH EVM, RMS: 3.036% Peak: 12.505% Slot 3 PDSCH EVM, RMS: 2.989% Peak: 11.587% Slot 4 PDSCH EVM, RMS: 2.901% Peak: 11.346% Slot 5 PDSCH EVM, RMS: 2.573% Peak: 8.262% Slot 6 PDSCH EVM, RMS: 2.675% Peak: 8.874% Slot 7 PDSCH EVM, RMS: 2.788% Peak: 10.717% Slot 8 PDSCH EVM, RMS: 2.911% Peak: 13.210% Slot 10 PDSCH EVM, RMS: 3.032% Peak: 8.778% Slot 11 PDSCH EVM, RMS: 2.729% Peak: 8.867% Slot 12 PDSCH EVM, RMS: 3.036% Peak: 11.233% Slot 13 PDSCH EVM, RMS: 3.365% Peak: 11.645% Slot 14 PDSCH EVM, RMS: 2.763% Peak: 10.647% Slot 15 PDSCH EVM, RMS: 2.611% Peak: 8.835% Slot 16 PDSCH EVM, RMS: 3.086% Peak: 12.029% Slot 17 PDSCH EVM, RMS: 3.428% Peak: 12.731% Slot 18 PDSCH EVM, RMS: 2.794% Peak: 8.649% Slot 20 PDSCH EVM, RMS: 3.044% Peak: 13.066% Slot 21 PDSCH EVM, RMS: 2.572% Peak: 8.695% Slot 22 PDSCH EVM, RMS: 2.999% Peak: 11.147% Slot 23 PDSCH EVM, RMS: 3.131% Peak: 13.562% Slot 24 PDSCH EVM, RMS: 3.420% Peak: 12.666% Slot 25 PDSCH EVM, RMS: 4.019% Peak: 16.212% Slot 26 PDSCH EVM, RMS: 2.689% Peak: 10.144% Slot 27 PDSCH EVM, RMS: 2.467% Peak: 7.728% Slot 28 PDSCH EVM, RMS: 2.804% Peak: 9.291% Slot 30 PDSCH EVM, RMS: 2.796% Peak: 13.386% Slot 31 PDSCH EVM, RMS: 3.154% Peak: 11.011% Slot 32 PDSCH EVM, RMS: 2.747% Peak: 9.354% Slot 33 PDSCH EVM, RMS: 2.636% Peak: 9.154% Slot 34 PDSCH EVM, RMS: 2.934% Peak: 11.586% Slot 35 PDSCH EVM, RMS: 2.540% Peak: 8.860% Slot 36 PDSCH EVM, RMS: 3.053% Peak: 9.888% Slot 37 PDSCH EVM, RMS: 3.156% Peak: 12.925% Slot 38 PDSCH EVM, RMS: 3.190% Peak: 15.825% Slot 40 PDSCH EVM, RMS: 3.005% Peak: 10.599% Slot 41 PDSCH EVM, RMS: 2.528% Peak: 8.828% Slot 42 PDSCH EVM, RMS: 2.824% Peak: 10.614% Slot 43 PDSCH EVM, RMS: 2.726% Peak: 10.576% Slot 44 PDSCH EVM, RMS: 2.735% Peak: 10.777% Slot 45 PDSCH EVM, RMS: 2.748% Peak: 9.195% Slot 46 PDSCH EVM, RMS: 2.985% Peak: 9.066% Slot 47 PDSCH EVM, RMS: 2.539% Peak: 8.803% Slot 48 PDSCH EVM, RMS: 3.371% Peak: 13.485% Slot 50 PDSCH EVM, RMS: 2.805% Peak: 8.677% Slot 51 PDSCH EVM, RMS: 2.428% Peak: 9.136% Slot 52 PDSCH EVM, RMS: 3.684% Peak: 17.043% Slot 53 PDSCH EVM, RMS: 2.802% Peak: 10.523% Slot 54 PDSCH EVM, RMS: 2.804% Peak: 9.368% Slot 55 PDSCH EVM, RMS: 2.788% Peak: 10.153% Slot 56 PDSCH EVM, RMS: 3.136% Peak: 12.831% Slot 57 PDSCH EVM, RMS: 2.739% Peak: 8.204% Slot 58 PDSCH EVM, RMS: 2.984% Peak: 11.302% Slot 60 PDSCH EVM, RMS: 3.007% Peak: 10.760% Slot 61 PDSCH EVM, RMS: 2.622% Peak: 8.684% Slot 62 PDSCH EVM, RMS: 3.276% Peak: 11.094% Slot 63 PDSCH EVM, RMS: 3.290% Peak: 13.024% Slot 64 PDSCH EVM, RMS: 2.962% Peak: 10.227% Slot 65 PDSCH EVM, RMS: 2.817% Peak: 9.630% Slot 66 PDSCH EVM, RMS: 3.134% Peak: 11.550% Slot 67 PDSCH EVM, RMS: 3.220% Peak: 12.505% Slot 68 PDSCH EVM, RMS: 3.263% Peak: 13.111% Slot 70 PDSCH EVM, RMS: 2.905% Peak: 10.428% Slot 71 PDSCH EVM, RMS: 2.768% Peak: 10.422% Slot 72 PDSCH EVM, RMS: 2.759% Peak: 9.903% Slot 73 PDSCH EVM, RMS: 3.405% Peak: 15.982% Slot 74 PDSCH EVM, RMS: 2.293% Peak: 6.821% Slot 75 PDSCH EVM, RMS: 2.835% Peak: 8.695% Slot 76 PDSCH EVM, RMS: 3.074% Peak: 10.207% Slot 77 PDSCH EVM, RMS: 2.463% Peak: 8.090% Slot 78 PDSCH EVM, RMS: 2.713% Peak: 8.993% Slot 80 PDSCH EVM, RMS: 3.273% Peak: 12.462% Slot 81 PDSCH EVM, RMS: 2.916% Peak: 10.495% Slot 82 PDSCH EVM, RMS: 3.408% Peak: 14.847% Slot 83 PDSCH EVM, RMS: 3.049% Peak: 10.221% Slot 84 PDSCH EVM, RMS: 3.153% Peak: 11.632% Slot 85 PDSCH EVM, RMS: 3.357% Peak: 11.146% Slot 86 PDSCH EVM, RMS: 3.099% Peak: 11.029% Slot 87 PDSCH EVM, RMS: 3.073% Peak: 12.753% Slot 88 PDSCH EVM, RMS: 3.166% Peak: 13.436% Slot 90 PDSCH EVM, RMS: 2.896% Peak: 11.020% Slot 91 PDSCH EVM, RMS: 2.797% Peak: 9.538% Slot 92 PDSCH EVM, RMS: 2.919% Peak: 13.055% Slot 93 PDSCH EVM, RMS: 2.505% Peak: 9.229% Slot 94 PDSCH EVM, RMS: 2.592% Peak: 8.633% Slot 95 PDSCH EVM, RMS: 2.651% Peak: 9.568% Slot 96 PDSCH EVM, RMS: 3.260% Peak: 10.910% Slot 97 PDSCH EVM, RMS: 2.999% Peak: 9.820% Slot 98 PDSCH EVM, RMS: 2.925% Peak: 8.608% Slot 100 PDSCH EVM, RMS: 3.065% Peak: 11.772% Slot 101 PDSCH EVM, RMS: 2.958% Peak: 9.612% Slot 102 PDSCH EVM, RMS: 2.985% Peak: 12.338% Slot 103 PDSCH EVM, RMS: 2.939% Peak: 14.105% Slot 104 PDSCH EVM, RMS: 2.889% Peak: 10.277% Slot 105 PDSCH EVM, RMS: 2.746% Peak: 11.697% Slot 106 PDSCH EVM, RMS: 2.597% Peak: 8.738% Slot 107 PDSCH EVM, RMS: 3.008% Peak: 13.573% Slot 108 PDSCH EVM, RMS: 3.126% Peak: 10.318% Slot 110 PDSCH EVM, RMS: 3.155% Peak: 12.611% Slot 111 PDSCH EVM, RMS: 3.385% Peak: 13.498% Slot 112 PDSCH EVM, RMS: 2.775% Peak: 9.324% Slot 113 PDSCH EVM, RMS: 3.258% Peak: 12.520% Slot 114 PDSCH EVM, RMS: 2.816% Peak: 13.212% Slot 115 PDSCH EVM, RMS: 3.293% Peak: 12.403% Slot 116 PDSCH EVM, RMS: 2.683% Peak: 9.193% Slot 117 PDSCH EVM, RMS: 3.166% Peak: 13.103% Slot 118 PDSCH EVM, RMS: 3.128% Peak: 11.523% Slot 120 PDSCH EVM, RMS: 3.040% Peak: 12.156% Slot 121 PDSCH EVM, RMS: 3.374% Peak: 13.415% Slot 122 PDSCH EVM, RMS: 3.069% Peak: 13.670% Slot 123 PDSCH EVM, RMS: 2.866% Peak: 10.491% Slot 124 PDSCH EVM, RMS: 2.876% Peak: 11.730% Slot 125 PDSCH EVM, RMS: 2.654% Peak: 9.544% Slot 126 PDSCH EVM, RMS: 2.971% Peak: 10.974%
Measure RMS and peak EVM for whole waveform. Elements of evGrid
contain NaN when no PDSCH is present, therefore, ignore these for the measurement (omitmissing
).
rmsEVM = sqrt(mean(abs(evGrid).^2,"all","omitmissing"))*100; peakEVM = max(abs(evGrid),[],"all","omitmissing")*100; fprintf("Overall PDSCH EVM, RMS: %0.3f%% Peak: %0.3f%%\n",rmsEVM,peakEVM);
Overall PDSCH EVM, RMS: 2.972% Peak: 17.043%
Plot EVM per subcarrier, averaged over OFDM symbols.
evmSubcarrierRMS = plotEVMPerSubcarrier(evGrid);
Plot EVM per symbol, averaged over subcarriers.
evmSymbolRMS = plotEVMPerSymbol(evGrid);
Further Exploration
Try changing the waveform modulation type to DFT-s-OFDM. Using DFT-s-OFDM results in a lower PAPR than OFDM. As the PTRS is inserted pre-DFT the EVM may be higher compared to using an OFDM waveform as tracking phase noise is more challenging [3].
References
[1] Hexa-X Deliverable D2.3 - Radio models and enabling techniques towards ultra-high data rate links and capacity in 6G.
[2] Hexa-X Deliverable D2.2 - Initial radio models and analysis towards ultra-high data rate links in 6G.
[3] Y. Qi, M. Hunukumbure, H. Nam, H. Yoo and S. Amuru, "On the Phase Tracking Reference Signal (PT-RS) Design for 5G New Radio (NR)," 2018 IEEE 88th Vehicular Technology Conference (VTC-Fall), Chicago, IL, USA, 2018, pp. 1-5, doi: 10.1109/VTCFall.2018.8690852.
Local Functions
function y = paMemorylessGaN(x) % Model 28 GHz GaN power amplifier as defined in R4-165901 Section 2.1.4 ak = [-0.334697-0.942326i; 0.89015-0.72633i; -2.58056+4.81215i; 4.81548-9.54837i; -4.41452+8.63164i; 1.54271-2.94034i]; y = x.*abs(x).^(2*(0:5))*ak; end function visualizeAMAMCharacteristic(paModel,modelName) % Plot the nonlinear characteristic of the power amplifier impairment x = logspace(-1.5,0).'; % Input samples with normalized input power y = paModel(x); % Nonlinearity figure; plot(pow2db(abs(x).^2),pow2db(abs(y).^2),'-'); hold on; plot(pow2db(abs(x).^2),pow2db(abs(x).^2),'-.'); grid on xlabel("Instantaneous normalized Input Power (dBW)"); ylabel("Instanteneous Output Power (dBW)"); title("AM/AM, "+modelName) legend(modelName+" characteristic","Linear characteristic",Location="Northwest"); end function visualizeTDDAllocation(tddConfig) % Show the TDD allocation pattern x = [0 1 1 0]; y = [0 0 1 1]; xTxtPos = (x(2)-x(1))/2+x(1); yTxtPos = (y(3)-y(1))/2+y(1)-1; % Position text below patch blocks hp = []; t = []; f = figure; for i = 0:tddConfig.TDDPeriod-1 if isSlotActive(i,tddConfig) patchColorIdx = 1; % DL slot txt = "D"; else patchColorIdx = 2; % UL slot txt = "U"; end hp = [hp patch(x+i,y,0,CDataMode="auto",SeriesIndex=patchColorIdx)]; % Use patch color from axis color series t = [t txt]; hold on; text(xTxtPos+i,yTxtPos,txt,HorizontalAlignment="center") end title(join(["TDD allocation pattern," num2str(tddConfig.TDDPeriod) "slot period"])) axis off set(gca,"DataAspectRatio",[1 1 1],"YLim",[yTxtPos*2 y(3)+0.25]); % Set limits to create space between data and title pos = get(gcf,"Position"); yScaleFactor = 3; % Scale figure to avoid excessive empty space above and below set(f,"Position",[pos(1) pos(2) pos(3) pos(4)/yScaleFactor]); hpdl = hp(find(t=="D",1)); % Handle of first downlink slot hpul = hp(find(t=="U",1)); % Handle of first uplink slot legendTxt = ["Downlink slot" "Uplink slot"]; legendTxt = legendTxt([any(t=="D") any(t=="U")]); % Remove entry if no downlink or uplink slots legend([hpdl hpul],legendTxt,location="eastoutside"); end function isActive = isSlotActive(nSlot,tddConfig) % Returns true if the carrier slot number contains the PDSCH isActive = any(mod(nSlot,tddConfig.TDDPeriod) == mod(tddConfig.SlotAllocation,tddConfig.TDDPeriod)); end function slotGrid = transformPrecode(pdsch,slotGrid,pdschInd,ptrsInd) % Perfrom transform precoding % Apply scaling to PTRS symbols ptrsSym = slotGrid(ptrsInd)*hPre6GPTRSPowerFactorDFTsOFDM(pdsch.Modulation); % Extract only PDSCH and PTRS and sort into absolute frequency/symbol % number ind = [pdschInd; ptrsInd]; [sortedCombInd,sortIdx] = sort(ind); sym = [slotGrid(pdschInd); ptrsSym]; sortedSym = sym(sortIdx); MRB = numel(pdsch.PRBSet); tp = nrTransformPrecode(sortedSym,MRB); slotGrid(sortedCombInd) = tp; end function slotGrid = transformDeprecode(pdsch,slotGrid,pdschInd,ptrsInd) % Perform transform de-precoding % De-precode ind = [pdschInd; ptrsInd]; sortedInd = sort(ind); eqSym = slotGrid(sortedInd); MRB = numel(pdsch.PRBSet); detransformed = nrTransformDeprecode(eqSym,MRB); slotGrid(sortedInd) = detransformed; % Undo scaling on PT-RS slotGrid(ptrsInd) = slotGrid(ptrsInd)/hPre6GPTRSPowerFactorDFTsOFDM(pdsch.Modulation); end function [eqSymGrid,cpe] = correctCPE(carrier,pdsch,pdschIndInfo,eqSymGrid) % Correct PDSCH common phase error ptrsInd = hpre6GPDSCHPTRSIndices(carrier,pdsch); if isempty(ptrsInd) % No CPE correction return end % Estimate the residual channel at the PT-RS locations ptrsSymbols = hpre6GPDSCHPTRS(carrier,pdsch); cpe = hpre6GChannelEstimate(carrier,eqSymGrid,ptrsInd,ptrsSymbols); % Sum estimates across subcarriers, receive antennas, and layers cpe = angle(sum(cpe,[1 3 4])); % Correct CPE in each OFDM symbol symLoc = pdschIndInfo.PTRSSymbolSet(1)+1:pdschIndInfo.PTRSSymbolSet(end)+1; eqSymGrid(:,symLoc,:) = eqSymGrid(:,symLoc,:).*exp(-1i*cpe(symLoc)); end function m = measureEVM(refSym,rxSym) % Returns a structure EVM containing: % EV - The error vector % RMS - Root Mean Square EVM (%) % Peak - Peak EVM (%) evm = comm.EVM; evm.AveragingDimensions = [1 2]; % Average across subcarriers and symbols evm.Normalization = "Average constellation power"; evm.AverageConstellationPower = 1; % All constellations have average unit power evm.MaximumEVMOutputPort = true; [rms,peak] = evm(refSym,rxSym); % Convert EVM percentages to decimal values m.EV = rxSym-refSym; % Error vector m.RMS = single(rms)/100; m.Peak = single(peak)/100; end function [evmSubcarrierRMS,evmSubcarrierPeak] = plotEVMPerSubcarrier(evGrid) % Plot EVM per subcarrier % Resource elements are NaN when they contain no PDSCH, so ignore for % measurement (omitmissing) evmSubcarrierRMS = sqrt(mean(abs(evGrid).^2,2,"omitmissing"))*100; evmSubcarrierPeak = sqrt(max(abs(evGrid).^2,[],2,"omitmissing"))*100; numSC = height(evmSubcarrierRMS); figure; plot(0:numSC-1,evmSubcarrierRMS,'.-'); hold on; plot(0:numSC-1,evmSubcarrierPeak,'.-'); legend(["RMS" "Peak"]); xlabel("Subcarrier Number"); ylabel("EVM (%)"); grid on title("PDSCH EVM per subcarrier") end function [evmSymbolRMS,evmSymbolPeak] = plotEVMPerSymbol(evGrid) % Plot EVM per OFDM symbol % Resource elements are NaN when they contain no PDSCH, so ignore for % measurement (omitmissing) evmSymbolRMS = sqrt(mean(abs(evGrid).^2,1,"omitmissing"))*100; evmSymbolPeak = sqrt(max(abs(evGrid).^2,[],1,"omitmissing"))*100; figure; plot(0:width(evmSymbolRMS)-1,evmSymbolRMS,'.-'); hold on; plot(0:width(evmSymbolRMS)-1,evmSymbolPeak,'.-'); legend(["RMS" "Peak"]); xlabel("Symbol Number"); ylabel("EVM (%)"); grid on title("PDSCH EVM per symbol") end