new tutorial: patch antenna phased array
Signed-off-by: Thorsten Liebig <Thorsten.Liebig@gmx.de>pull/10/head
parent
b357ab2b24
commit
2aa320cfcc
|
@ -0,0 +1,170 @@
|
|||
function [port nf2ff] = Patch_Antenna_Array(Sim_Path, postproc_only, show_structure, xpos, caps, resist, active )
|
||||
% [port nf2ff] = Patch_Antenna_Array(Sim_Path, postproc_only, show_structure, xpos, caps, resist, active )
|
||||
%
|
||||
% Script to setup the patch array as described in [1].
|
||||
% Run main script in Patch_Antenna_Phased_Array.m instead!
|
||||
%
|
||||
% Sim_Path: Simulation path
|
||||
% postproc_only: set to post process only 0/1
|
||||
% show_structure: show the strucuture in AppCSXCAD 0/1
|
||||
% xpos: the x-position for each antenna is defined
|
||||
% caps: the port capacity (will override active port)
|
||||
% resist: port resitance
|
||||
% active: switch port active
|
||||
%
|
||||
% References:
|
||||
% [1] Y. Yusuf and X. Gong, “A low-cost patch antenna phased array with
|
||||
% analog beam steering using mutual coupling and reactive loading,” IEEE
|
||||
% Antennas Wireless Propag. Lett., vol. 7, pp. 81–84, 2008.
|
||||
%
|
||||
% Tested with
|
||||
% - Matlab 2011a
|
||||
% - openEMS v0.0.31
|
||||
%
|
||||
% (C) 2013 Thorsten Liebig <thorsten.liebig@gmx.de>
|
||||
|
||||
% example
|
||||
% xpos = [-41 0 41];
|
||||
% caps = [0.2e-12 0 0.2e-12];
|
||||
% active = [0 1 0];
|
||||
% resist = [50 50 50];
|
||||
|
||||
%% setup the simulation
|
||||
physical_constants;
|
||||
unit = 1e-3; % all length in mm
|
||||
|
||||
% patch geometry setup
|
||||
patch.W = 35; % width
|
||||
patch.L = 28.3; % length
|
||||
patch.Ws = 3.8; % width of feeding stub
|
||||
patch.Gs = 1; % width of feeding gab
|
||||
patch.l = 6; % length of feeding stub
|
||||
patch.y0 = 10; % depth of feeding stub into into patch
|
||||
|
||||
% patch resonance frequency
|
||||
f0 = 3e9;
|
||||
|
||||
%substrate setup
|
||||
substrate.name = 'Ro3003';
|
||||
substrate.epsR = 3;
|
||||
substrate.kappa = 0.0013 * 2*pi*f0 * EPS0*substrate.epsR;
|
||||
substrate.thickness = 1.524;
|
||||
substrate.cells = 4;
|
||||
|
||||
substrate.width = patch.W + range(xpos) + 4*patch.l;
|
||||
substrate.length = 3*patch.l + patch.L;
|
||||
|
||||
% size of the simulation box
|
||||
AirSpacer = [50 50 30];
|
||||
|
||||
edge_res = [-1/3 2/3]*1;
|
||||
|
||||
%% setup FDTD parameter & excitation function
|
||||
fc = 2e9; % 20 dB corner frequency
|
||||
FDTD = InitFDTD( 'EndCriteria', 1e-4 );
|
||||
FDTD = SetGaussExcite( FDTD, f0, fc );
|
||||
BC = [1 1 1 1 1 1]*3;
|
||||
FDTD = SetBoundaryCond( FDTD, BC );
|
||||
|
||||
%% setup CSXCAD geometry & mesh
|
||||
CSX = InitCSX();
|
||||
|
||||
mesh.x = [];
|
||||
mesh.y = [];
|
||||
mesh.z = [];
|
||||
|
||||
%% create patch
|
||||
CSX = AddMetal( CSX, 'patch' ); % create a perfect electric conductor (PEC)
|
||||
|
||||
for port_nr=1:numel(xpos)
|
||||
start = [xpos(port_nr)-patch.W/2 patch.l substrate.thickness];
|
||||
stop = [xpos(port_nr)-patch.Ws/2-patch.Gs patch.l+patch.L substrate.thickness];
|
||||
CSX = AddBox(CSX,'patch',10, start, stop);
|
||||
mesh.x = [mesh.x xpos(port_nr)-patch.W/2-edge_res];
|
||||
|
||||
start = [xpos(port_nr)+patch.W/2 patch.l substrate.thickness];
|
||||
stop = [xpos(port_nr)+patch.Ws/2+patch.Gs patch.l+patch.L substrate.thickness];
|
||||
CSX = AddBox(CSX,'patch',10, start, stop);
|
||||
mesh.x = [mesh.x xpos(port_nr)+patch.W/2+edge_res];
|
||||
|
||||
mesh.y = [mesh.y patch.l-edge_res patch.l+patch.L+edge_res];
|
||||
|
||||
start = [xpos(port_nr)-patch.Ws/2-patch.Gs patch.l+patch.y0 substrate.thickness];
|
||||
stop = [xpos(port_nr)+patch.Ws/2+patch.Gs patch.l+patch.L substrate.thickness];
|
||||
CSX = AddBox(CSX,'patch',10, start, stop);
|
||||
|
||||
% feed line
|
||||
start = [xpos(port_nr)-patch.Ws/2 patch.l+patch.y0 substrate.thickness];
|
||||
stop = [xpos(port_nr)+patch.Ws/2 0 substrate.thickness];
|
||||
CSX = AddBox(CSX,'patch',10, start, stop);
|
||||
|
||||
mesh.x = [mesh.x xpos(port_nr)+linspace(-patch.Ws/2-patch.Gs,-patch.Ws/2,3) xpos(port_nr)+linspace(patch.Ws/2,patch.Ws/2+patch.Gs,3)];
|
||||
|
||||
start = [xpos(port_nr)-patch.Ws/2 0 0];
|
||||
stop = [xpos(port_nr)+patch.Ws/2 0 substrate.thickness];
|
||||
if (caps(port_nr)>0)
|
||||
CSX = AddLumpedElement(CSX, ['C_' num2str(port_nr)], 2, 'C', caps(port_nr));
|
||||
CSX = AddBox(CSX,['C_' num2str(port_nr)],10, start, stop);
|
||||
|
||||
[CSX port{port_nr}] = AddLumpedPort(CSX, 5 ,port_nr ,inf, start, stop, [0 0 1], 0);
|
||||
else
|
||||
% feed port
|
||||
[CSX port{port_nr}] = AddLumpedPort(CSX, 5 ,port_nr, resist(port_nr), start, stop, [0 0 1], active(port_nr));
|
||||
end
|
||||
end
|
||||
|
||||
%% create substrate
|
||||
CSX = AddMaterial( CSX, substrate.name );
|
||||
CSX = SetMaterialProperty( CSX, substrate.name, 'Epsilon', substrate.epsR, 'Kappa', substrate.kappa );
|
||||
start = [-substrate.width/2 0 0];
|
||||
stop = [ substrate.width/2 substrate.length substrate.thickness];
|
||||
CSX = AddBox( CSX, substrate.name, 0, start, stop );
|
||||
|
||||
mesh.x = [mesh.x start(1) stop(1)];
|
||||
mesh.y = [mesh.y start(2) stop(2)];
|
||||
|
||||
% add extra cells to discretize the substrate thickness
|
||||
mesh.z = [linspace(0,substrate.thickness,substrate.cells+1) mesh.z];
|
||||
|
||||
%% create ground (same size as substrate)
|
||||
CSX = AddMetal( CSX, 'gnd' ); % create a perfect electric conductor (PEC)
|
||||
start(3)=0;
|
||||
stop(3) =0;
|
||||
CSX = AddBox(CSX,'gnd',10,start,stop);
|
||||
|
||||
%% finalize the mesh
|
||||
% generate a smooth mesh with max. cell size: lambda_min / 20
|
||||
mesh = SmoothMesh(mesh, 2, 1.3);
|
||||
mesh.x = [mesh.x min(mesh.x)-AirSpacer(1) max(mesh.x)+AirSpacer(1)];
|
||||
mesh.y = [mesh.y min(mesh.y)-AirSpacer(2) max(mesh.y)+AirSpacer(2)];
|
||||
mesh.z = [mesh.z min(mesh.z)-AirSpacer(3) max(mesh.z)+2*AirSpacer(3)];
|
||||
|
||||
mesh = SmoothMesh(mesh, c0 / (f0+fc) / unit / 20, 1.3);
|
||||
|
||||
%% add a nf2ff calc box; size is 3 cells away from MUR boundary condition
|
||||
start = [mesh.x(4) mesh.y(4) mesh.z(4)];
|
||||
stop = [mesh.x(end-3) mesh.y(end-3) mesh.z(end-3)];
|
||||
[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop);
|
||||
|
||||
mesh = AddPML(mesh,(BC==3)*8);
|
||||
CSX = DefineRectGrid(CSX, unit, mesh);
|
||||
|
||||
%% prepare simulation folder
|
||||
Sim_CSX = 'patch_array.xml';
|
||||
|
||||
if (postproc_only==0)
|
||||
[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory
|
||||
[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder
|
||||
|
||||
%% write openEMS compatible xml-file
|
||||
WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX );
|
||||
|
||||
%% show the structure
|
||||
if (show_structure>0)
|
||||
CSXGeomPlot( [Sim_Path '/' Sim_CSX] );
|
||||
end
|
||||
|
||||
%% run openEMS
|
||||
RunOpenEMS( Sim_Path, Sim_CSX);
|
||||
end
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
%
|
||||
% Tutorials / Patch Antenna Phased Array
|
||||
%
|
||||
% Describtion at:
|
||||
%
|
||||
% Tested with
|
||||
% - Matlab 2011a
|
||||
% - openEMS v0.0.31
|
||||
%
|
||||
% References:
|
||||
% [1] Y. Yusuf and X. Gong, “A low-cost patch antenna phased array with
|
||||
% analog beam steering using mutual coupling and reactive loading,” IEEE
|
||||
% Antennas Wireless Propag. Lett., vol. 7, pp. 81–84, 2008.
|
||||
% [2] S. Otto, S. Held, A. Rennings, and K. Solbach,
|
||||
% "Array and multiport antenna farfield simulation using
|
||||
% EMPIRE, MATLAB and ADS," 39th European Microwave Conf. (EuMC 2009),
|
||||
% Sept. 29 – Oct. 1, Rome, Italy, pp. 1547-1550, 2009.
|
||||
% [3] K. Karlsson, J. Carlsson, I. Belov, G. Nilsson, and P.-S. Kildal,
|
||||
% “Optimization of antenna diversity gain by combining full-wave and
|
||||
% circuit simulations,” in Proc. Second European Conference on Antennas
|
||||
% and Propagation EuCAP 2007, 11–16 Nov. 2007, pp. 1–5.
|
||||
%
|
||||
% (C) 2013 Thorsten Liebig <thorsten.liebig@gmx.de>
|
||||
|
||||
|
||||
close all
|
||||
clear
|
||||
clc
|
||||
|
||||
% we need the "Cuircuit Toolbox"
|
||||
addpath('C:\CTB');
|
||||
% get the latest version from:
|
||||
% using git: https://github.com/thliebig/CTB
|
||||
% or zip: https://github.com/thliebig/CTB/archive/master.zip
|
||||
|
||||
% set this to 0 to NOT run a reference simulation with the given C2 and C3
|
||||
% for comparison
|
||||
do_reference_simulation = 1;
|
||||
|
||||
% set to 1 if you want to run AppCSXCAD to see the simulated structure
|
||||
show_structure = 1;
|
||||
|
||||
% set this to 1, to force openEMS to run again even if the data already exist
|
||||
force_rerun = 0;
|
||||
|
||||
% frequency range of interest
|
||||
f = linspace( 1e9, 5e9, 1601 );
|
||||
|
||||
% resonant frequency for far-field calculations
|
||||
f0 = 3e9;
|
||||
|
||||
% capacities for port 2 and 3 to shift the far-field pattern
|
||||
C2 = 0.2e-12;
|
||||
C3 = 0.2e-12;
|
||||
|
||||
Sim_Path_Root = ['tmp_' mfilename];
|
||||
|
||||
%% calculate the full S-parameter set for all 3 patch antennas running 3
|
||||
% individual openEMS simulations in which one antenna is active and the
|
||||
% other two a passive (50 Ohm load) respectively
|
||||
xpos = [0 -41 41]; % x-center position of the 3 antennas
|
||||
caps = [0 0 0];
|
||||
resist = [50 50 50];
|
||||
|
||||
spara = [];
|
||||
color_code = {'k-','r--','m-.'};
|
||||
|
||||
for n=1:3
|
||||
active = [0 0 0];
|
||||
active(n) = 1; % activate antenna n
|
||||
Sim_Path = [Sim_Path_Root '_' num2str(n)]; % create an individual path
|
||||
[port{n} nf2ff{n}] = Patch_Antenna_Array(Sim_Path, ((exist(Sim_Path,'dir')>0) && (force_rerun==0)), show_structure, xpos, caps, resist, active);
|
||||
port{n} = calcPort( port{n}, Sim_Path, f, 'RefImpedance', 50);
|
||||
nf2ff{n} = CalcNF2FF(nf2ff{n}, Sim_Path, f0, [-180:2:180]*pi/180, 0);
|
||||
|
||||
figure
|
||||
hold on
|
||||
grid on
|
||||
for p=1:3
|
||||
I(p,n) = interp1(f, port{n}{p}.if.tot,f0);
|
||||
P_in(p) = 0.5*interp1(f, port{n}{n}.uf.inc,f0)*conj(interp1(f, port{n}{n}.if.inc,f0));
|
||||
spara(p,n,:) = port{n}{p}.uf.ref./ port{n}{n}.uf.inc;
|
||||
plot(f, squeeze(20*log10(abs(spara(p,n,:)))),color_code{p},'Linewidth',2);
|
||||
end
|
||||
end
|
||||
|
||||
%% export sparameter to touchstone file
|
||||
write_touchstone('s',f,spara,[Sim_Path_Root '.s3p']);
|
||||
|
||||
% instructions for Qucs:
|
||||
% load the written touchstone file
|
||||
% attach C2 and C3 to port 2 and 3
|
||||
% attach a signal port to port 1
|
||||
% probe the currents going into port 1 to 3
|
||||
|
||||
% example currents for ports 1 to 3 for C2 = 0.2pF and C3=0.2pF
|
||||
I_qucs(1,1) = 0.00398-0.000465j;
|
||||
I_qucs(2,1) = 2.92e-5-0.000914j;
|
||||
I_qucs(3,1) = 2.92e-5-0.000914j;
|
||||
|
||||
disp(['I2/I1: Qucs: ' num2str(I_qucs(2)/I_qucs(1)) ' (defined manually)'])
|
||||
disp(['I3/I1: Qucs: ' num2str(I_qucs(3)/I_qucs(1)) ' (defined manually)'])
|
||||
|
||||
%% Calculate the currents of port 1 to 3 using Matlab [1]
|
||||
z = s2z(spara);
|
||||
|
||||
Z2 = 1/(1j*2*pi*f0*C2);
|
||||
Z3 = 1/(1j*2*pi*f0*C3);
|
||||
|
||||
z23(1,1) = interp1(f,squeeze(z(2,2,:)),f0) + Z2;
|
||||
z23(1,2) = interp1(f,squeeze(z(2,3,:)),f0);
|
||||
z23(2,1) = interp1(f,squeeze(z(3,2,:)),f0);
|
||||
z23(2,2) = interp1(f,squeeze(z(3,3,:)),f0) + Z3;
|
||||
|
||||
%set input/feeding current of port 1 to 1mA
|
||||
I_out(1,1) = 1e-3;
|
||||
% calc current for port 2 and 3
|
||||
I_out([2 3],1) = z23\[-interp1(f,squeeze(z(2,1,:)),f0);-interp1(f,squeeze(z(3,1,:)),f0)]*I_out(1);
|
||||
|
||||
disp(['I2/I1: Matlab: ' num2str(I_out(2)/I_out(1))])
|
||||
disp(['I3/I1: Matlab: ' num2str(I_out(3)/I_out(1))])
|
||||
|
||||
|
||||
%% do a referenc simulation for the given C2/C3 values
|
||||
if (do_reference_simulation)
|
||||
active = [1 0 0];
|
||||
caps = [0 C2 C3];
|
||||
resist = [50 inf inf];
|
||||
Sim_Path = [Sim_Path_Root '_C2=' num2str(C2*1e12) '_C3=' num2str(C3*1e12)];
|
||||
[port_ref nf2ff_ref] = Patch_Antenna_Array(Sim_Path, ((exist(Sim_Path,'dir')>0) && (force_rerun==0)), show_structure, xpos, caps, resist, active);
|
||||
port_ref = calcPort( port_ref, Sim_Path, f, 'RefImpedance', 50);
|
||||
nf2ff_ref = CalcNF2FF(nf2ff_ref, Sim_Path, f0, [-180:2:180]*pi/180, 0);
|
||||
|
||||
% extract currents from referenc simulation
|
||||
for p=1:3
|
||||
I_ref(p,1) = interp1(f, port_ref{p}.if.tot,f0);
|
||||
end
|
||||
|
||||
disp(['I2/I1: openEMS: ' num2str(I_ref(2)/I_ref(1))])
|
||||
disp(['I3/I1: openEMS: ' num2str(I_ref(3)/I_ref(1))])
|
||||
end
|
||||
|
||||
%% calculate and apply weighting cooefficients [3]
|
||||
% calculate
|
||||
coeff = I\I_out;
|
||||
|
||||
% apply
|
||||
E_ff_phi = 0*nf2ff{1}.E_phi{1};
|
||||
E_ff_theta = 0*nf2ff{1}.E_phi{1};
|
||||
for n=1:3
|
||||
E_ff_phi = E_ff_phi + coeff(n)*nf2ff{n}.E_phi{1};
|
||||
E_ff_theta = E_ff_theta + coeff(n)*nf2ff{n}.E_theta{1};
|
||||
end
|
||||
|
||||
%% plot far-field patterns
|
||||
figure
|
||||
polar([-180:2:180]'*pi/180,abs(E_ff_phi(:))/max(abs(E_ff_phi(:))));
|
||||
hold on
|
||||
if (do_reference_simulation)
|
||||
polar([-180:2:180]'*pi/180,abs(nf2ff_ref.E_norm{1}(:,1))/max(abs(nf2ff_ref.E_norm{1}(:,1))),'r--');
|
||||
end
|
||||
title('normalized far-field pattern','Interpreter', 'none')
|
||||
legend('calculated','reference')
|
||||
|
||||
|
Loading…
Reference in New Issue