Transient and DC simulation of an illuminated photodiode

Hi @Frangipani,

I have modified the example gmsh_diode3d.py which shows how to formulate circuit elements and connect them to the device (see below). In combination with the optical carrier generation from Ssac and transient in generation term, it should be all you need. I have succesfully simulated an image sensor with this approach.

# Copyright 2013 DEVSIM LLC
#
# SPDX-License-Identifier: Apache-2.0
from devsim import *
from devsim.python_packages.simple_physics import *
import devsim.python_packages.Klaassen as kla
import diode_common


def print_currents(device, contact):
    """
    Print out contact currents
    """
    ece_name = "ElectronContinuityEquation"
    hce_name = "HoleContinuityEquation"
    contact_bias_name = GetContactBiasName(contact)
    electron_current= get_contact_current(device=device, contact=contact, equation=ece_name)
    hole_current    = get_contact_current(device=device, contact=contact, equation=hce_name)
    total_current   = electron_current + hole_current
    if contact in ["top", "bot"]:
        voltage = get_circuit_node_value(solution='dcop', node=f"n{contact}")
    else:
        voltage = get_parameter(device=device, name=GetContactBiasName(contact))
    data = (voltage, electron_current, hole_current, total_current)
    print(f"{contact:10}{voltage:+.3e}\t{electron_current:+.3e}\t{hole_current:+.3e}\t{total_current:+.3e}")
    return data


def print_all_currents():
    """
    Prints all currents to console and returns outmap of values. !Currently only functional when all contacts are
    silicon contacts!
    :return:
    """
    print("\nSolution:")
    print("{0:10}{1:15}{2:12}{3:12}{4:10}".format("Contact", "Voltage", "Electron", "Hole", "Total"))
    print("                         Current     Current     Current")
    device_list = get_device_list()
    for device in device_list:
        contact_list = get_contact_list(device=device)
        outmap = {}
        for contact in contact_list:
                outmap[contact] = print_currents(device, contact)
    print_circuit_solution()
    return outmap


def print_circuit_solution():
    print('Circuit Solution')
    nodes = get_circuit_node_list()
    for node in get_circuit_node_list():
        r = get_circuit_node_value(solution='dcop', node=node)
        print("%s\t%1.15e" % (node, r))


set_parameter(name="debug_level", value="info")
#set_parameter(name="threads_available", value=8)
#set_parameter(name="threads_task_size", value=1024)
set_parameter(name="extended_solver", value="True")
set_parameter(name="extended_model", value="True")
set_parameter(name="extended_equation", value="True")

device="diode3d"
region="Bulk"

diode_common.Create3DGmshMesh(device, region)

# this is the devsim format
write_devices (file="gmsh_diode3d_out.msh")

diode_common.SetParameters(device=device, region=region)

v_source_top = circuit_element(name="VSourceTop", n1="ntop_res", n2="GND", value=0.0)
v_source_bot = circuit_element(name="VSourceBot", n1="nbot_res", n2="GND", value=0.0)

r_source_top = circuit_element(name="RSourceTop", n1="ntop_res", n2="ntop", value=1.0)
r_source_bot = circuit_element(name="RSourceBot", n1="nbot_res", n2="nbot", value=1.0)

c_source_top = circuit_element(name="CSourceTop", n1="ntop", n2="GND", value=1e-12)


# Connecting circuit to device ntop->top, nbot->bot, top and bot are defined in the mesh
circuit_node_alias(node="ntop", alias="top_bias")
circuit_node_alias(node="nbot", alias="bot_bias")

####
#### NetDoping
####
node_model(device=device, region=region, name="Acceptors", equation="1.0e18*step(0.5e-5-z);")
node_model(device=device, region=region, name="Donors",    equation="1.0e18*step(z-0.5e-5);")
node_model(device=device, region=region, name="NetDoping", equation="Donors-Acceptors;")
node_model(device=device, region=region, name="AbsDoping", equation="abs(NetDoping)")
node_model(device=device, region=region, name="logDoping", equation="log(AbsDoping)/log(10)")

diode_common.InitialSolution(device, region, circuit_contacts=["top", "bot"])


####
#### Initial DC solution
####
solve(type="transient_dc", absolute_error=1e-10, relative_error=1e-12, maximum_iterations=30)

###
### Drift diffusion simulation at equilibrium
###
diode_common.DriftDiffusionInitialSolution(device, region, circuit_contacts=["top", "bot"])
kla.Set_Mobility_Parameters(device, region)
kla.Klaassen_Mobility(device, region)

solve(type="transient_dc", absolute_error=1e-10, relative_error=1e-9, maximum_iterations=50)

v = -0.1
while v > -3.01:
    circuit_alter(name="VSourceTop", value=v)
    solve(type="transient_bdf1", absolute_error=1.0, relative_error=1e-09,
          maximum_iterations=100, tdelta=1e-8, charge_error=1.0)
    print_all_currents()
    v -= 0.1

print("\n\n\nSteady State: -----------------------------------------------------------")
for i in range(50):
    solve(type="transient_bdf1", absolute_error=1.0, relative_error=1e-09,
              maximum_iterations=30, tdelta=1e-8, charge_error=1.0)
    print_all_currents()

2 Likes