example 1.1
ZIP with MATLAB scripts and note:
example 1.1 notes:
All necessary scripts, working and ready to run are available in the Dropbox link top right corner of this page.
These notes are also available in Adobe format from the Adobe icon just below the Dropbox link.
For each example and exercise there are 2 support functions load_question.m and load_results_if_available.m that load each question that is not shown in the answer notes. One could argue what's the point to read an answer if one doesn't know the question. However why did go for the answer before reading the question I'd reply.
Some scripts consume some time in calculations so once the solution has been stored in a .mat file in same folder the support functions offer option to retrieve previously solution.
c0=299795856; % [m/s]
etha0=120*pi; % [ohm]
f0=5e9
% probably out of direct measurement, wavelength is provided
lambda=.03
kz=2*pi/lambda % propagation constant
vp=lambda*f0 % phase velocity
er=(c0/vp)^2 % relative permittivity
etha=etha0/er^.5 % wave impedance
f0 =
5.000000000000000e+09
lambda =
0.030000000000000
kz =
2.094395102393196e+02
vp =
150000000
er =
3.994558012212122
etha =
1.886239140163974e+02
One could argue that while solving [POZAR] exercises and examples a hand held calculator suffices, as regretfully some Universities still put through students, not only at fresh year but at postgraduate level. In a more than ever competitive engineering jobs market, applying the right tool is more important than ever, and MATLAB offers the capacity yet relative simplicity to simulate the kind of electromagnetic problems detailed in [POZAR].
The point of solving [POZAR] with MATLAB is to enhance solving capabilities with MATLAB & Simulink hereon, just MATLAB.
In order to work with Electric and Magnetic fields efficiently, any seasoned engineer knows that either you work with spectrum analysers and tools of the kind, with real measurements and real signals, or one can go for an edged and purpose-built simulator, a wide range commercially available.
In any case, regarding electromagnetic simulation, pick and shovel (the hand held calculator) means one can barely cope with the amounts of data to process, or for the case, with most of the real world complex structures beyond the few simple examples that until computers were available to every one, were the only solvable problems with 'pen and paper'. The 'barely' is because there are simple solutions that cleverly exploit symmetries and particular circumstances, that may fool readers to consider that the hand held calculator is enough to work with electromagnetic simulations.
Make no mistake on this point, the more tools you have in your arsenal the more chances to get a good job.
So when it comes to for instance drilling why limit CV skills to pick and shovel, when one can include JCB motorised shovel?
To such purpose, in between tools to work with real signals and purpose built simulators literature references [ED] and [TXEP] focus on developing functions that can be used to solve [POZAR] with MATLAB.
The [ED] suggested script to start 1D wave simulation is appended at the end of these notes, and also attached in .zip named Appendix_A:
modifying [ED] Appendix A script to simulate the following [TXEP] suggested 1D circuits:
In the above slide readers see 6 scenarios, yet when reaching [TXEP] 2D slide containing 2D proposed start exercises, the periodic BC case may also be relevant.
So, a good start simulating electromagnetic waves has to do with implementing the following 7 points:
1.- Basic FDTD 1D loop. [ED] supplies a starter, slow and with diffraction (1), but let's take it from here.
2.- Control source location, place source on one side.
3.- Absorbing boundaries instead of perfect reflectors.
4.- Add one way source. The general wave solution pings a pulse both ways.
With a temporary reflector, just standing behind the source for the duration of the pulse,
then one can 'beam' the source towards just one boundary.
5.- Cyclic space, aka periodic BC: Folding the transmission line under test onto smaller identical
space consecutive cells.
Whatever pulse leaving rightwards automatically re-enters from the left side.
6.- How to calculate transmittance and reflectance when boundaries are not perfect (conductor / absorber).
7.- Add arbitrary device and measure.
In this example the 4 initial points are solved
Since nx is amount of cells, I have renamed number_of_time_steps to nt .
When setting the space to simulate, one cannot simply double or halve for instance domain_source , or make the cavity larger or smaller without the simulation potentially suffering dispersion.
When attempting to change [ED] Appendix A script space and frequency parameters the output may show heavy numerical dispersion. Because the script may be too slow, the amount of time per iteration may be so large that not even the 1st bouncing may show up.
If one does number_of_time_steps=25000 , enough to see travelling pulses a few times backward and forward, then numerical dispersion happens, sample on right hand side:
This is not even half way the total number_of_time_steps and just a couple bounces.
One way to reduce numerical dispersion is to change dx=1e-4; dt=1e-13;I0=15 so the time dispersion parameter equals the space dispersion, read [ED] chapter 2 and [TXEP].
I0 is the pulse amplitude, that has to be modified accordingly because the display box is static, doesn´t shrink or expand to meet the signals inside.
So this is [ED] suggested pulse, with the signal source located right in the middle of the 1D grid, in between perfect metal reflectors.
Since example 1.1 is about calculating wave parameters of a 5GHz plane wave travelling through lossless dielectric medium, electric field wave with expression
E0*cos(2*pi*f0*t-beta*z)
then replacing the Gaussian test pulse with single tone seems reasonable.
To measure numerical dispersion of the algorithm we need to have a look at lambda0 and kx so using a single frequency signal makes it easier to visually spot whether a simulation suffers dispersion.
Again, with the initial script parameters dx and dt the dispersion is again excessive for a burst of single frequency pulses.
Excessive numerical dispersion renders simulation efforts pointless because the signal eventually falls down to same signal levels as the dispersion.
Following, MATLAB to build a single frequency burst of pulses. Overlapped in red, the Gaussian pulse.
source_position = .125; % define source
source_position_index = round(nx*source_position/domain_size)+1;
I0=1
% gauss pulse; use gaussian pulse as reference only
t0=2e-10
% t0=0
tau0=5e-10
Jz_waveform_ref = I0*exp(-((time-t0)/tau0).^2)';
% test pulse: sin burst
f0=2.5e9
Np=4 % amount of cycles, 1 cycle = 2 (sin)^2 peaks
t_window=Np*1/f0
n0=floor(t_window/dt)
nt1=[0:1:2*n0];
Jz_waveform=…
[I0*sin(2*pi*f0*nt1*dt).^2 zeros(1,nt-2*n0-1)];
% figure;plot(time,Jz_waveform+Jz_waveform_ref)
% inspect test signal against reference
figure;plot(time,Jz_waveform);grid on
hold all
plot(time,Jz_waveform_ref);title('test signal + reference')
close all
A parameter missing in [ED] Appendix A script is the ratio lambda/dx .
On the right hand side, showing why, from [TXEP]
Effect of dx too small:
f0=1e8
I0=.3
domain_size=1.25
dx=1e-2
dt=1e-13
nt=75000
n3=1 % dx=n3*dx;dt=n3*dt
n2=3 % main loop time step
it's supposed to be single frequency pulse bouncing on perfect reflector.
After playing a bit with different values of dx and dt as shown in following fdtd_1d_4_1.m [ED] Appendix A simulations starts going somewhere.
Free space defined in initialize_fields_and_materials_1.m
[ED] shows the good practice of building different small code modules instead of writing all code in same single file.
I have modified [ED] start script in Appendix A, into the fddtd_1d_4_1.m . All support functions to run fdtd_1d_4_1.m are:
check_cell2lambda.m
check_numerical_stability.m
E_display_loop.n
init_E_display_loop.m
initialize_fdtdt_coefficients.m
initialize_fields_and_materials_1.m
initialize_plotting_parameters.m
measure_numerical_dispersion.m
plot_fields_while_solving_fdtd.m
I have renamed the modified [ED] plot_fields.m to plot_fields_while_solving_fdtd.m
This highlights the point that it's not an efficient practice to nest plot inside for loops.
Even more considering that at each iteration electromagnetic fields coefficients are updated, that for relatively large models, there is where the computing capacity has to go, not to repeating command plot every time fields are updated.
% fdtd_1d_4_1_1.m
close all;clc;clear all
eps_0=8.854187817e-12; % permittivity of free space
mu_0=4*pi*1e-7; % permeability of free space
c0=1/sqrt(mu_0*eps_0); % light speed
etha0=120*pi
n4=1/2
eps_0=n4*eps_0;
mu_0=n4*mu_0;
%% TIME SPACE YEE FRAME
domain_size = 20.25; % 1D problem space length in meters
dx = 1e-2; % space resolution
nx = round(domain_size/(dx)); % number of space cells
x=[0:dx:domain_size]
nt = 75000; % number of main loop iterations
dt = 1e-11; % time resolution
time = dt*[0:nt-1].'; % define time reference vector
% GEOMETRY
Ndim=1 % Ndim may take values [1 2 3] 1D 2D or 3D problem
n3=1
% eps_0=n3*eps_0
% mu_0=n3*mu_0
domain_size=n3*domain_size
dx=n3*dx
dt=n3*dt
% BAND
f0=5e7;
lambda0=c0/f0
check_numerical_stability
% SIGNAL SOURCE, current
source_position = .1 %25; % define source position
source_position_index = round(nx*source_position/domain_size)+1;
I0=50 % signal amplitude
% gauss pulse; here used as reference only,
% test carried out with burst of single freq sin cycles
% t0=2e-10
% % t0=0
% tau0=5e-10
% % Jz_waveform_ref = I0*exp(-((time-t0)/tau0).^2)';
% Jz_waveform_ref = I0*exp(-((time-t0)/tau0))';
% test pulse: sin^2 burst
Np=1; % amount of cycles, 1 cycle = 2 (sin)^2 peaks
t_window=Np*1/f0;
n0=floor(t_window/dt);
nt1=[0:1:n0];
Jz_waveform=[I0*sin(2*pi*f0*nt1*dt).^2 zeros(1,nt-n0-1)];
% figure;plot(time,Jz_waveform);grid on % check pulse
% hold all
% plot(time,Jz_waveform_ref);title('test signal + reference')
% % close all
measure_numerical_dispersion
check_cell2lambda % Nlambda>10 at least
%% INIT CALCULATION LOOP
initialize_fields_and_materials_1 % free space
initialize_fdtd_coefficients
initialize_plotting_parameters;
Hy_sim=zeros([nt size(Hy)]);
Ez_sim=zeros([nt size(Ez)]);
%% CALCULATION LOOP : calculate simulation
tic
n2=1 % just for test purposes
for kt=1:n2:nt % FDTD loop, kt: previous time_step
Jz(source_position_index) = Jz_waveform(kt);
Hy(1:nx) =... Chyh(1:nx).*Hy(1:nx)+Chyez(1:nx).*(Ez(2:nx+1)-...
Ez(1:nx))+Chym(1:nx).*My(1:nx);
Ez(2:nx) =...
Ceze(2:nx).*Ez(2:nx)+Cezhy(2:nx).*(Hy(2:nx)-...
Hy(1:nx-1))+Cezj(2:nx).*Jz(2:nx);
Hy_sim(kt,:)=Hy; % recording field values
Ez_sim(kt,:)=Ez;
if kt<=n0
Ez(source_position_index-1)=0;
end
Ez(1) = 0; % Apply PEC boundary condition at x = 0 m
Ez(nx+1) = 0; % Apply PEC boundary condition at x = domain_size
plot_fields_while_solving_fdtd;
end
toc
%% INIT E DISPLAY LOOP
init_E_display_loop
%% INIT H DISPLAY LOOP
%% E DISPLAY LOOP
E_display_loop
%% H DISPLAY LOOP
% initialize_fields_and_materials_1.m
% support function for fdtd_1d_4_1.m
% free space
Ceze = zeros(nx+1,1);
Cezhy = zeros(nx+1,1);
Cezj = zeros(nx+1,1);
Ez = zeros(nx+1,1);
Jz = zeros(nx+1,1);
eps_r_z = ones(nx+1,1); % free space
sigma_e_z = zeros(nx+1,1); % free space
% sigma_e_z = 4.4e-4*ones(nx+1,1); % Silicon
% sigma_e_z = 2e-4*ones(nx+1,1); % distilled water
% sigma_e_z = 4*ones(nx+1,1); % sea water
% sigma_e_z=5.823e7 % Cu
% sigma_e_z=6.173e7 % Ag
% sigma_e_z=5 % sea water
% sigma_e_z=9.52e7 % Pt
Chyh = zeros(nx,1);
Chyez = zeros(nx,1);
Chym = zeros(nx,1);
Hy = zeros(nx,1);
My = zeros(nx,1);
mu_r_y = ones (nx,1); % free space
sigma_m_y = zeros(nx,1); % free space
I also tried scaling permittivity and permeability in [ED] Appendix A script but there was no reduction in processing time.
n41=.5 % eps_0 scaling
n42=.5 % mu_0 scaling
domain_size=1.25
dx=1e-4
nx=domain_size/dx
nt=7500000
dt=1e-13
n3=1
domain_size scaling
f0=5e7
I0 =1200 % signal amplitude
n2=50 % main loop time step
Yee stable
time dispersion
space dispersion
Nlambda % not too large but >10
Also tried mu_0=1 and eps_0= eps_0/mu_0 to use [ED] Appendix A script directly but far worse; the wave doesn't start yet MATLAB busy.
So why the limited performance of [ED] Appendix A script? why cannot one just change key parameters like size and simulate at any frequency? or combine multiple frequencies? with different materials?
It turned out that the bulk of the delay is caused by the plot function inside main for loop:
Applying tic toc with nt=7.5e6 and plot_fields.m suppressed, then it only takes 41 seconds to generate all data.
When attempting to store all simulated values the required size of the variables where storing simulated fields may exceed MATLAB default matrix roof size:
Hy_sim=zeros([size(Hy) nt]);
Ez_sim=zeros([size(Ez) nt]);
..
for kt=1:n2:nt
..
Hy_sim(:,kt)=Hy;
Ez_sim(:,kt)=Ez;
..
end
Error using zeros
Requested 12500x1x7500000 (698.5GB) array exceeds maximum array
size preference. Creation of arrays greater than this limit may
take a long time and cause MATLAB to become unresponsive. See
array size limit or preference panel for more information.
n2 only for test purposes. One cannot use n2 too high or the shape of the test signal is lost. Also, n2>1 in the time loop compresses the signal in space. The signal is still going to bounce back wherever a reflector is found, but then reducing domain_size may be the only way to get the signal getting to any boundary, for the same nt.
I found it useful to collect main parameters in Excel spread sheet fdtd_budget.xls and shift values up and down before applying them in the script:
Splitting simulation and display calculations
One loop for simulation calculations, and the other one to display values, fdtd_1d_4_1_2.m
This approach allows to simulate fields with wait time a fraction only of that required to run [ED] Appendix A script. The pace of the simulation display can also be changed without having to recalculate every single time. On the right hand side the start pulse that correctly bounces on both side boundary perfect conductors.
At the cost of a few more data storage bytes, I have copied all necessary files to run fdtd_1d_4_2.m into a separate folder. This is another point that perhaps [ED] should consider in next edition, because while the abundance of working scripts helps read and understand a text, having to guess what files to reuse from previous chapters doesn't help.
Additional functions:
init_E_display_loop.m
E_display_loop.m
n20=5 % simulation display rate
for kt=1:n20:nt/10
Ez_disp=Ez_sim(kt,:);
hp1=plot(hf2.CurrentAxes,Ez_disp); grid on;grid minor;
axis(hf2.CurrentAxes,[0 nx+1 -1.1*Ez_peak 1.1*Ez_peak]);
hf2.CurrentAxes.XTickLabel=cell_x_ruler;
% the following 4 lines require n2 from 5 to 55 for similar signal rate
% lg1=legend(hf2.CurrentAxes,'Ez','Location','northeastoutside')
% title(lg1,['f0 = ' num2str(f0) ' Hz'])
% text(hf2.CurrentAxes,2100,.01,['simulation loop: kt = ' num2str(kt) ])
% text(hf2.CurrentAxes,2100,.008,['simulation time: t = ' num2str(kt*dt) ])
if kt>1
E_frame(floor(kt/n20))=getframe; % ignore 1st frame
end
drawnow
end
% support function for fdtd_4_1.m
Ez_peak=abs(max(max(Ez_sim))) % display very 1st trace
Ez_disp=Ez_sim(2000,:);
hf2=figure(2);
hf2.Name='Ez';
plot(Ez_disp);grid on;grid minor; title(hf2.CurrentAxes,'simulated Ez');
axis(hf2.CurrentAxes,[0 nx+1 -1.1*Ez_peak 1.1*Ez_peak]);
% replace display reference vector numerals with actual physical distance
dXTick=domain_size/numel(hf2.CurrentAxes.XTickLabel); % capture XTick
x_ruler=[0:dXTick:domain_size]';
cell_x_ruler=mat2cell(num2str(x_ruler),ones(1,size(num2str(x_ruler),1)),size(num2str(x_ruler),2));
for sk3=1:1:numel(cell_x_ruler) % limit XTickLabel to just 2 decimals
L1=cell_x_ruler{sk3};
L1(L1==' ')=[]; % remove ' ' from XTickLabel
loc_dot=find(L1=='.'); % take 2 decimals only
if ~isempty(loc_dot)
dloc_dot=length(L1)-loc_dot
switch dloc_dot
case dloc_dot<2
L1=L1([1:find(L1=='.')+length(L1)-loc_dot]);
case dloc_dot>=2
L1=L1([1:find(L1=='.')+2]);
otherwise
end
end
cell_x_ruler{sk3}=L1;
end
hf2.CurrentAxes.XTickLabel=cell_x_ruler;
title(hf2.CurrentAxes,'simulated Ez')
Propagation through lossy materials:
In fdtd_1d_4_3.m as requested in one of [ED] exercises, a lossy material simulation is implemented
In initialize_fields_and_materials.m instead of using ideal material, use real conductivities.
sima_e_z=zeros(nx+1,1) has been replaced with for instance, Silicon conductivity:
sigma_e_z = 4.4e-4*ones(nx+1,1)
the pulse correctly shifts forward only (rightwards) and bounces back correctly on both sides until simulation time steps exhausted.
Saving and retrieving simulated E H
The main purpose of including fields simulation in the very 1st example of [POZAR] solved with MATLAB is to build tools needed when simulating electromagnetic fields. While some electromagnetic modelling may require dedicated processing capacity (for instance a GPU), [ED] may be a basic start point may be function save_load_fields.m appended at the end of this note.
Why recalculate it all every time? here I briefly attempted adding storage support function for calculated fields, including clause to choose whether use stored fields, if in same folder, or just recalculate.
With
dx = 0.010000000000000
dt = 9.999999999999999e-12
f0 = 50000000
nt = 75000
nx = 2025
then
nt*nx
=
151875000
Yet stored field in file size, for different parameters used, for just Ez_sim that exceeds 2GB.
I also checked whether getframe would somehow save disk space for same simulated field size.
command movie can be used to reproduce simulation directly from workspace, with movie(E_frame)
save E_frame.mat E_frame
save('E_frame.mat','E_frame')
to load stored field
filename=E_frame.mat
load(filename)
or
load('E_frame.mat')
However, it's a back-to-square-one effort: using getframe and movie doesn't save file size. There is no data compression because E_frame.mat and E_sim_field.mat have same size.
Saving 1st derivative dE/dt, instead of E halves the size of the .mat file, but given the large amount of zeros, there has to be a far more efficient way to save simulated fields data.
Edot_sim=diff(Ez_sim);
save Edot_sim.mat 'Edot_sim'
Also tried the following
zip('Edot_sim.zip','Edot_sim.mat')
tic;tar('Edot_sim.tar','Edot_sim.mat');toc
dir('E*field*')
L3=dir('E*field*')
L3.bytes
Elapsed time is 61.876906 seconds.
E_01_01_field.mat E_01_01_field.tar
L3 =
2×1 struct array with fields:
name
folder
date
bytes
isdir
datenum
=
1.112588546000000e+09
=
1.112596480000000e+09
.mat to .zip or .tar compressed files all have same size.
I used save_load_fields.m right after the simulation loop:
n1_save='1'; % E field descriptors
n2_save='1';
str_save_e=['Ez_' n1_save n2_save]
[str150_vars_file,num123,rload]=save_load_fields(Ez_sim,'Ez_sim',n1_save,n2_save,1)
n3_save='1'; % H field descriptors
n4_save='1';
str_save_e=['Hy_' n3_save n4_save]
[str150_vars_file,num123,rload]=save_load_fields(Ez_sim,'Hy_sim',n1_save,n2_save,1)
Efficiently compressing fields data is one of the many benchmarks of commercial electromagnetic simulators. No further time will be spent on this point.
Absorbing materials on boundaries
[POZAR] example 1.1 supplies lambda equal 3cm. Such measurement is carried out measuring consecutive field peaks. To measure consecutive peaks it's cheaper to use a stationary wave. Resonators hold propagating waves stationary within it's cavity. Another convenient way is to suppress return waves.
So suppress electromagnetic waves, there are commercial products readily available.
example real absorbing materials http://www.masttechnologies.com/rf-absorbers/
example different absorbers frequency response
https://leadertechinc.com/blog/different-types-rf-absorbers/
[ED] chapter 7 develops a support function for 2D perfectly matched layer. 3D PML matching conditions:
I tried the following to simulate the so called Perfect Matched Layer PML
Ez(nx+1)=-Ez(nx)
Doesn't work, just shifting electric field phase 180° does not behave as PML, it's just another way to implement a reflector.
[ED] chapter 7 2D implementation of a perfect PML layer requires PML layers to have certain thickness
However, a magnetic wall, although not exactly a PML, it approaches the equivalent wave impedance to that of free space, as if the boundary layer were RF 'transparent'. To such purpose, replace
Ez(1) = 0;Ez(nx+1) = 0; % perfect reflectors at x=0 m and x=domain_size
with
Ez(nx+1) = -Ez(nx);
Hy(1) = 0;
Hy(nx+1) = 0;
also the following has been added in initialize_fields_and_materials.m
Ez(nx+1)=Cezxe_border1*Ez(nx)+Cezxby_border1*(Hz(nx+1)-Hz(nx))
Cezxe_border1=1
Cezxby_border1=dt/(eps_0*dx)
When using initialize_fields_and_materials_1.m lossless material, with a hold all right before calling E_display_loop.m the following s obtained:
With initialize_fields_and_materials_4.m lossy material,
Appreciate that the green line showing the return is far lower than when
If just 'some' absorption is ok, 'some' as in how many dB do you need, then an approximation of matched layer for 1D absorber would be a magnetic wall:
This is not a thick PML, just an approximation of PML code solution provide in [ED] chapter 7, but sometimes combining a thin absorber with lossy material may be ok.
Measuring lambda and er
Now use fdtd_1d_4_5.m and support functions in same folder.
There's no need for absorber, or even to cut the transmission line at a specific length. Not even to know the exact value of the load, but the closer to a short the better to get as much return as possible.
However, a far longer train of pulses is needed, otherwise only 2 peaks would show up when near reflection, and let's apply example 1.1 parameters.
In fdtd_1d_4_5.m the following FDTD parameters matching example 1.1 question are applied
domain_size = .25;
dx = 1e-3;
nt = 175000;
dt = 1e-13;
f0=5e9;
source_position = .01
I0=1
Np=5
obtaining the simulation on the right hand side:
One can now manually measure lambda
(176-145)*dx
=
0.031000000000000
Or directly processing the simulation
mean_Ez_sim=mean(Ez_sim,1);
figure;plot(x,mean_Ez_sim);grid on
xlabel('x');ylabel('Ez sim')
% solve odd samples around source
nsource_position=find(x==source_position)
mean_Ez_sim([nsource_position-1 nsource_position nsource_position+1])=0
% fold signal to include negative peaks
mean_Ez_sim=abs(mean_Ez_sim)
figure;plot(x,mean_Ez_sim);grid on
xlabel('x');ylabel('|Ez sim|')
title('stationary wave to measure \lambda')
[row,col,v]=findpeaks(mean_Ez_sim)
x_peaks=x(col)
hold all;plot(x(col),mean_Ez_sim(col),'ro')
% ignore peaks behind source position
x_peaks(x_peaks<source_position+.001)=[]
% now x_peaks samples behind or on source removed
x_peaks
lambda_measure2=mean(diff(x_peaks))
x_peaks =
0.008 0.016 0.045 0.075 0.107 0.143 0.175 0.206 0.235
x_peaks = 0.016 0.045 0.075 0.107 0.143 0.175 0.206 0.235
lambda_measure2 = 0.031285714285714
Once lambda has been measured, then it's time to plug the initial lines calculate wave constant kz propagation velocity vp and relative permittivity er
When producing enough pulses against any load other than PML or a matched load, if watching long enough, then wave peaks are observable, similarly to [POZAR] example 2.4 supplied measurement
Appendices to Pozar example 1.1 Notes
save_load_fields.m
function [str150_vars_file,num123,rload]=save_load_fields(A,str_field_name,n1,n2,field_type)
%
% FILE NAME: load_results_if_available.m
%
% DESCRIPTION: Support function for fdtd_4_1_3.m
%
%
%
% MATLAB script author: John Bofarull.
% jgb2012@sky.com jgb2014@live.co.uk
num123(1)=n1;
num123(2)=n2;
num123(3)=field_type;
if n1<10 L_chap_n=[ '0' num2str(n1)]; end % generate .mat file name
if n1>=10 L_chap_n=num2str(n1); end
if n2<10 L_ex_n=[ '0' num2str(n2)]; end
if n2>=10 L_ex_n=num2str(n2); end
if field_type==1 % ex_type=1 then Electric field
str150_vars_file=['E_' L_chap_n '_' L_ex_n '_field.mat']
str_field_type='E'
end
if field_type==0 % ex_type=0 then Magnetic field
str150_vars_file=['H_' L_chap_n '_' L_ex_n '_field.mat']
str_field_type='H'
end
rload=0 % 0: no results stored or script told to recalculate regardless of possibly available results.
% 1: results available, may reload and avoid recalculate.
Ldir=ls('*.mat'); % assume already in right directory: get list .mat files within same directory.
s=0 % s: amount .mat files with file name matching str150_var_file
% OS should have policy of unique file names in same folder active
k1=1
if size(Ldir,1)>0 % Ldir not empty
while s==0 && k1<=size(Ldir,1)
Ldir1=Ldir(k1,:);
if strcmp(str150_vars_file,Ldir1) % remove trailing heading possible blank characters in name.
s=1;
rload=1;
k1=k1+1;
else
s=0;
rload=0;
k1=k1+1;
end
end
end
if s==0 % Ldir empty = list doesn't contain str150_vars_file, results not available.
disp(['No previous ' str150_vars_file ' stored in folder, saving ' str_field_type ' field in .mat file.'])
L2=['save ' str150_vars_file ' ' str_field_name]
evalin('base',L2)
save(str150_vars_file,A)
rload=1;
return
end
prompt='Results already stored. Do you want to recalculate? Y/N [Y]: '; % list contains str150_vars_file, results available.
str150_input=input(prompt,'s');
if isempty(str150_input) || str150_input=='y' || str150_input=='Y'
rload=1;
return % recalculating
end
if str150_input=='n' || str150_input=='N'
rload=0;
hw=whos;
Lvars={}
for k2=1:1:size(hw,1) % list with all .mat file names
if ~isequal(hw(k2).name,'str150_vars_file')
Lvars=[Lvars hw(k2).name];
end
end
disp('Loading Results ...');
str151=['load ' str150_vars_file];
evalin('base',str151)
pause(2)
disp('Stored results loaded.') % exit to avoid recalculating just loaded results
rload=0
num123(1)=n1;
num123(2)=n2;
num123(3)=field_type;
end
end
[ED] original Appendix A 1D, wave moves way too slow when slightly varying simulation parameters.
fdtd_solve.m
% This program demonstrates a one-dimensional FDTD simulation.
% The problem geometry is composed of two PEC plates extending to
% infinity in y, and z dimensions, parallel to each other with 1 meter
% separation. The space between the PEC plates is filled with air.
% A sheet of current source paralle to the PEC plates is placed
% at the center of the problem space. The current source excites fields
% in the problem space due to a z-directed current density Jz,
% which has a Gaussian waveform in time.
% Define initial constants
eps_0 = 8.854187817e-12; % permittivity of free space
mu_0 = 4*pi*1e-7; % permeability of free space
c = 1/sqrt(mu_0*eps_0); % speed of light
% Define problem geometry and parameters
domain_size = 1; % 1D problem space length in meters
dx = 1e-3; % cell size in meters
dt = 3e-12; % duration of time step in seconds
number_of_time_steps = 2000; % number of iterations
nx = round(domain_size/dx); % number of cells in 1D problem space
source_position = 0.5; % position of the current source Jz
% Initialize field and material arrays
Ceze = zeros(nx+1,1);
Cezhy = zeros(nx+1,1);
Cezj = zeros(nx+1,1);
Ez = zeros(nx+1,1);
Jz = zeros(nx+1,1);
eps_r_z = ones (nx+1,1); % free space
sigma_e_z = zeros(nx+1,1); % free space
Chyh = zeros(nx,1);
Chyez = zeros(nx,1);
Chym = zeros(nx,1);
Hy = zeros(nx,1);
My = zeros(nx,1);
mu_r_y = ones (nx,1); % free space
sigma_m_y = zeros(nx,1); % free space
% Calculate FDTD updating coefficients
Ceze = (2 * eps_r_z * eps_0 - dt * sigma_e_z) ...
./(2 * eps_r_z * eps_0 + dt * sigma_e_z);
Cezhy = (2 * dt / dx) ...
./(2 * eps_r_z * eps_0 + dt * sigma_e_z);
Cezj = (-2 * dt) ...
./(2 * eps_r_z * eps_0 + dt * sigma_e_z);
Chyh = (2 * mu_r_y * mu_0 - dt * sigma_m_y) ...
./(2 * mu_r_y * mu_0 + dt * sigma_m_y);
Chyez = (2 * dt / dx) ...
./(2 * mu_r_y * mu_0 + dt * sigma_m_y);
Chym = (-2 * dt) ...
./(2 * mu_r_y * mu_0 + dt * sigma_m_y);
% Define the Gaussian source waveform
time = dt*[0:number_of_time_steps-1].';
Jz_waveform = exp(-((time-2e-10)/5e-11).^2);
source_position_index = round(nx*source_position/domain_size)+1;
% Subroutine to initialize plotting
initialize_plotting_parameters;
% FDTD loop
for time_step = 1:number_of_time_steps
% Update Jz for the current time step
Jz(source_position_index) = Jz_waveform(time_step);
% Update magnetic field
Hy(1:nx) = Chyh(1:nx) .* Hy(1:nx) ...
+ Chyez(1:nx) .* (Ez(2:nx+1) - Ez(1:nx)) ...
+ Chym(1:nx) .* My(1:nx);
% Update electric field
Ez(2:nx) = Ceze (2:nx) .* Ez(2:nx) ...
+ Cezhy(2:nx) .* (Hy(2:nx) - Hy(1:nx-1)) ...
+ Cezj(2:nx) .* Jz(2:nx);
Ez(1) = 0; % Apply PEC boundary condition at x = 0 m
Ez(nx+1) = 0; % Apply PEC boundary condition at x = 1 m
% Subroutine to plot the current state of the fields
plot_fields;
end
initialize_plotting_parameters.m
% subroutine used to initialize 1D plot
Ez_positions = [0:nx]*dx;
Hy_positions = ([0:nx-1]+0.5)*dx;
v = [0 -0.1 -0.1; 0 -0.1 0.1; 0 0.1 0.1; 0 0.1 -0.1; ...
1 -0.1 -0.1; 1 -0.1 0.1; 1 0.1 0.1; 1 0.1 -0.1];
f = [1 2 3 4; 5 6 7 8];
axis([0 1 -0.2 0.2 -0.2 0.2]);
lez = line(Ez_positions,Ez*0,Ez,'Color','b','LineWidth',1.5);
lhy = line(Hy_positions,377*Hy,Hy*0,'Color','r', ...
'LineWidth',1.5,'linestyle','-.');
set(gca,'fontsize',12,'FontWeight','bold');
axis square;
legend('E_{z}', 'H_{y} \times 377','Location','NorthEast');
xlabel('x [m]');
ylabel('[A/m]');
zlabel('[V/m]');
grid on;
p = patch('vertices', v, 'faces', f, 'facecolor', 'g', 'facealpha',0.2);
text(0,1,1.1,'PEC','horizontalalignment','center','fontweight','bold');
text(1,1,1.1,'PEC','horizontalalignment','center','fontweight','bold');
plot_fields.m
% subroutine used to plot 1D transient fields
delete(lez);
delete(lhy);
lez = line(Ez_positions,Ez*0,Ez,'Color','b','LineWidth',1.5);
lhy = line(Hy_positions,377*Hy,Hy*0,'Color','r', ...
'LineWidth',1.5,'linestyle','-.');
ts = num2str(time_step);
ti = num2str(dt*time_step*1e9);
title(['time step = ' ts ', time = ' ti ' ns']);
drawnow;