Contents

Preamble

This code listing is generated using Matlab's publishing function. The code is in the exact same order as the plaintext .m file. The main bulk of the program (constructing the matrix and solving for the E-field) is contained in a function compute_R_and_T() at the bottom of the file.

% Assignment 1
close all
clear all

Constants

global mu0 c0 e0;
mu0 = 4e-7*pi;
c0 = 299792458;
e0 = 1/(mu0*c0^2);

Input params

N = 4;
a = 2e-2;       % Glass thickness (=2cm)
omega = 3*10^9;
E0 = 1;         % amplitude of incident field E^i_z
er = 2.5;       % relative permittivity
sigma = 0.02;   % conductivity
grid_select = "G1";

Analytical values

k0 = omega/c0;
k1ana = sqrt(er*k0^2 - j*omega*mu0*sigma);
Dana = ((k0 + k1ana)^2)*exp(j*4*a*k1ana) - (k0 - k1ana)^2;
Rana = ((k0^2 - k1ana^2)/Dana)*exp(j*2*a*k0)*(exp(j*4*a*k1ana) - 1); %
Tana = ((k0*k1ana)/Dana)*4*exp(j*2*a*(k0 + k1ana));

Compute R & T for four values of h

Rvec = [];
Tvec = [];
hvec = [];

for idx = 1:4
    % N^idx as an argument ensures a geometric series for h.
    [R, T] = compute_R_and_T(N^idx, a, omega, E0, er, sigma, grid_select);

    Rvec(idx) = R;
    Tvec(idx) = T;
    hvec(idx) = 2*a/N^idx;
end

% Absolute error values
Rerr = Rana - Rvec;
Terr = Tana - Tvec;

Order of Convergence

We obtain two values for order of convergence (alpha) using two geometric sequences. This is just to increase confidence in our result.

alpha_R_vec = [0,0];
alpha_T_vec = [0,0];

for idx = 1:2
    alpha_R_vec(idx) = log((Rvec(idx) - Rvec(idx+1))./(Rvec(idx+1) - Rvec(idx+2)))./log(hvec(idx)/hvec(idx+1));
    alpha_T_vec(idx) = log((Tvec(idx) - Tvec(idx+1))./(Tvec(idx+1) - Tvec(idx+2)))./log(hvec(idx)/hvec(idx+1));
end

alpha_R = alpha_R_vec(1);
alpha_T = alpha_T_vec(1);

Extrapolate to zero cell size

Least-squares approximation

% R
A = [ones(length(hvec), 1), (hvec.^(alpha_R)).'];
b = Rvec.';
x = A\b;
extrapolated_R = x(1);

% T
A = [ones(length(hvec), 1), (hvec.^(alpha_T)).'];
b = Tvec.';
x = A\b;
extrapolated_T = x(1);

compute_R_and_T

This function is called from the main body of the program above.

function [R, T] = compute_R_and_T(N, a, omega, E0, er, sigma, grid_select)
    % Solve E-field and compute R and T for a given grid and resolution
    % Inputs:
    %   N: grid size specifier. Must be even integer >=4
    %   a: glass thickness
    %   omega: wave frequency
    %   E0: complex magnitude of incident wave
    %   er: relative permittivity of glass
    %   sigma: conductivity of glass
    %   grid_select: select grid G1 or G2

    % Initial Parameters
    global mu0 c0 e0;
    k0 = omega/c0;

    % Construct grid
    if (grid_select == "G1")
        % G1 (ie. grid 1) material interfaces fall between grid points
        n = -N-1:1:N;
        dx = 2*a/N;
        xn = (n + 0.5)*dx;
        Ngp = length(xn);
    elseif (grid_select == "G2")
        % G2 - material interfaces fall on grid points
        n = -N:1:N;
        dx = 2*a/N;
        xn = n*dx;
        Ngp = length(xn);
    else
        assert(false, "Use G1 or G2 as grid type")
    end

    % Set up system of equations

    % Set up material properties (e & sigma) for each spatial grid point
    sigma_vec = zeros(Ngp, 1);
    e_vec = e0*ones(Ngp, 1);  % e(x) = er(x)*e0

    glass_indices = find(xn > -a & xn < a);
    sigma_vec(glass_indices) = sigma;
    e_vec(glass_indices) = er * e_vec(glass_indices);

    % Fill the interior
    A = -1/dx^2*spdiags([1, -2, 1],-1:1,Ngp,Ngp); % generic FD tridiagonal
    % Add material-dependent terms to the main diagonal
    for idx = 1:Ngp
        A(idx, idx) = A(idx, idx) + mu0*(j*omega*sigma_vec(idx) - omega^2*e_vec(idx));
    end

    % Left boundary condition (z1-z0)/h - j*k0*(z1+z0)/2 = -2*j*k*Ez((x0+x1)/2)
    A(1, 1:2) = [-1/dx-j*k0/2, 1/dx-j*k0/2];

    % Right boundary condition (zN-zN-1)/h + jk0(zN+zN-1)/2
    A(Ngp, Ngp-1:Ngp) = [-1/dx+j*k0/2, 1/dx+j*k0/2];

    % Right hand side
    b = zeros(Ngp, 1);
    b(1) = -2*j*k0*E0*exp(-j*k0*(0.5*(xn(1) + xn(2)))); % Left bound, evaluated at x1, but really lies on half-grid(??). We obviously don't have a half grid, so we approximate by taking nearest neighbour average.

    Etot = A\b;
    Etot = Etot.'; % Nonconjugate transpose!

    % Compute R & T
    % We obtain values for R and T for every grid point.
    % We choose to keep the value that is nearest (but not on) the scatterer.

    % Reflection coeff
    Rnum = ((Etot - E0*exp(-j*k0*xn)).*exp(-j*k0*xn))/E0;
    Rnum = Rnum(find(xn < -a));
    Rnum = Rnum(end);

    % Transmission coeff
    Tnum = (Etot.*exp(j*k0*xn))/E0;
    Tnum = Tnum(find(xn > a));
    Tnum = Tnum(1);

    R = Rnum;
    T = Tnum;
end