IEEE.org     |     IEEE Xplore Digital Library     |     IEEE Standards     |     IEEE Spectrum     |     More Sites

Commit 044ed67d authored by Martin Hudlicka's avatar Martin Hudlicka
Browse files

OFDM Baseline EVM algorithm

parent 5fd489a7
function params = F_Basic_Communication_Parameters()
% This function defines the basic communication parameters for the P1765
% Baseline EVM Algorithm code for OFDM
global structGlobal
%-------------------------------------------
% Chose impairments applied to the signal
%-------------------------------------------
% Saleh type AM/AM and AM/PM non-linearity
params.nonlin = 0; % 0 or 1
% Echo with amplitude and delay
params.echo = 1; % 0 or 1
% Noise addition
params.noise = 0; % 0 or 1
% Tx RF filter (use RF filter when addding noise or non-linearity)
params.Txfilter = 0; % 0 or 1
%-------------------------------------
% OFDM modulation parameters
%-------------------------------------
% QAM depth: constellation of NxN symbols, N=8 for 64QAM
params.N = 8; % 8;
%
% number of sub-carriers Nc = 601, can be reduced to 51 for curves clarity
params.Nc = 51; % 51; % 601; %
%
% Number of OFDM Symbols in simulated frame
params.NS = 100; % 100;
%
% length of circular prefix added to symbol in fraction of symbol (< 1)
params.RATIOprefix = 0.14;%0.14;
%
% length of guard time added to symbol in fraction of symbol (< 1)
params.RATIOguard = 0.15;%0.15;
%
% oversampling on each side (can be reduced to 1 for curves clarity)
params.OS_side = 2; % 2;
%-------------------------------------
% derived parameters
%-------------------------------------
% average power of symbols in constellation
params.Pc = (params.N-1) * (params.N+1) / 6;
% average amplitude of symbols in constellation
params.Ac = sqrt(params.Pc);
%
% number of oversampling bins on each side of OFDM signal spectrum
params.N_side = params.OS_side * params.Nc;
%
% OFDM Oversampling ratio
params.OS_OFDM = 2 * params.OS_side + 1;
%
% number of samples on each oversampled OFDM symbol without prefix
params.N_OFDM = params.OS_OFDM * params.Nc;
params.lx = params.N_OFDM;
%
% length of prefix in samples
params.Npref = max(0,floor(params.RATIOprefix*params.lx));
% length of guard time in samples
params.Nguard = max(0,floor(params.RATIOguard*params.lx));
% shape of fade-in and fade-out for guard time
if params.Nguard > 0
params.Wguard = (1-cos(pi * (1:params.Nguard) / (params.Nguard+1) )) / 2;
end
%
% length of prefix plus guard time
params.Nprefguard = params.Nguard + params.Npref;
% length of one OFDM symbol with prefix and guard time
params.lxprefguard = params.lx + params.Nprefguard;
% total length of simulated frame
params.lxF = params.NS * params.lxprefguard;
% normalization of oversampled spectra
params.normalize = params.lxF / ...
sqrt(params.Nc*params.NS*(1+params.RATIOprefix+params.RATIOguard));
%------------------------------------------------------
% frequency and time units, e.g. nanoseconds and GHz
%------------------------------------------------------
% duration of OFDM symbol without prefix and guard time
params.TS = 1000;
% frequency difference between carriers
params.DF = 1 / params.TS;
% total frequency bandwidth = oversampling frequency
params.BW = params.lx * params.DF;
% time sampling step
params.dt = 1 / params.BW;
% duration of simulated frame
params.TF = params.lxF * params.dt;
% frequency sampling step
params.df = 1/params.TF;
if structGlobal.printdebug > 0
fprintf('QAM modulation: N = %d , Constellation of %d symbols \n', params.N, params.N*params.N);
fprintf('Average power of constellation symbols: Pc = %f\n', params.Pc);
fprintf('Number of OFDM cariers: Nc = %d\n', params.Nc);
fprintf('Oversampling coefficient on each side: OS_side = %d\n', params.OS_side);
fprintf('OFDM oversampling coefficient: OS_OFDM = %d\n', params.OS_OFDM);
fprintf('Number of samples for 1 OFDM symbol: N_OFDM = %d\n', params.N_OFDM);
fprintf('Number of samples in prefix: Npref = %d\n ', params.Npref);
fprintf('Number of samples in guard time: Nguard = %d\n ', params.Nguard);
fprintf('Number of samples with prefix and guard: lxprefguard = %d\n', params.lxprefguard);
fprintf('Number of OFDM symbols: NS = %d\n', params.NS);
fprintf('Number of samples for frame: lxF = %d\n', params.lxF);
fprintf('\n');
end
end
\ No newline at end of file
function [G_OPT,EVM] = F_EVM_Computation_on_Channels(params, Symb, Sideal)
% In this subroutine, the EVM and optimum gain Gsymb are computed separatly
% on the symbols of each frequency channels then they are averaged.
% For more details, refer to Section 9.1.2.
%
% This is equivalent to an equalization of the gains on channels
%
% Inputs:
% Symb or r(nT): Recovered OFDM symbols
% Sideal: Ideal OFDM symbols from ideal signal
% params: structure containing the basic communication paramters
%
% Outputs:
% G_OPT: Optimum gain on symbols for EVM computation
% EVM or Baseline signal EVM: Baseline rms EVM in percent
global structGlobal
%% %-----------------------------------------------------------
% Reshaping of ideal and received symbols and
% transposition giving Nc lines of NS symbols
%-----------------------------------------------------------
Symb = reshape(Symb, params.NS, params.Nc).';
Sideal = reshape(Sideal, params.NS, params.Nc).';
%% %-------------------------------------------------------------------------
% computation of optimum gain and EVM on symbols of each frequency carrier
%-------------------------------------------------------------------------
G_OPT = 0;
EVM2 = 0;
Gnc = zeros(1,params.Nc);
EVM2nc = zeros(1,params.Nc);
% loop on all channels (lines) and summation on columns
for nc = 1:params.Nc
% Auto and cross-correlations at time 0 for normalization of symbols
CC = dot(Symb(nc, :), Sideal(nc, :)); % conjugate of Symb(nc, :) * Sideal(nc, :)';
ACideal = dot(Sideal(nc, :) , Sideal(nc, :));
AC = dot(Symb(nc, :) , Symb(nc, :));
% normalization of symbols
Gnc(nc) = CC / AC;
% computation of EVM on symbols
cos2 = real(CC*conj(CC) / AC / ACideal);
EVM2nc(nc) = 1/cos2-1; % = square of tangent of angle
EVMnc = sqrt(EVM2nc(nc));
if (structGlobal.printdebug >2 && nc < 5 ) || structGlobal.printdebug > 3
fprintf('Optimum gain on symbols of channel %d for EVM computation\n', nc);
fprintf(' amplitude = %8.6f phase = %8.2f �\n',...
abs(Gnc(nc)), angle(Gnc(nc))*180/pi );
fprintf('Angle between measured symbols of channel %d and reference symbols\n', nc);
fprintf(' cos2 = %8.6f angle = %10.6f �\n',cos2,acosd(sqrt(cos2)));
fprintf('EVM measured on symbols of channel %d\n', nc);
fprintf(' EVM = %8.4f %% or %6.2f dB\n',EVMnc * 100, 20*log10(EVMnc));
end
EVM2 = EVM2 + EVM2nc(nc);
G_OPT = G_OPT + Gnc(nc);
end % of loop Nc
EVM = sqrt(EVM2 / params.Nc);
G_OPT = G_OPT / params.Nc;
if structGlobal.printdebug > 2
fprintf('\n');
end
fprintf('Average of optimum gain measured on symbols of each frequency channel\n');
fprintf(' amplitude = %8.6f phase = %8.2f �\n',...
abs(G_OPT), angle(G_OPT)*180/pi );
fprintf('Average of EVM measured separatly on symbols of each frequency channel\n');
fprintf(' EVM with equalization = %8.4f %% or %6.2f dB\n',EVM * 100, 20*log10(EVM));
%% Plot constellation for all symbols with average gain compensation
Symb = Symb * G_OPT * params.Ac;
Sideal = Sideal * params.Ac;
ColorV = 'rbgkcym';
if structGlobal.tracedebug >0
figure1 = figure(26); clf; grid on; box on;
hold on; axis('square');
axis([-params.N/2 params.N/2 -params.N/2 params.N/2]);
set(gca,'XTick',(-params.N/2:1:params.N/2));
set(gca,'YTick',(-params.N/2:1:params.N/2));
title({'Ideal and measured symbols constellations','(one color per frequency channel)'});
xlabel('Real part');
ylabel('Imaginary part');
plot(real(Sideal(1:params.Nc*params.NS)),imag(Sideal(1:params.Nc*params.NS)),'k*');
plot(params.Ac*cos(pi*(0:360)/180),params.Ac*sin(pi*(0:360)/180),'-b');
for nc = 1:params.Nc
color=ColorV(1+mod(nc,length(ColorV)));
plot(real(Symb(nc, :)),imag(Symb(nc, :)),[color,'o'])
end
legend({'Ideal symbols', 'Average level', 'Measured symbols'}, 'Location', 'eastoutside', 'Orientation', 'vertical');
% Saving figure as graphic file in current directory (plot must still be present in MATLAB plot window)
stri_fig = fullfile(structGlobal.evm_results_folder,strcat(structGlobal.filename,'_with_average_gain.jpg')); % Change file naming to save as needed
set(figure1,'PaperPositionMode','auto');
print(figure1,stri_fig,'-djpeg','-r0');
end
%% Plot constellation for all symbols without echo
if structGlobal.tracedebug >0
figure1 = figure(27); clf; grid on; box on;
hold on; axis('square');
axis([-params.N/2 params.N/2 -params.N/2 params.N/2]);
set(gca,'XTick',(-params.N/2:1:params.N/2));
set(gca,'YTick',(-params.N/2:1:params.N/2));
title({'Ideal and measured symbols contellations','after echo equalization'});
xlabel('Real part');
ylabel('Imaginary part');
plot(real(Sideal(1:params.Nc*params.NS)),imag(Sideal(1:params.Nc*params.NS)),'k*');
plot(params.Ac*cos(pi*(0:360)/180),params.Ac*sin(pi*(0:360)/180),'-b');
for nc = 1:params.Nc
Symb(nc, :) = Symb(nc, :) * G_OPT / Gnc(nc);
color=ColorV(1+mod(nc,length(ColorV)));
plot(real(Symb(nc, :)),imag(Symb(nc, :)),[color,'o'])
end
legend({'Ideal symbols', 'Average level', 'Measured symbols'}, 'Location', 'eastoutside', 'Orientation', 'vertical');
% Saving figure as graphic file in current directory (plot must still be present in MATLAB plot window)
stri_fig = fullfile(structGlobal.evm_results_folder,strcat(structGlobal.filename,'_with_equalization.jpg')); % Change file naming to save as needed
set(figure1,'PaperPositionMode','auto');
print(figure1,stri_fig,'-djpeg','-r0');
end
%% Plot optimum gain and EVM versus frequency channel
if structGlobal.tracedebug >1
figure(28); clf; grid on; hold on;
title('Relative gain and phase on measured symbols on each frequency channel');
xlabel('Frequency channel number');
ylabel('Relative gain amplitude (dB) or relative gain phase (�)');
Gdb = 20*log10(abs(Gnc/G_OPT));
Gfi = angle(Gnc/G_OPT) * 180 / pi;
plot(1:params.Nc, Gdb,'k-');
plot(1:params.Nc, Gfi,'r-');
legend({'Relative gain amplitude', 'Relative gain phase'}, 'Location', 'southeast');
figure(29); clf; grid on; hold on;
title('EVM on each frequency channel and average EVM');
xlabel('Frequency channel number');
ylabel('EVM (%)');
plot(1:params.Nc, sqrt(EVM2nc)*100,'k-');
plot([1 params.Nc], [EVM*100 EVM*100 ],'r-');
legend({'EVM on each channel', 'Average EVM'}, 'Location', 'southeast');
end
end
function [G_OPT,EVM] = F_EVM_Computation_on_Symbols(params,Symb,Sideal)
% This function performs EVM computation on symbols according to Section
% 5.2.1.5 of the IEEE P1765 Baseline EVM Algorithm for OFDM:
% Determine the EVM of the User-Lab and Reference-Lab Measured Waveforms
%
% Inputs:
% Symb or r(nT): Recovered OFDM symbols
% Sideal: Ideal OFDM symbols from ideal signal
% params: structure containing the basic communication paramters
%
% Outputs:
% G_OPT: Optimum gain on symbols for EVM computation
% EVM or Baseline signal EVM: Baseline rms EVM in percent
global structGlobal
%------------------------------------
% computation of EVM on all symbols
%------------------------------------
% Auto and cross-correlations at time 0 for normalization of symbols
CC = dot(Symb, Sideal); % conjugate of Symb * Sideal';
ACideal = dot(Sideal, Sideal); % Sideal * Sideal';
AC = dot(Symb, Symb); % Symb * Symb';
% normalization of symbols
G_OPT = CC / AC ; % Gsymb = CC / ACideal;
fprintf('Optimum gain on symbols for EVM computation\n');
fprintf(' amplitude = %8.6f phase = %8.2f �\n',...
abs(G_OPT), angle(G_OPT) * 180 / pi );
% EVM Calculation same as the single-carrier case Section 5.1.2.5
EV = G_OPT*Symb - Sideal;
EVM = sqrt(dot(EV,EV)/dot(Sideal,Sideal));
% % The EVM computation in Lines 42 to 47 follows the same Math as in the
% % single-carrier case. It computes the same values but with less
% % computation and errors. Provided here for reference.
% % Computation of EVM on symbols
% cos2 = real(CC*conj(CC) / AC / ACideal);
% if structGlobal.printdebug
% fprintf('Angle between measured symbols and reference symbols\n');
% fprintf(' cos2 = %8.6f angle = %10.6f �\n',cos2,acosd(sqrt(cos2)));
% end
% EVM = sqrt(1/cos2-1); % = tangent of angle
fprintf('EVM measured on all symbols\n');
fprintf(' EVM = %8.4f %% or %6.2f dB\n',EVM * 100, 20*log10(EVM));
% Plot constellation for all symbols
Symb = Symb * G_OPT * params.Ac;
Sideal = Sideal * params.Ac;
if structGlobal.tracedebug >0
figure1 = figure(25); clf; grid on; box on;
hold on; axis('square');
axis([-params.N/2 params.N/2 -params.N/2 params.N/2]);
set(gca,'XTick',(-params.N/2:1:params.N/2));
set(gca,'YTick',(-params.N/2:1:params.N/2));
title('Ideal and measured symbols constellations');
plot(real(Symb(1:params.Nc*params.NS)),imag(Symb(1:params.Nc*params.NS)),'ro')
plot(real(Sideal(1:params.Nc*params.NS)),imag(Sideal(1:params.Nc*params.NS)),'k*');
plot(params.Ac*cos(pi*(0:360)/180),params.Ac*sin(pi*(0:360)/180),'-b');
% Saving figure as graphic file in current directory (plot must still be present in MATLAB plot window)
stri_fig = fullfile(structGlobal.evm_results_folder,strcat(structGlobal.filename,'_baseline.jpg')); % Change file naming to save as needed
set(figure1,'PaperPositionMode','auto');
print(figure1,stri_fig,'-djpeg','-r0');
end
end
\ No newline at end of file
function [NPR_EVM,NMSE] = F_NPR_NMSE_Oversampled_Signal(params, fxF, fxFideal)
global structGlobal
%------------------------------------------------------------
% computation of NPR and NMSE on oversampled signals spectra
%------------------------------------------------------------
%-------------------------------------------------------
% low pass filter on oversampled signal spectrum
%-------------------------------------------------------
if structGlobal.printdebug >1
fprintf('Low-pass filter on oversampled received signal\n');
end
filter = zeros(1, params.lxF);
% filter guard band in carrier bandwidth on each side
% optimum may vary with type and importance of impairments and value of Nc
% it can be 0 (less noise but more distortion)
filter_side = 5;
% filter bandwidth in number of df steps
bandwidth = min(params.lxF, floor((params.Nc + 2*filter_side)* params.DF/params.df));
if structGlobal.printdebug > 1
fprintf(' Filter relative bandwidth = %9.2f %%\n', 100*(params.Nc+2*filter_side)/params.Nc);
end
% filter stopband in number of df steps
stopband = floor((params.lxF -bandwidth)/2);
filter(stopband+1:params.lxF-stopband+1)= ones(1, params.lxF-2*stopband+1);
fxF = fxF .* filter;
Pavg=sum(abs(fxF).^2) / (params.lxF-2*stopband+1);
if structGlobal.printdebug >1
fprintf(' Average power in bandwidth after filter = %6.2f dB\n', 10*log10(Pavg));
end
% filtered signal
xF = F_fft_inverse(params, fxF);
%
if structGlobal.tracedebug >1
figure(14)
clf
grid on
title('Power spectrum of filtered received signal frame in dB');
hold on
freq = params.df*linspace(-floor(params.lxF/2), params.lxF -1 -floor(params.lxF/2), params.lxF);
plot(freq, max(-200,20*log10(abs(fxF))), 'r');
% smoothing on NS frequency samples
fx2int=zeros(1,params.lxprefguard);
for i=1:params.lxprefguard
fx2int(i)=sum(abs(fxF(params.NS*(i-1)+1:params.NS*i)).^2)/params.NS;
end
freq = params.df*(-floor(params.lxF/2)+floor(params.NS/2): params.NS : params.lxF-floor(params.lxF/2)+floor(params.NS/2)-1);
plot(freq, max(-200,10*log10(abs(fx2int))), 'k');
end
% New in version 3 and 4
% filter on ideal spectrum
fxFideal = fxFideal .* filter;
Pavg=sum(abs(fxFideal).^2) / (params.lxF-2*stopband+1);
if structGlobal.printdebug
fprintf(' Average power of ideal signal after low-pass filter = %6.2f dB\n', 10*log10(Pavg));
end
% filtered ideal signal
xFideal = F_fft_inverse(params, fxFideal);
%
if structGlobal.tracedebug >1
figure(15)
clf
grid on
title('Power spectrum of filtered ideal signal frame in dB');
hold on
freq = params.df*linspace(-floor(params.lxF/2),params.lxF -1-floor(params.lxF/2),params.lxF);
plot(freq, max(-200,20*log10(abs(fxFideal))), 'r');
% smoothing on NS frequency samples
fx2int=zeros(1,params.lxprefguard);
for i=1:params.lxprefguard
fx2int(i)=sum(abs(fxFideal(params.NS*(i-1)+1:params.NS*i)).^2)/params.NS;
end
freq = params.df*(-floor(params.lxF/2)+floor(params.NS/2): params.NS : params.lxF-floor(params.lxF/2)+floor(params.NS/2)-1);
plot(freq, max(-200,10*log10(abs(fx2int))), 'k');
end
%---------------------------------------------------------------------
% Auto and cross-correlations at time 0 for normalization of signals
%---------------------------------------------------------------------
CC = xF * xFideal';
ACideal = xFideal * xFideal';
AC = xF * xF';
% computation of optimum complex gain and error on oversampled signal
% these values are not correct if noise and IMD are not filtered
G0 = CC / ACideal;
fprintf('Optimum gain on oversampled signal with low-pass filter\n');
fprintf(' amplitude = %8.6f phase = %8.2f �\n',abs(G0), angle(G0)*180/pi );
%---------------------------------------------------------------
% computation of NPR or RF spectrum EVM on oversampled waveform
%---------------------------------------------------------------
cos2 = real(CC*conj(CC) / AC / ACideal);
if structGlobal.printdebug > 1
fprintf('Angle between measured signal and reference signal\n');
fprintf(' cos2 = %8.6f angle = %10.6f �\n',cos2,acos(sqrt(cos2))*180/pi );
end
NPR_EVM = sqrt(1/cos2-1); % = tangent of angle
fprintf('RF spectrum EVM (= in-band average NPR) with low-pass filter\n');
fprintf(' RF spectrum EVM or NPR = %8.4f %% or %6.2f dB\n',NPR_EVM * 100, -20*log10(NPR_EVM));
chord = 2 * sin(0.5 * acos(sqrt(cos2))); % twice sine of half angle
NMSE = chord^2;
fprintf(' RF spectrum NMSE = %6.2f dB\n', 10*log10(NMSE));
end
\ No newline at end of file
function Symb = F_OFDM_Symbols_Recovery(params,xF)
% This function performs the OFDM symbols recovery according to Section
% 5.2.1.4 of the IEEE P1765 Baseline EVM Algorithm for OFDM.
%
% Inputs:
% xF: Time domain signal corrected for optimal time delay and
% after normalization of signal average power
% params: structure containing the basic communication paramters
%
% Output:
% Symb or r(nT): Recovered OFDM symbols
%
% When applied to ideal signal, this function recovers ideal symbols.
global structGlobal
%--------------------------------------------------
% OFDM symbols recovery
%--------------------------------------------------
% measured symbols table, one line for each OFDM symbol
Symb = zeros(params.NS, params.Nc);
for S=1:params.NS
% removal of cyclic prefix and guard from one OFDM symbol
x = xF((S-1)*params.lxprefguard+1+params.Nprefguard:S*params.lxprefguard);
% OFDM symbol x duration is now TS = 1/DF
if structGlobal.tracedebug >4 && S<5
figure(40+S); clf; hold on; grid on
title('Real and imaginary parts and amplitude of time aligned OFDM symbol');
time = params.dt*((S-1)*params.lxprefguard+params.Nprefguard:S*params.lxprefguard-1); % (0:params.lx-1);
plot(time, real(x), 'g');
plot(time, imag(x), 'r');
plot(time, abs(x), 'k');
end
% fft(x) integrates the signal on a duration of TS = 1/DF
% and is the matched filter
fx = fftshift(fft(x))*sqrt(params.Nc)/params.lx;
% extraction of symbols from carriers of one OFDM symbol
Symb(S,1:params.Nc) = fx(params.N_side+1:params.N_side+params.Nc);
end
% reshaping of symbol matrices as vectors
Symb = reshape(Symb, 1, params.NS*params.Nc);
end
\ No newline at end of file
function [delay,Gsymb,EVM] = F_P1765_OFDM_Baseline_EVM_Algorithm(params,xFideal,xF)
% This function applies the four steps of the P1765 OFDM Baseline EVM
% Algorithm, namely, coarse and fine time alignment, OFDM symbol
% recovery and EVM calculation on symbols.
% Refer to Section 5.2 of the IEEE P1765 document.
global structGlobal
%% computation of spectrum of ideal signal
fxFideal = F_fft_direct(params, xFideal);
%% computation of spectrum of received signal
fxF = F_fft_direct(params, xF);
%% Time alignment (Step1:Coarse, Step2:Fine, Section 5.2.1.2)
[delay,fxF] = F_calculateOptimal(params,fxFideal,fxF);
%% Time aligned measured signal computed from its spectrum
xF = F_fft_inverse(params, fxF);
if structGlobal.tracedebug >3
figure(22); clf; hold on; grid on
title('Real and imaginary parts and amplitude of time aligned signal frame');
time = params.dt*(0:params.lxF-1);
plot(time, real(xF), 'g');
plot(time, imag(xF), 'r');
plot(time, abs(xF), 'k');
end
%% OFDM Symbols Recovery (Step3, Section 5.2.1.4)
Symb = F_OFDM_Symbols_Recovery(params,xF);
%% Ideal OFDM symbols Recovery, identical to step 3 but from ideal signal
Sideal = F_OFDM_Symbols_Recovery(params,xFideal);
%% EVM Computation on symbols (Step4, Section 5.2.1.5)
[Gsymb,EVM] = F_EVM_Computation_on_Symbols(params, Symb, Sideal);
end
\ No newline at end of file
function [GSymb,EVM_with_equalization] = F_P1765_OFDM_Baseline_EVM_Algorithm_with_equalization(params,xFideal,xF)
%% computation of spectrum of ideal signal
fxFideal = F_fft_direct(params, xFideal);
%% computation of spectrum of received signal
fxF = F_fft_direct(params, xF);
%% Time alignment (Step1:Coarse, Step2:Fine)
[delay,fxF] = F_calculateOptimal(params,fxFideal,fxF);
%% Time aligned measured signal computed from its spectrum
xF = F_fft_inverse(params, fxF);
%% OFDM Symbols Recovery (Step3)
Symb = F_OFDM_Symbols_Recovery(params,xF);
%% Ideal OFDM symbols Recovery, identical to step 3 but from ideal signal
Sideal = F_OFDM_Symbols_Recovery(params,xFideal);