Skip to content

Commit

Permalink
Moved optika.sensors.quantum_yield_ideal() to a different source file.
Browse files Browse the repository at this point in the history
  • Loading branch information
byrdie committed Jan 12, 2024
1 parent 7f6ae13 commit 670764e
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 93 deletions.
1 change: 1 addition & 0 deletions optika/sensors/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from ._materials import *
from ._sensors import *
1 change: 1 addition & 0 deletions optika/sensors/_materials/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._materials import *
83 changes: 83 additions & 0 deletions optika/sensors/_materials/_materials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import numpy as np
import astropy.units as u
import named_arrays as na

__all__ = [
"energy_bandgap",
"energy_electron_hole",
"quantum_yield_ideal",
]

energy_bandgap = 1.12 * u.eV
"""the bandgap energy of silicon"""

energy_electron_hole = 3.65 * u.eV
"""
the high-energy limit of the energy required to create an electron-hole pair
in silicon at room temperature
"""


def quantum_yield_ideal(
wavelength: u.Quantity | na.AbstractScalar,
) -> na.AbstractScalar:
r"""
Calculate the ideal quantum yield of a silicon detector for a given
wavelength.
Parameters
----------
wavelength
the wavelength of the incident photons
Notes
-----
The quantum yield is the number of electron-hole pairs produced per photon.
The ideal quantum yield is given in :cite:t:`Janesick2001` as:
.. math::
\text{QY}(\epsilon) = \begin{cases}
0, & \epsilon < E_\text{g}\\
1, & E_\text{g} \leq \epsilon < E_\text{e-h} \\
E_\text{e-h} / \epsilon, & E_\text{e-h} \leq \epsilon,
\end{cases},
where :math:`\epsilon` is the energy of the incident photon,
:math:`E_\text{g} = 1.12\;\text{eV}` is the bandgap energy of silicon,
and :math:`E_\text{e-h} = 3.65\;\text{eV}` is the energy required to
generate 1 electron-hole pair in silicon at room temperature.
Examples
--------
Plot the quantum yield vs wavelength
.. jupyter-execute::
import matplotlib.pyplot as plt
import astropy.units as u
import named_arrays as na
import optika
# Define an array of wavelengths
wavelength = na.geomspace(100, 100000, axis="wavelength", num=101) << u.AA
# Compute the quantum yield
qy = optika.sensors.quantum_yield_ideal(wavelength)
# Plot the quantum yield vs wavelength
fig, ax = plt.subplots()
na.plt.plot(wavelength, qy, ax=ax);
ax.set_xscale("log");
ax.set_xlabel(f"wavelength ({wavelength.unit:latex_inline})");
ax.set_ylabel("quantum yield");
"""
energy = wavelength.to(u.eV, equivalencies=u.spectral())

result = energy / energy_electron_hole
result = np.where(energy > energy_electron_hole, result, 1)
result = np.where(energy > energy_bandgap, result, 0)

return result
20 changes: 20 additions & 0 deletions optika/sensors/_materials/_materials_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pytest
import numpy as np
import astropy.units as u
import named_arrays as na
import optika


@pytest.mark.parametrize(
argnames="wavelength,result_expected",
argvalues=[
(1.0 * u.eV, 0),
(2.0 * u.eV, 1),
(2 * optika.sensors.energy_electron_hole, 2),
],
)
def test_quantum_yield_ideal(
wavelength: u.Quantity | na.AbstractScalar, result_expected: na.AbstractScalar
):
result = optika.sensors.quantum_yield_ideal(wavelength)
assert np.all(result == result_expected)
78 changes: 0 additions & 78 deletions optika/sensors/_sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
import optika

__all__ = [
"energy_bandgap",
"energy_electron_hole",
"quantum_yield_ideal",
"quantum_efficiency_effective",
"AbstractImagingSensor",
"AbstractCCD",
Expand All @@ -21,81 +18,6 @@
MaterialT = TypeVar("MaterialT", bound=optika.materials.AbstractMaterial)


energy_bandgap = 1.12 * u.eV
"""the bandgap energy of silicon"""

energy_electron_hole = 3.65 * u.eV
"""
the high-energy limit of the energy required to create an electron-hole pair
in silicon at room temperature
"""


def quantum_yield_ideal(
wavelength: u.Quantity | na.AbstractScalar,
) -> na.AbstractScalar:
r"""
Calculate the ideal quantum yield of a silicon detector for a given
wavelength.
Parameters
----------
wavelength
the wavelength of the incident photons
Notes
-----
The quantum yield is the number of electron-hole pairs produced per photon.
The ideal quantum yield is given in :cite:t:`Janesick2001` as:
.. math::
\text{QY}(\epsilon) = \begin{cases}
0, & \epsilon < E_\text{g}\\
1, & E_\text{g} \leq \epsilon < E_\text{e-h} \\
E_\text{e-h} / \epsilon, & E_\text{e-h} \leq \epsilon,
\end{cases},
where :math:`\epsilon` is the energy of the incident photon,
:math:`E_\text{g} = 1.12\;\text{eV}` is the bandgap energy of silicon,
and :math:`E_\text{e-h} = 3.65\;\text{eV}` is the energy required to
generate 1 electron-hole pair in silicon at room temperature.
Examples
--------
Plot the quantum yield vs wavelength
.. jupyter-execute::
import matplotlib.pyplot as plt
import astropy.units as u
import named_arrays as na
import optika
# Define an array of wavelengths
wavelength = na.geomspace(100, 100000, axis="wavelength", num=101) << u.AA
# Compute the quantum yield
qy = optika.sensors.quantum_yield_ideal(wavelength)
# Plot the quantum yield vs wavelength
fig, ax = plt.subplots()
na.plt.plot(wavelength, qy, ax=ax);
ax.set_xscale("log");
ax.set_xlabel(f"wavelength ({wavelength.unit:latex_inline})");
ax.set_ylabel("quantum yield");
"""
energy = wavelength.to(u.eV, equivalencies=u.spectral())

result = energy / energy_electron_hole
result = np.where(energy > energy_electron_hole, result, 1)
result = np.where(energy > energy_bandgap, result, 0)

return result


def quantum_efficiency_effective(
wavelength: u.Quantity | na.AbstractScalar,
direction: na.AbstractCartesian3dVectorArray,
Expand Down
15 changes: 0 additions & 15 deletions optika/sensors/_tests/test_sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,6 @@
import optika


@pytest.mark.parametrize(
argnames="wavelength,result_expected",
argvalues=[
(1.0 * u.eV, 0),
(2.0 * u.eV, 1),
(2 * optika.sensors.energy_electron_hole, 2),
],
)
def test_quantum_yield_ideal(
wavelength: u.Quantity | na.AbstractScalar, result_expected: na.AbstractScalar
):
result = optika.sensors.quantum_yield_ideal(wavelength)
assert np.all(result == result_expected)


@pytest.mark.parametrize(
argnames="wavelength",
argvalues=[
Expand Down

0 comments on commit 670764e

Please sign in to comment.