QA0008
ZIP with MATLAB scripts:
How to calculate MIMO channel figures of merit
-
Channel Capacity Loss ( CCL ),
-
Envelope Correlation Coefficient ( ECC )
-
Total Angle Reflection Coefficient ( TARC )
from scattering parameter files that have been inadvertently modified leaving behind multiple delimiter characters in each Sij.txt file. I also highlight limitations of obsolete command dlmread as well as for the one that is supposed to replace it readmatrix :
QA0008 note:
This QA addresses the problem of attempting to calculate the above figures of merit out of scattering S parameters in files s11.txt s12.txt s21.txt s22.txt that have different delimiters (TAB '\t' and space ' ') in same file.
Sometimes this happens when data manually merged by different operators. If other people processing such data wrongly assume that just one type of delimiter is used per file one can only realise when inspecting the source files.
Simplified calculations of
-
CCL: Channel Capacity Loss
-
ECC: Envelope Correlation Coefficient
-
TARC: Total Angle Reflection Coefficient
from S parameters in txt files with mixed delimiters
The initial MATLAB approach is often dlmread
QA1=dlmread('s11.txt')
QA1=dlmread('s11.txt')
Error using dlmread (line 147)
Mismatch between file and format character vector.
Trouble reading 'Numeric' field from file (row number 1, field number 1) ==> #\n
Error using dlmread (line 147)
Mismatch between file and format character vector.
Trouble reading 'Numeric' field from file (row number 1, field number 1) ==> #\n
QA1=dlmrec
On checking the contents of the source files:
dbtype s11.txt 1:10
1 #
2 #"Frequency / GHz" "S1,1 [Re]" "S1,1 [Im]" "Ref.Imp. [Re]" "Ref.Imp. [Im]"
3 #-------------------------------------------------------------------------
4 2.0000000000000 -0.43436479568481 -0.27583473920822 49.499982587419 0.00000000000000
5 2.0130000114441 -0.43212774395943 -0.25979641079903 49.499982587419 0.00000000000000
6 2.0260000228882 -0.42928242683411 -0.24402607977390 49.499982587419 0.00000000000000
7 2.0390000343323 -0.42584636807442 -0.22855253517628 49.499982587419 0.00000000000000
8 2.0520000457764 -0.42183887958527 -0.21340312063694 49.499982587419 0.00000000000000
9 2.0650000572205 -0.41728088259697 -0.19860377907753 49.499982587419 0.00000000000000
10 2.0780000686646 -0.41219443082809 -0.18417946994305 49.499982587419 0.00000000000000
The yellow space between 1st and 2nd column is not space but TAB. The space between 2nd 3rd, 3rd 4th, and so on are spaces.
dbtype s12.txt 1:10
1 #
2 #"Frequency / GHz" "S1,2 [Re]" "S1,2 [Im]"
3 #-----------------------------------------
4 2.0000000000000 -0.0087176365777850 0.19573307037354
5 2.0130000114441 -0.00025198308867402 0.19772811233997
6 2.0260000228882 0.0083699077367783 0.19926650822163
7 2.0390000343323 0.017119051888585 0.20033770799637
8 2.0520000457764 0.025965791195631 0.20093321800232
9 2.0650000572205 0.034879870712757 0.20104672014713
10 2.0780000686646 0.043830763548613 0.20067396759987
Another discrepancy is the different amount of columns. If all S parameter files have same amount of columns, separated by same type of delimiter, processing them is easier.
Since Mathworks recommends replacing dlmread with readmatrix next logic step is for instance:
d_S11=readmatrix('s11.txt');
d_S12=readmatrix('s12.txt');
d_S21=readmatrix('s21.txt');
d_S22=readmatrix('s22.txt');
size(d_S11)
size(d_S12)
size(d_S21)
size(d_S22)
= 1001 5
= 1001 3
= 994 3
= 1001 5
This approach has 2 problems; firstly NaN values show up despite dbtype just showed above that there isn’t any within the initial 10 lines of any of the source files.
d_S12(1,:)
d_S11(1,:)
d_S21(1,:)
d_S22(1,:)
= Columns 1 through 2
2.000000000000000 -0.008717636577785
Column 3
0.195733070373540
= Columns 1 through 2
2.000000000000000 -0.434364795684810
Columns 3 through 4
-0.275834739208220 49.499982587418998
Column 5
0
= Columns 1 through 2
2.091000080108600 NaN
Column 3
NaN
= Columns 1 through 2
2.000000000000000 -0.434202671051030
Columns 3 through 4
-0.277085989713670 49.499805239380997
Column 5
0
With Notepad, doing ctrl+F: NaN in all source files, there is no such string. Then how many NaN generated from readmatrix reading anyway?
nnz(isnan(d_S11))
nnz(isnan(d_S12))
nnz(isnan(d_S21))
nnz(isnan(d_S22))
= 0
= 0
= 12
= 0
And secondly, the size checks done above show that while files s11.txt s12.txt and s22.txt have 1001 lines of data (the 1st 3 lines of all files are preceded by Python’s comment character #, the equivalent to % in MATLAB) s21.txt only seems to have 994. However, on checking directly with Notepad how many lines Notepad says all source files have, here are the readings:
[fG_S11,S11_]=read_Sf('s11.txt');
[fG_S12,S12_]=read_Sf('s12.txt');
[fG_S21,S21_]=read_Sf('s21.txt');
[fG_S22,S22_]=read_Sf('s22.txt');
Is there any NaN now?
nnz(isnan(S11_))
nnz(isnan(S12_))
nnz(isnan(S21_))
nnz(isnan(S22_))
size(S11_)
size(S12_)
size(S21_)
size(S22_)
Is there any numerical data rows columns discrepancy?
sz1=min([size(S11_,1) size(S12_,1) size(S21_,1) size(S22_,1)])
sz2=min([size(fG_S11,1) size(fG_S12,1) size(fG_S21,1) size(fG_S22,1)])
Generating the frequency vector:
Although it’s not strictly needed to complete the sought calculations in this question, it’s good practice to put all S parameters in a single variable. On the right, how to generate S(f) without for loops:
sz1 = 1001
sz2 = 1001
% f=fG_S11*1e9; % fG_Sij are equal length, GHz to Hz
f=fG_S11;
S11=S11_(:,1)+1j*S11_(:,2);
S12=S12_(:,1)+1j*S12_(:,2);
S21=S21_(:,1)+1j*S21_(:,2);
S22=S22_(:,1)+1j*S22_(:,2);
S=[reshape(S11,1,1,sz1) reshape(S12,1,1,sz1) ; ...
reshape(S21,1,1,sz1) reshape(S22,1,1,sz1)];
Here is not the case, but it may also happen that even with the same amount of points, frequencies do not coincide on few points, then interpolation would be required.
Checking a couple of lines, 1st and last, that reshape used correctly
isequal([ S11(1) S12(1); S21(1) S22(1)], S(:,:,1))
isequal([ S11(end) S12(end); S21(end) S22(end)], S(:,:,end))
ans = logical
1
ans = logical
1
Now all clear to calculate CCL ECC and TARC
CCL: Channel Capacity Loss
Psi_r=[reshape((1-S11.*conj(S11)-S21.*conj(S21)),1,1,sz1) ...
reshape(conj(S11).*S12+conj(S21).*S12,1,1,sz1 ) ; ...
reshape(conj(S22).*S21+conj(S12).*S21,1,1,sz1) ...
reshape((1-S22.*conj(S22)-S12.*conj(S12)),1,1,sz1)];
CCL=zeros(1,numel(S11));
for k=1:1:1
C_loss(k)=log2(abs(det(Psi_r(:,:,k))));
end
ECC: Envelope Correlation Coefficient
ECC=(conj(S11).*S12+conj(S21).*S22).*conj(conj(S11).*S12+conj(S21).*S22)./...
((1-S11.*conj(S11)-S21.*conj(S21)).*(1-S22.*conj(S22)-S12.*conj(S12)));
MEG1=.5*(1-S11.*conj(S11)-S12.*conj(S12));
MEG2=.5*(1-S12.*conj(S12)-S22.*conj(S22));
etha1=.7
etha2=.7
etha1 etha2 : antennas efficiencies, maybe optimistic antenna efficiency value.
peak efficiency
etha_max=(etha1*etha2*(1-(ECC).^2)).^.5;
TARC: Total Angle Reflection Coefficient
gamma_TARC has to be calculated on each frequency. For frequency f point gamma_TARC has numel(theta) points
theta=pi/180*[30 60 90 120 150 180] % angle, grads to rads
gamma_TARC=zeros(numel(S11),numel(theta));
for k=1:1:numel(S11)
gamma_TARC(k,:)= ...
2^(-.5)*((abs(S11(k)+S12(k)*exp(1j*theta))).^2+ ...
(abs(S21(k)+S22(k)*exp(1j*theta))).^2).^.5;
end
gamma_TARC(1,:)=0;
CCL graph
figure(1);
plot(f,CCL);grid on
xlabel('f: frequency[GHz]');
ylabel('CCL : Channel Capacity Loss')
title('CCL(f)')
MEG1 MEG2 graphs
figure(2);
plot(f,MEG1);
hold on;
plot(f,MEG2); grid on
xlabel('f: frequency[GHz]');
ylabel('MEG : Mean Effective Gain') ;
title('MEG(f)')
legend('port1','port2')
ECC graph
figure(3);
plot(f,ECC); grid on
xlabel('f : frequency[GHz]');
ylabel('ECC : Envelope Correlation Coefficient');
title('ECC(f)')