Metamaterials Tutorials
Step-by-step guides from basic concepts to advanced applications
Getting Started with Split-Ring Resonators
Learn the basics of SRR design and understand magnetic resonance in metamaterials.
Step 1: Understanding the LC Model
An SRR behaves like an LC resonant circuit. The ring provides inductance L, while the gap provides capacitance C. The resonance frequency is:
f₀ = 1 / (2π√LC)
Step 2: Design Your First SRR
from metamaterials import UnitCellDesigner
# Create an SRR for 5 THz operation
srr = UnitCellDesigner(
cell_type='srr',
radius=50e-6, # 50 μm radius
track_width=8e-6, # 8 μm track
gap_width=4e-6 # 4 μm gap
)
# Calculate resonance
f_res = srr.calculate_resonance()
print(f"Resonance: {f_res/1e12:.2f} THz")
# Get circuit parameters
L = srr.get_inductance()
C = srr.get_capacitance()
print(f"L = {L*1e9:.2f} nH, C = {C*1e15:.3f} fF")
Step 3: Analyze the Response
Near resonance, the SRR produces a strong magnetic dipole moment, leading to negative effective permeability μ(ω) in a narrow frequency band above ω₀.
Key Takeaway
Reducing SRR dimensions increases the resonance frequency. To reach optical frequencies, nanoscale fabrication is required.
Achieving Negative Refractive Index
Combine electric and magnetic resonances to create a negative index material.
Step 1: The Dual Requirement
For n < 0, you need both ε < 0 and μ < 0 simultaneously. This requires overlapping the electric response (from wires) with the magnetic response (from SRRs).
Step 2: Design the Composite Structure
from metamaterials import UnitCellDesigner, DispersionModel
# Design SRR + wire hybrid
hybrid = UnitCellDesigner(
cell_type='hybrid',
radius=80e-6,
track_width=10e-6,
gap_width=5e-6
)
# Create dispersion model
model = DispersionModel(
model_type='drude_lorentz',
epsilon_inf=1.0,
omega_p=2*np.pi*15e12, # Electric plasma frequency
omega_0=2*np.pi*5e12, # Magnetic resonance
gamma_e=2*np.pi*0.5e12, # Electric damping
gamma_m=2*np.pi*0.3e12, # Magnetic damping
F=0.4 # Filling factor
)
Step 3: Find the NIM Band
# Sweep frequency and find where both ε' < 0 and μ' < 0
frequencies = np.linspace(1e12, 15e12, 1000)
nim_band = model.find_nim_band((1e12, 15e12))
print(f"NIM band: {nim_band[0]/1e12:.1f} - {nim_band[1]/1e12:.1f} THz")
# Calculate figure of merit
n_min, fom = model.calculate_fom()
print(f"Minimum n' = {n_min:.2f}, FOM = {fom:.1f}")
Important
High losses (low FOM) are a major challenge for NIMs. The FOM = |Re(n)|/Im(n) should be > 3 for practical applications.
Designing a Transformation Optics Cloak
Create an invisibility cloak using coordinate transformations.
Step 1: Define the Transformation
A cylindrical cloak compresses the region r ∈ [0, b] into r' ∈ [a, b], leaving a hidden region r < a where light cannot penetrate.
from metamaterials import CloakDesigner
# Design cylindrical cloak
cloak = CloakDesigner(
shape='cylindrical',
inner_radius=1.0, # Hide objects smaller than 1λ
outer_radius=2.5, # Cloak shell extends to 2.5λ
n_layers=20
)
# Get required material parameters
r_values = np.linspace(1.0, 2.5, 20)
for r in r_values:
params = cloak.get_material_profile(r)
print(f"r={r:.2f}λ: εr={params['eps_r']:.2f}, εθ={params['eps_theta']:.2f}")
Step 2: Simulate the Cloaking Effect
# Run full-wave simulation
field = cloak.simulate_field(
wavelength=10e-6,
angle=0, # Normal incidence
polarization='TE'
)
# Calculate scattering
total_scat = cloak.calculate_scattering()
print(f"Total scattering: {total_scat:.1f} dB")
# Compare to uncloaked object
uncloaked_scat = -10 * np.log10(np.pi * 1.0**2) # Geometric cross-section
reduction = uncloaked_scat - total_scat
print(f"Scattering reduction: {reduction:.1f} dB")
Challenge
The material parameters at r = a become singular (εr → 0, εθ → ∞). Practical cloaks use reduced parameter sets that sacrifice bandwidth for realizability.
Perfect Absorber Optimization
Design a metamaterial absorber with >99% absorption through impedance matching.
Step 1: Impedance Matching Condition
Perfect absorption occurs when the metamaterial impedance matches free space (Z = Z₀) while having non-zero imaginary parts of ε and μ for energy dissipation.
Step 2: MIM Structure Design
from metamaterials import PerfectAbsorber
# Design metal-insulator-metal absorber
absorber = PerfectAbsorber(
structure='patch_array',
period=20e-6,
patch_size=15e-6,
dielectric_thickness=500e-9,
metal_thickness=100e-9,
metal='gold',
dielectric='sio2'
)
# Optimize for target frequency
target_freq = 10e12
absorber.optimize(target_freq, bandwidth='narrowband')
# Get absorption spectrum
freqs, absorption = absorber.calculate_spectrum()
peak_idx = np.argmax(absorption)
print(f"Peak absorption: {absorption[peak_idx]*100:.1f}% at {freqs[peak_idx]/1e12:.2f} THz")
Step 3: Angular Performance
# Check angular stability
angles = np.linspace(0, 80, 17)
angular_response = absorber.angular_response(target_freq, angles)
for angle, abs_te, abs_tm in zip(angles, angular_response['TE'], angular_response['TM']):
print(f"θ={angle:2.0f}°: TE={abs_te*100:.1f}%, TM={abs_tm*100:.1f}%")
FDTD Simulation with Dispersive Materials
Implement full-wave time-domain simulation including material dispersion.
from metamaterials import FDTDSolver, DispersionModel
# Setup dispersive NIM model
nim_model = DispersionModel(
model_type='drude_lorentz',
omega_p=2*np.pi*15e12,
omega_0=2*np.pi*5e12,
gamma=2*np.pi*0.3e12
)
# Initialize FDTD with dispersive material support
fdtd = FDTDSolver(
grid_size=(512, 512),
dx=50e-9,
pml_layers=30,
dispersive=True
)
# Add Gaussian pulse source
fdtd.add_source(
'gaussian',
position=(100, 256),
params={
'f0': 5e12,
'bandwidth': 2e12,
'polarization': 'Ez'
}
)
# Add NIM slab
fdtd.add_structure(
geometry={'type': 'slab', 'x1': 200, 'x2': 312},
material=nim_model
)
# Add field monitors
fdtd.add_monitor('reflection', position=150)
fdtd.add_monitor('transmission', position=350)
# Run simulation
fdtd.run(
n_steps=10000,
callbacks=[
('field_snapshot', 500, 'Ez'),
('energy_evolution', 100)
]
)
# Extract S-parameters
sparams = fdtd.calculate_sparams()
print(f"|S11| = {sparams['S11_mag']:.3f}, |S21| = {sparams['S21_mag']:.3f}")