Through silicon via

A through-silicon via (TSV) consists of one or more vertical signal vias that cuts through the main silicon layer in a wafer. They provide an alternative to traditional wire-bond layouts and allow the creation of densely packaged 3D integrated circuits.
In this notebook, we simulate the vertical transition of a CPW-connected TSV and characterize its insertion and return loss characteristics.
import matplotlib.pyplot as pltimport numpy as npimport flex_rf.tidy3d as rfimport flex_rf.web as web
rf.config.logging.level = "ERROR"Building the Simulation
Section titled “Building the Simulation”Key Parameters
Section titled “Key Parameters”Important geometry dimensions are defined below.
# Geometry dimensionslen_inf = 1e5 # Effective infinityR_TSV = 5 # TSV radiusP_TSV = 20 # TSV pitchG = 7 # CPW gapWS = 10 # CPW signal widthWG = 100 # CPW ground widthW_CPW = WS + 2 * (G + WG) # CPW full spanH = 100 # Silicon thicknessTL = 2 # SiO2 liner thicknessTM = 3 # Metal thickness
# Simulation dimensionssim_LX, sim_LY, sim_LZ = (600, 300, 450)We will perform a wideband sweep of 1-30 GHz.
# Frequencies and bandwidth(f_min, f_max) = (1e9, 30e9)f0 = (f_min + f_max) / 2freqs = np.linspace(f_min, f_max, 101)Medium and Structures
Section titled “Medium and Structures”The TSV comprises of two dielectric material types, silicon and silicon dioxide. The silicon dioxide layer encases the main silicon substrate as well as the vertical vias.
med_Si = rf.Medium(permittivity=11.7)med_SiO2 = rf.Medium(permittivity=3.9)med_metal = rf.LossyMetalMedium(conductivity=60, frequency_range=(f_min, f_max))The simulation geometry is defined below. We start with the dielectric layers.
# Dielectric layersgeom_sub = rf.Box.from_bounds( rmin=(-len_inf / 2, -len_inf / 2, -H), rmax=(len_inf / 2, len_inf / 2, 0))geom_liner = rf.Box.from_bounds( rmin=(-len_inf / 2, -len_inf / 2, -H - TL), rmax=(len_inf / 2, len_inf / 2, TL))For the TSV, we define a custom function.
# Create TSV geometrydef create_TSV_cylinders(xpos, ypos): """Create TSV cylinders for Si, SiO2, and metal layers at given x, y positions""" cyl_sub = rf.Cylinder(center=(xpos, ypos, -H / 2), axis=2, radius=R_TSV + TL, length=H) cyl_liner = rf.Cylinder(center=(xpos, ypos, -H / 2), axis=2, radius=R_TSV, length=H + 2 * TL) cyl_metal = rf.Cylinder( center=(xpos, ypos, -H / 2), axis=2, radius=R_TSV, length=H + TL * 2 + TM * 2 )
return [cyl_sub, cyl_liner, cyl_metal]The TSVs are created below, along with the SiO2 liner.
# Cut TSV holes from dielectric and create metal TSV cylindersgeoms_TSV_metal = []for ypos in [-P_TSV, 0, P_TSV]: cyl_sub, cyl_liner, cyl_metal = create_TSV_cylinders(0, ypos) geom_sub = geom_sub - cyl_sub geom_liner = geom_liner - cyl_liner geoms_TSV_metal += [cyl_metal]The CPW geometry is created below.
# Create CPW geometrydef create_CPW_geometry(x_start, x_end, zpos): """Create CPW geometry from start to end x-positions (x_start, x_end) at height zpos (relative to bottom boundary)""" sig = rf.Box.from_bounds(rmin=(x_start, -WS / 2, zpos), rmax=(x_end, WS / 2, zpos + TM)) gnd1 = rf.Box.from_bounds( rmin=(x_start, WS / 2 + G, zpos), rmax=(x_end, WS / 2 + G + WG, zpos + TM) ) gnd2 = rf.Box.from_bounds( rmin=(x_start, -WS / 2 - G - WG, zpos), rmax=(x_end, -WS / 2 - G, zpos + TM) )
return [sig, gnd1, gnd2]Finally, the geometry of all metallic structures are collected into a single GeometryGroup to facilitate processing.
# Collect CPW geometries (including TSV ) into a single GeometryGroupgeom_CPW_TSV = rf.GeometryGroup( geometries=create_CPW_geometry(-len_inf / 2, 0, -H - TL - TM) + create_CPW_geometry(0, len_inf / 2, TL) + geoms_TSV_metal)The Structure instances are defined below, ready for simulation.
# Create structuresstr_sub = rf.Structure(geometry=geom_sub, medium=med_Si)str_liner = rf.Structure(geometry=geom_liner, medium=med_SiO2)str_CPW_TSV = rf.Structure(geometry=geom_CPW_TSV, medium=med_metal)
# Full structure liststr_list_full = [str_liner, str_sub, str_CPW_TSV]Grid and Boundaries
Section titled “Grid and Boundaries”For accurate results, the grid should be more refined along the path of the signal, i.e. along the CPW signal trace and vertical vias. To this end, we use the LayerRefinementSpec to refine the metallic corners/edges in the top and bottom CPWs, and the MeshOverrideStructure to enforce a maximum cross-sectional grid size in the region occupied by each TSV.
# Parameter settings from LayerRefinementSpeclr_params = { "axis": 2, "min_steps_along_axis": 2, "corner_refinement": rf.GridRefinement(dl=TM / 2, num_cells=2),}
# Create layer refinement for top and bottom layerslr1 = rf.LayerRefinementSpec(center=(0, 0, TL + TM / 2), size=(len_inf, W_CPW, TM), **lr_params)lr2 = rf.LayerRefinementSpec( center=(0, 0, -H - TL - TM / 2), size=(len_inf, W_CPW, TM), **lr_params)# Refine box around signal TSVsrefine_box = rf.MeshOverrideStructure( geometry=rf.Box.from_bounds( rmin=(-R_TSV - TL, -WS / 2 - TL, -H - TL - TM), rmax=(R_TSV + TL, WS / 2 + TL, TL + TM) ), dl=(R_TSV / 6, R_TSV / 6, None),)refine_box2 = refine_box.updated_copy(geometry=refine_box.geometry.translated(0, P_TSV, 0))The overall grid specification is defined below.
grid_spec = rf.GridSpec.auto( wavelength=rf.C_0 / f_max, min_steps_per_sim_size=75, layer_refinement_specs=[lr1, lr2], override_structures=[refine_box, refine_box2],)Monitors
Section titled “Monitors”For visualization purposes, we define several field monitors below.
# Field monitorsmon_1 = rf.FieldMonitor( center=(0, 0, 0), size=(0, len_inf, len_inf), freqs=[f_min, f0, f_max], name="TSV x-plane",)mon_2 = rf.FieldMonitor( center=(0, (WS + G) / 2, 0), size=(len_inf, 0, len_inf), freqs=[f_min, f0, f_max], name="TSV y-plane",)mon_3 = rf.FieldMonitor( center=(0, 0, TL), size=(len_inf, len_inf, 0), freqs=[f_min, f0, f_max], name="TSV z-plane upper",)mon_4 = rf.FieldMonitor( center=(0, 0, -H - TL), size=(len_inf, len_inf, 0), freqs=[f_min, f0, f_max], name="TSV z-plane lower",)
# Full list of monitorsmonitor_list = [mon_1, mon_2, mon_3, mon_4]The excitation for this model will be generated by WavePort instances connected to the CPW on each layer. These are defined below.
# Port dimensionsX0, Y0, Z0 = (-200, 0, -H - TL - TM / 2) # Port 1 centerX1, Y1, Z1 = (200, 0, TL + TM / 2) # Port 2 centerw_port, h_port = (W_CPW - 15, 270) # Port size# Wave portsWP1 = rf.WavePort( center=(X0, Y0, Z0), size=(0, w_port, h_port), mode_spec=rf.MicrowaveModeSpec(target_neff=np.sqrt(6)), direction="+", name="WP1", absorber=False,)WP2 = WP1.updated_copy( center=(X1, Y1, Z1), direction="-", name="WP2",)Defining Simulation and TerminalComponentModeler
Section titled “Defining Simulation and TerminalComponentModeler”The base Simulation object and the TerminalComponentModeler are defined below.
sim = rf.Simulation( center=(0, 0, -H / 2), size=(sim_LX, sim_LY, sim_LZ), grid_spec=grid_spec, structures=str_list_full, monitors=[mon_1, mon_2, mon_3, mon_4], run_time=6e-10, shutoff=1e-7, symmetry=(0, 1, 0),)tcm = rf.TerminalComponentModeler( simulation=sim, ports=[WP1, WP2], freqs=freqs,)Visualization
Section titled “Visualization”Before running the simulation, it is a good idea to visualize the simulation domain and grid. The 2D layout of each plane is shown below.
# z-planes upper, mid, and lowerfig, ax = plt.subplots(3, 1, figsize=(8, 8), tight_layout=True)tcm.plot_sim(z=TL + TM / 2, ax=ax[0], monitor_alpha=0)tcm.plot_sim(z=-H / 2, ax=ax[1], monitor_alpha=0)tcm.plot_sim(z=-H - TL - TM / 2, ax=ax[2], monitor_alpha=0)for axis in ax: axis.set_ylim(-WS - G - WG, WS + G + WG) axis.set_xlim(-sim_LX / 2, sim_LX / 2)plt.show()![]()
We check the grid resolution around the TSV structures.
fig, ax = plt.subplots(1, 2, figsize=(10, 6), tight_layout=True)tcm.plot_sim(z=-H / 2, ax=ax[0], monitor_alpha=0)sim.plot_grid(z=-H / 2, ax=ax[0])ax[0].set_ylim(-40, 40)ax[0].set_xlim(-40, 40)
tcm.plot_sim(y=0, ax=ax[1], monitor_alpha=0)sim.plot_grid(y=0, ax=ax[1])ax[1].set_ylim(-120, 20)ax[1].set_xlim(-40, 40)plt.show()![]()
The region around each WavePort is shown below.
# Grid, CPW portsfig, ax = plt.subplots(1, 2, figsize=(10, 6), tight_layout=True)tcm.plot_port(port='WP1', ax=ax[0], monitor_alpha=0)tcm.plot_sim_grid(x=-200, ax=ax[0], hlim=(-50, 50), vlim=(-120, -80))tcm.plot_port(port='WP2', ax=ax[1], monitor_alpha=0)tcm.plot_sim_grid(x=200, ax=ax[1], hlim=(-50, 50), vlim=(-20, 20))plt.show()![]()
Running the Simulation
Section titled “Running the Simulation”tcm_data = web.run(tcm, task_name="TSV", path="data/tcm_data.hdf5", verbose=False)Results
Section titled “Results”Field Profile
Section titled “Field Profile”We load the field monitor data and plot the various 2D magnitude profiles below.
# Load simulation datasim_data = tcm_data.data["WP1@0"]# Field plotsfig, ax = plt.subplots(2, 2, figsize=(10, 8), tight_layout=True)f_plot = f0sim_data.plot_field("TSV x-plane", "E", val="abs", f=f_plot, ax=ax[0, 0])ax[0, 0].set_xlim(-100, 100)ax[0, 0].set_ylim(-150, 50)sim_data.plot_field("TSV y-plane", "E", val="abs", f=f_plot, ax=ax[0, 1])ax[0, 1].set_xlim(-200, 200)ax[0, 1].set_ylim(-150, 50)sim_data.plot_field("TSV z-plane upper", "E", val="abs", f=f_plot, ax=ax[1, 0])ax[1, 0].set_xlim(-200, 200)ax[1, 0].set_ylim(-100, 100)sim_data.plot_field("TSV z-plane lower", "E", val="abs", f=f_plot, ax=ax[1, 1])ax[1, 1].set_xlim(-200, 200)ax[1, 1].set_ylim(-100, 100)plt.show()![]()
S-parameters
Section titled “S-parameters”We calculate the S-matrix and plot the insertion and return losses below.
# Calculate S-matrix from TCM datasmat = tcm_data.smatrix()
# Convenience functions to access S_ijdef sparam(i, j): return np.conjugate(smat.data.isel(port_in=j - 1, port_out=i - 1))
def sparam_abs(i, j): return np.abs(sparam(i, j))
def sparam_dB(i, j): return 20 * np.log10(sparam_abs(i, j))fig, ax = plt.subplots(2, 1, figsize=(10, 8), tight_layout=True)ax[0].plot(freqs / 1e9, sparam_dB(1, 1), "r", label="|S11|$^2$")ax[0].set_title("Return loss")ax[1].plot(freqs / 1e9, sparam_dB(1, 2), "b", label="|S21|$^2$")ax[1].set_title("Insertion loss")for axis in ax: axis.legend() axis.grid() axis.set_xlabel("f (GHz)") axis.set_ylabel("dB")plt.show()![]()