Silicon Microring Resonator

WDM Drop Filter @ 1550nm - Weekend Photonics Project

1550nm

Center Wavelength

Q ≈ 1950

Quality Factor

≥20dB

Extinction Ratio

100GHz

Free Spectral Range

<30µm²

Footprint

Project Overview

Why This Project?

Silicon microring resonators offer a perfect introduction to integrated photonics: simple geometry yet rich physics, runs on free/academic software, and provides skills directly transferable to complex PIC designs. Master resonance, Q-factor, and coupling in a weekend!

Compact Design

Ultra-small footprint (<30µm × 30µm) with powerful wavelength selectivity. Ideal for dense photonic integration and WDM applications.

Rich Physics

Explore resonance conditions, quality factors, coupling coefficients, and free spectral range through hands-on simulation.

Industry Workflow

Learn the complete PIC design flow: layout → mode solving → FDTD → compact modeling → circuit verification.

Software Stack

Choose your preferred tools - all options support the complete workflow

Task Open-Source / Free-Tier Commercial (Trial/Edu)
Layout & Scripting gdsfactory (Python) or KLayout + SiEPIC Ansys Lumerical Layout
Eigen-mode Solver mode_solver.py in Meep or MPB Ansys MODE
3D FDTD Meep or Flexcompute Tidy3D (GPU cloud) Ansys FDTD (2025 R1 trial)
Circuit Verification Caphe in gdsfactory or simphony Ansys INTERCONNECT

Quick Start

All tools install with pip or run in the browser. gdsfactory even autogenerates Meep/Tidy3D scripts from your GDS layout. Check the awesome-photonics repo for alternative tools!

Design Specifications

Center Wavelength 1550 nm
FWHM ≈ 0.8 nm
Quality Factor Q ≈ 1950
Extinction Ratio ≥ 20 dB
Free Spectral Range ≈ 100 GHz
Footprint ≤ 30µm × 30µm

Microring Resonator Design

Step-by-Step Workflow

1

Layout Parametric Cell

Create the ring resonator geometry using gdsfactory's parametric components.

c = gf.components.ring_single(radius=7, gap=0.15)

💡 Keep waveguide width at 450nm for Si PIC foundry compatibility

2

Mode-Solver Check

Sweep waveguide width & slab height to extract effective refractive index (n_eff).

A quick 2D solver run tells you if the ring will be single-mode.

3

3D FDTD Sweep

Automate parameter sweeps: radius (6-8 µm) & gap (0.12-0.25 µm). Measure S-parameters.

💡 Meep/Tidy3D jobs finish in minutes on a GPU instance

4

Extract Metrics

From the transmission spectrum, fit Lorentzian → Q, FSR, ER.

scipy.optimize.curve_fit(lorentzian, wavelength, transmission)
5

Build Compact Model

Convert fitted parameters to an INTERCONNECT or Caphe ring component.

Drop the device into a larger NRZ/PAM-4 link to see eye-diagrams.

6

(Optional) Inverse-Design Tweak

With Tidy3D's autodiff API, optimize the bus-ring gap profile for max ER.

TidyGrad examples show 10-line scripts that converge in <50 iterations.

Interactive Demonstrations

Explore the physics and design process through interactive tools

Performance Analysis

Transmission Spectrum & Q-Factor Analysis

Design Space Exploration

Implementation Example

Complete Python workflow for ring resonator design and analysis

import gdsfactory as gf
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

# Step 1: Create parametric ring resonator
def create_ring_filter(radius=7, gap=0.15, width=0.45):
    """Create a single ring resonator drop filter"""
    c = gf.Component()
    
    # Create ring and bus waveguides
    ring = c.add_ref(gf.components.ring(radius=radius, width=width))
    bus = c.add_ref(gf.components.straight(length=2*radius+10))
    
    # Position bus waveguide with specified gap
    bus.movey(-radius - width/2 - gap - width/2)
    
    # Add ports
    c.add_port("in", port=bus.ports["o1"])
    c.add_port("through", port=bus.ports["o2"])
    c.add_port("drop", port=ring.ports["o2"])
    c.add_port("add", port=ring.ports["o1"])
    
    return c

# Step 2: FDTD simulation setup (using Tidy3D)
def simulate_ring(component, wavelengths):
    """Run FDTD simulation and extract S-parameters"""
    import tidy3d as td
    
    # Convert GDS to simulation geometry
    sim = gf.plugins.tidy3d.get_simulation(
        component=component,
        wavelength=1.55,
        wavelength_span=0.1,
        port_source="in",
        port_monitors=["through", "drop"],
        mesh_accuracy=3
    )
    
    # Run simulation
    data = td.web.run(sim, task_name="ring_resonator")
    
    # Extract S-parameters
    S21 = data["through"].amps
    S31 = data["drop"].amps
    
    return S21, S31

# Step 3: Analyze resonances
def lorentzian(x, x0, gamma, A, offset):
    """Lorentzian function for resonance fitting"""
    return A * gamma**2 / ((x - x0)**2 + gamma**2) + offset

def extract_metrics(wavelengths, transmission):
    """Extract Q-factor, FSR, and extinction ratio"""
    # Find resonances
    from scipy.signal import find_peaks
    peaks, _ = find_peaks(-transmission, height=0.1)
    
    # Fit Lorentzian to each resonance
    metrics = []
    for peak in peaks:
        # Select data around peak
        idx_range = slice(max(0, peak-20), min(len(wavelengths), peak+20))
        x_fit = wavelengths[idx_range]
        y_fit = transmission[idx_range]
        
        # Initial guess
        x0_guess = wavelengths[peak]
        gamma_guess = 0.0004  # ~0.8nm FWHM
        A_guess = 1 - np.min(y_fit)
        offset_guess = np.max(y_fit)
        
        # Fit
        popt, _ = curve_fit(lorentzian, x_fit, y_fit, 
                           p0=[x0_guess, gamma_guess, A_guess, offset_guess])
        
        # Calculate metrics
        resonance_wavelength = popt[0]
        fwhm = 2 * popt[1]
        Q_factor = resonance_wavelength / fwhm
        extinction_ratio_dB = -10 * np.log10(np.min(y_fit) / np.max(y_fit))
        
        metrics.append({
            'wavelength': resonance_wavelength,
            'Q': Q_factor,
            'ER_dB': extinction_ratio_dB,
            'FWHM_nm': fwhm * 1000  # Convert to nm
        })
    
    # Calculate FSR
    if len(metrics) > 1:
        fsr_nm = np.diff([m['wavelength'] for m in metrics]).mean() * 1000
        fsr_ghz = 3e8 / (1.55e-6)**2 * fsr_nm * 1e-9 * 1e9  # Convert to GHz
    else:
        fsr_nm = fsr_ghz = None
    
    return metrics, fsr_ghz

# Step 4: Parameter sweep
def sweep_design_space():
    """Sweep radius and gap to optimize performance"""
    radii = np.linspace(6, 8, 5)
    gaps = np.linspace(0.12, 0.25, 5)
    
    results = []
    for radius in radii:
        for gap in gaps:
            # Create design
            ring = create_ring_filter(radius=radius, gap=gap)
            
            # Simulate (simplified - would use actual FDTD)
            # Here we use analytical approximation
            Q_loaded = estimate_Q(radius, gap)
            ER = estimate_ER(gap)
            
            results.append({
                'radius': radius,
                'gap': gap,
                'Q': Q_loaded,
                'ER_dB': ER
            })
    
    return results

# Helper functions for analytical estimates
def estimate_Q(radius, gap):
    """Estimate loaded Q-factor"""
    # Coupling coefficient (empirical model)
    kappa = np.exp(-2 * gap / 0.1)  # Simplified exponential model
    
    # Intrinsic Q (loss-limited)
    Q_intrinsic = 50000  # Typical for low-loss SOI
    
    # Loaded Q
    Q_loaded = Q_intrinsic / (1 + kappa * Q_intrinsic)
    
    return Q_loaded

def estimate_ER(gap):
    """Estimate extinction ratio"""
    kappa = np.exp(-2 * gap / 0.1)
    ER_linear = (1 - kappa)**2 / (4 * kappa)
    return 10 * np.log10(ER_linear)

# Step 5: Generate compact model
def create_compact_model(ring_params, s_params):
    """Generate Caphe/INTERCONNECT compatible model"""
    model = {
        'type': 'ring_resonator',
        'parameters': ring_params,
        'ports': ['in', 'through', 'drop', 'add'],
        's_parameters': s_params,
        'center_wavelength': 1.55e-6,
        'ng': 4.2,  # Group index
        'loss_dB_per_cm': 2.0
    }
    
    return model

# Main execution
if __name__ == "__main__":
    # Create optimized design
    ring = create_ring_filter(radius=7.2, gap=0.18)
    
    # Export GDS
    ring.write_gds("ring_filter.gds")
    
    # Run parameter sweep
    results = sweep_design_space()
    
    # Find optimal design
    optimal = max(results, key=lambda x: x['ER_dB'] if x['Q'] > 1500 else 0)
    
    print(f"Optimal Design:")
    print(f"  Radius: {optimal['radius']:.1f} µm")
    print(f"  Gap: {optimal['gap']:.3f} µm")
    print(f"  Q-factor: {optimal['Q']:.0f}")
    print(f"  Extinction Ratio: {optimal['ER_dB']:.1f} dB")

Project Extensions

Take your design further with these advanced features

Thermo-Optic Tuning

Add a heater layer in layout & simulate Δn(T). Demonstrates active control using coupled-mode theory. Essential for practical WDM systems.

Ring-Array Vernier Filter

Cascade rings of different radii for >40 dB rejection. Perfect for dense WDM applications requiring ultra-narrow filtering.

MZI Wavelength Locker

Use the ring as a feedback sensor in a control loop. Combines photonics with control theory - impressive for technical interviews!

Project Deliverables

📓

Jupyter Notebook

Complete Python script that generates GDS, runs parameter sweeps, and plots S-parameters. Fully documented with markdown explanations.

📊

Transmission Plots

Annotated figures showing Q-factor, extinction ratio, and FSR. Include both simulation results and fitted analytical models.

📄

Technical Report

One-page PDF summarizing specifications, field snapshots, and fit results. Professional format suitable for portfolio or technical review.

👁️

Eye Diagram Analysis

(Extra Credit) PIC-level eye-diagram comparing NRZ link performance with and without the filter block.

Learning Resources

AIM Photonics Virtual Lab

Browser-based applets for ring resonators and MZIs. Great for building intuition before diving into code.

Explore Virtual Lab →

Ansys Lumerical Tutorials

Traveling-wave MZM tutorial shows end-to-end multi-physics setup. Same workflow applies to ring resonators.

View Tutorial →

Open PDKs & Examples

ResearchGate thread links several open PDKs compatible with Meep/gdsfactory. Simulate realistic foundry layers!

Browse Resources →

Weekend Project Timeline

Friday Evening

Setup tools, create initial layout, run mode solver checks

Saturday Morning

FDTD parameter sweeps, optimize gap & radius

Saturday Afternoon

Extract metrics, build compact model, validate

Sunday Morning

Circuit-level verification, eye diagram analysis

Sunday Afternoon

Documentation, create report, optional extensions