From 2aa320cfcc137e745b6f6c99a21d4ab204d7e906 Mon Sep 17 00:00:00 2001 From: Thorsten Liebig Date: Mon, 26 Aug 2013 16:54:48 +0200 Subject: [PATCH] new tutorial: patch antenna phased array Signed-off-by: Thorsten Liebig --- matlab/Tutorials/Patch_Antenna_Array.m | 170 ++++++++++++++++++ matlab/Tutorials/Patch_Antenna_Phased_Array.m | 165 +++++++++++++++++ 2 files changed, 335 insertions(+) create mode 100644 matlab/Tutorials/Patch_Antenna_Array.m create mode 100644 matlab/Tutorials/Patch_Antenna_Phased_Array.m diff --git a/matlab/Tutorials/Patch_Antenna_Array.m b/matlab/Tutorials/Patch_Antenna_Array.m new file mode 100644 index 0000000..83381ce --- /dev/null +++ b/matlab/Tutorials/Patch_Antenna_Array.m @@ -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 + +% 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 + diff --git a/matlab/Tutorials/Patch_Antenna_Phased_Array.m b/matlab/Tutorials/Patch_Antenna_Phased_Array.m new file mode 100644 index 0000000..05d7961 --- /dev/null +++ b/matlab/Tutorials/Patch_Antenna_Phased_Array.m @@ -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 + + +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') + +