Exemplo n.º 1
0
def get_potential(V_bias, n_eff):
    try:
        return tools.load(
            os.path.join(DATAFOLDER, 'pot_descr_%d_%d_%d_3D' %
                         (V_bias, n_eff, RESOLUTION)))
    except IOError:
        V_readout = 0.
        V_bi = -silicon.get_diffusion_potential(n_eff / 1e12, temperature=TEMP)

        mesh = get_mesh()
        potential = fields.calculate_3D_sensor_potential(
            mesh, WIDTH_X, WIDTH_Y, NPIXEL_X, NPIXEL_Y, RADIUS, ND, n_eff,
            V_bias, V_readout, V_bi)

        min_x, max_x, min_y, max_y = GEOM_DESCR.get_array_corners()
        nx = WIDTH_X * NPIXEL_X * 4
        ny = WIDTH_Y * NPIXEL_Y * 4

        pot_descr = fields.Description(
            potential,
            min_x=min_x,
            max_x=max_x,
            min_y=min_y,
            max_y=max_y,
            nx=nx,  # um res.
            ny=ny,  # um res.
            smoothing=SMOOTHING)

        tools.save(
            pot_descr,
            os.path.join(DATAFOLDER, 'pot_descr_%d_%d_%d_3D' %
                         (V_bias, n_eff, RESOLUTION)))

    return pot_descr
Exemplo n.º 2
0
def plot_diffusion_potential():
    n_eff = np.linspace(0.1, 100., 1000.)
    plt.clf()
    # Plot diffusion potential
    for temperature in [200, 250, 300, 350]:
        plt.plot(n_eff,
                 silicon.get_diffusion_potential(n_eff,
                                                 temperature=temperature),
                 linewidth=2.,
                 label='T = %d' % temperature)
    plt.title('Diffusion potential at thermal equilibrium in silicon')
    plt.xlabel('Effective doping concentration [$\mathrm{10^{12} / cm^3}}$]')
    plt.ylabel('Diffusion potential [$\mathrm{V}$]')
    plt.legend(loc=0)
    plt.grid()
    plt.savefig('DiffusionPotential.pdf', layout='tight')
Exemplo n.º 3
0
def get_potential(V_bias, n_eff, thickness):
    try:
        return tools.load(
            os.path.join(DATAFOLDER,
                         'pot_descr_%d_%d_%d' % (V_bias, n_eff, thickness)))
    except IOError:
        V_readout = 0.
        V_bi = -silicon.get_diffusion_potential(n_eff / 1e12, temperature=TEMP)

        #         mesh = MESH_1 if thickness == THICKNESS_1 else MESH_2
        mesh = get_mesh(n_pixel=NPIXEL,
                        width=WIDTH,
                        thickness=thickness,
                        resolution=RESOLUTION_1
                        if thickness == THICKNESS_1 else RESOLUTION_2)

        potential = fields.calculate_planar_sensor_potential(
            mesh=mesh,
            width=WIDTH,
            pitch=PITCH,
            n_pixel=NPIXEL,
            thickness=thickness,
            n_eff=n_eff,
            V_bias=V_bias,
            V_readout=V_readout,
            V_bi=V_bi)

        min_x = float(mesh.getFaceCenters()[0, :].min())
        max_x = float(mesh.getFaceCenters()[0, :].max())
        nx = WIDTH * NPIXEL
        ny = thickness

        pot_descr = fields.Description(potential,
                                       min_x=min_x,
                                       max_x=max_x,
                                       min_y=0,
                                       max_y=thickness,
                                       nx=nx,
                                       ny=ny,
                                       smoothing=SMOOTHING)

        tools.save(
            pot_descr,
            os.path.join(DATAFOLDER,
                         'pot_descr_%d_%d_%d' % (V_bias, n_eff, thickness)))

    return pot_descr
Exemplo n.º 4
0
def planar_sensor(n_eff,
                  V_bias,
                  V_readout=0.,
                  temperature=300,
                  n_pixel=9,
                  width=50.,
                  pitch=45.,
                  thickness=200.,
                  selection=None,
                  resolution=300.,
                  nx=None,
                  ny=None,
                  smoothing=0.05,
                  mesh_file='planar_mesh.msh'):
    ''' Create a planar_sensor sensor pixel array.

        Parameters
        ----------
        n_eff : number
            Effective doping concentration in :math:`\mathrm{\frac{1}{cm^3}}`
        V_bias : number
            Bias voltage in Volt
        V_readout : number
            Readout voltage in Volt
        temperature : float
            Temperature in Kelvin
        n_pixel : int
            Number of pixels
        width : number
            Width of one pixel in :math:`\mathrm{\mu m}`
        pitch : number
            Pitch (redout implant width) of one pixel in :math:`\mathrm{\mu m}`
        thickness : number
            Thickness of the sensor in :math:`\mathrm{\mu m}`
        selection : string
            Selects if the weighting potential / potentials or both are
            calculated.
            If not set: calculate weighting potential and drift potential
            If drift: calculate drift potential only
            If weighting: calculate weighting potential only
        resolution : number
            Mesh resolution. Should lead to > 200000 mesh points for exact
            results.
        nx : number
            Interpolation points in x for the potentials and fields
        ny : number
            Interpolation points in y for the potentials and fields
        smoothing : number
            Smoothing parameter for the potential. Higher number leads to
            more smooth looking potential, but be aware too much smoothing
            leads to wrong results!
        mesh_file : str
            File name of the created mesh file

        Returns
        -----
        Two scarce.fields.Description objects for the weighting potential and
        potential if no specified selection.
    '''

    # Create mesh of the sensor and stores the result
    # The created file can be viewed with any mesh viewer (e.g. gmsh)
    mesh = geometry.mesh_planar_sensor(n_pixel=n_pixel,
                                       width=width,
                                       thickness=thickness,
                                       resolution=resolution,
                                       filename=mesh_file)

    min_x = float(mesh.getFaceCenters()[0, :].min())
    max_x = float(mesh.getFaceCenters()[0, :].max())

    # Set um resolution grid
    if not nx:
        nx = width * n_pixel
    if not ny:
        ny = thickness

    if not selection or 'drift' in selection:
        V_bi = -silicon.get_diffusion_potential(n_eff, temperature)
        # Numerically solve the Laplace equation on the mesh
        potential = fields.calculate_planar_sensor_potential(
            mesh=mesh,
            width=width,
            pitch=pitch,
            n_pixel=n_pixel,
            thickness=thickness,
            n_eff=n_eff,
            V_bias=V_bias,
            V_readout=V_readout,
            V_bi=V_bi)
        pot_descr = fields.Description(potential,
                                       min_x=min_x,
                                       max_x=max_x,
                                       min_y=0,
                                       max_y=thickness,
                                       nx=nx,
                                       ny=ny,
                                       smoothing=smoothing)
        if selection and 'drift' in selection:
            return pot_descr

    if not selection or 'weighting' in selection:
        # Numerically solve the Poisson equation on the mesh
        w_potential = fields.calculate_planar_sensor_w_potential(
            mesh=mesh,
            width=width,
            pitch=pitch,
            n_pixel=n_pixel,
            thickness=thickness)
        pot_w_descr = fields.Description(w_potential,
                                         min_x=min_x,
                                         max_x=max_x,
                                         min_y=0,
                                         max_y=thickness,
                                         nx=nx,
                                         ny=ny,
                                         smoothing=smoothing)
        if selection and 'weighting' in selection:
            return pot_w_descr

    return pot_w_descr, pot_descr
Exemplo n.º 5
0
def sensor_3D(n_eff,
              V_bias,
              V_readout=0.,
              temperature=300,
              n_pixel_x=3,
              n_pixel_y=3,
              width_x=250.,
              width_y=50.,
              radius=6.,
              nD=2,
              selection=None,
              resolution=80.,
              nx=None,
              ny=None,
              smoothing=0.1,
              mesh_file='3D_mesh.msh'):
    ''' Create a 3D sensor pixel array.

        Parameters
        ----------
        n_eff : number
            Effective doping concentration in :math:`\mathrm{\frac{1}{cm^3}}`
        V_bias : number
            Bias voltage in Volt
        V_readout : number
            Readout voltage in Volt
        temperature : float
            Temperature in Kelvin
        n_pixel_x : int
            Number of pixels in x
        n_pixel_y : int
            Number of pixels in y
        width_x : number
            Width of one pixel in x in :math:`\mathrm{\mu m}`
        width_y : number
            Width of one pixel in y in :math:`\mathrm{\mu m}`
        radius : number
            Radius of readout and biasing columns in :math:`\mathrm{\mu m}`
        nD : int
            Number of readout columns per pixel
        selection : string
            Selects if the weighting potential / potentials or both are
            calculated.
            If not set: calculate weighting potential and drift potential
            If drift: calculate drift potential only
            If weighting: calculate weighting potential only
        resolution : number
            Mesh resolution. Should lead to > 300000 mesh points for exact
            results.
        nx : number
            Interpolation points in x for the potentials and fields
        ny : number
            Interpolation points in y for the potentials and fields
        smoothing : number
            Smoothing parameter for the potential. Higher number leads to
            more smooth looking potential, but be aware too much smoothing
            leads to wrong results!
        mesh_file : str
            File name of the created mesh file

        Returns
        -----
        Two scarce.fields.Description objects for the weighting potential and
        potential if not specified selection and a geometry desciption object.
    '''

    if not nx:
        nx = width_x * n_pixel_x * 4
    if not ny:
        ny = width_y * n_pixel_y * 4

    mesh = geometry.mesh_3D_sensor(width_x=width_x,
                                   width_y=width_y,
                                   n_pixel_x=n_pixel_x,
                                   n_pixel_y=n_pixel_y,
                                   radius=radius,
                                   nD=nD,
                                   resolution=resolution,
                                   filename=mesh_file)

    # Describe the 3D sensor array
    geom_descr = geometry.SensorDescription3D(width_x, width_y, n_pixel_x,
                                              n_pixel_y, radius, nD)
    min_x, max_x, min_y, max_y = geom_descr.get_array_corners()

    if not selection or 'drift' in selection:
        V_bi = -silicon.get_diffusion_potential(n_eff, temperature)
        potential = fields.calculate_3D_sensor_potential(
            mesh, width_x, width_y, n_pixel_x, n_pixel_y, radius, nD, n_eff,
            V_bias, V_readout, V_bi)
        pot_descr = fields.Description(
            potential,
            min_x=min_x,
            max_x=max_x,
            min_y=min_y,
            max_y=max_y,
            nx=nx,  # um res.
            ny=ny,  # um res.
            smoothing=smoothing)
        if selection and 'drift' in selection:
            return pot_descr, geom_descr

    if not selection or 'weighting' in selection:
        w_potential = fields.calculate_3D_sensor_w_potential(mesh,
                                                             width_x,
                                                             width_y,
                                                             n_pixel_x,
                                                             n_pixel_y,
                                                             radius,
                                                             nD=nD)
        pot_w_descr = fields.Description(w_potential,
                                         min_x=min_x,
                                         max_x=max_x,
                                         min_y=min_y,
                                         max_y=max_y,
                                         nx=nx,
                                         ny=ny,
                                         smoothing=smoothing)
        if selection and 'weighting' in selection:
            return pot_w_descr, geom_descr

    return pot_w_descr, pot_descr, geom_descr
Exemplo n.º 6
0
def sensor_planar():
    # Sensor parameters
    n_eff = 6.2e12
    n_pixel = 9
    width = 50.
    pitch = 30.
    thickness = 250.
    smoothing = 0.05
    resolution = 287
    temperature = 300.
    V_bias = -300.
    V_readout = 0.

    # Create sensor
    pot_descr = sensor.planar_sensor(
        n_eff=n_eff,
        V_bias=V_bias,
        V_readout=V_readout,
        temperature=temperature,
        n_pixel=n_pixel,
        width=width,
        pitch=pitch,
        thickness=thickness,
        # Calculate drift potential only
        # to safe time
        selection='drift',
        resolution=resolution,
        # Might have to be adjusted when changing
        # the geometry
        smoothing=smoothing)

    # Build in voltage needed for analytical solution
    V_bi = -silicon.get_diffusion_potential(n_eff, temperature)

    # Plot analytical / numerical result with depletion region in 1D
    y = np.linspace(0, thickness, 1000)
    x = np.zeros_like(y)

    plt.plot(y,
             pot_descr.get_potential(x, y),
             label='Potential, numerical',
             linewidth=2)
    pot_masked = np.ma.masked_array(pot_descr.get_potential(x, y),
                                    mask=pot_descr.get_depl_mask(x, y))
    plt.plot(y, pot_masked, label='Potential, numerical, depl.', linewidth=2)
    plt.plot(
        [pot_descr.get_depletion(x[500]),
         pot_descr.get_depletion(x[500])],
        plt.ylim(),
        label='Depletion, numerical ',
        linewidth=2)
    plt.plot(y,
             fields.get_potential_planar_analytic_1D(y,
                                                     V_bias=V_bias + V_bi,
                                                     V_readout=V_readout,
                                                     n_eff=n_eff,
                                                     D=thickness),
             '--',
             label='Potential, analytical',
             linewidth=2)
    plt.plot([
        silicon.get_depletion_depth(np.abs(V_bias), n_eff / 1e12, temperature),
        silicon.get_depletion_depth(np.abs(V_bias), n_eff / 1e12, temperature)
    ],
             plt.ylim(),
             '--',
             label='Depletion, analytical',
             linewidth=2)
    plt.ylabel('Potential [V]')
    plt.legend(loc=1)
    plt.ylabel('Potential [V]')
    ax2 = plt.gca().twinx()
    ax2.plot(y,
             pot_descr.get_field(x, y)[1],
             '--',
             label='Field, numerical',
             linewidth=2)
    ax2.plot(y,
             fields.get_electric_field_analytic(x,
                                                y,
                                                V_bias=V_bias,
                                                V_readout=V_readout,
                                                n_eff=n_eff,
                                                D=thickness)[1],
             '--',
             label='Field, analytical',
             linewidth=2)
    plt.ylabel('Field [V/cm]')
    plt.legend(loc=4)
    plt.ylabel('Field [V/cm]')
    plt.title('Potential in a not fully depleted planar sensor')
    plt.xlabel('Position [um]')

    plt.grid()
    plt.show()

    # Plot numerical result in 2D
    plot.plot_planar_sensor(
        width=width,
        pitch=pitch,
        thickness=thickness,
        n_pixel=n_pixel,
        # Weighting field = 0 at backplane
        V_backplane=V_bias,
        # Weighting field = 1 at readout
        V_readout=V_readout,
        pot_func=pot_descr.get_potential,
        field_func=pot_descr.get_field,
        depl_func=pot_descr.get_depletion,
        # Comment in if you want to see the mesh
        mesh=None,  # potential.mesh,
        title='Planar sensor potential')