Strona główna Przykłady Zrzuty ekranu Instrukcja obsługi Logo Bluesky. YouTube ☰
OghmaNano Platforma do symulacji wielofizycznych procesów zachodzących w optoelektronicznych urządzeniach i systemach fotonicznych. POBIERZ Przewodnik szybkiego uruchomienia

Widma emisyjne w OghmaNano

Widmo emisyjne opisuje, w jaki sposób światło emitowane przez dany materiał rozkłada się w zależności od długości fali. Firma OghmaNano przechowuje te widma w ramach swojej bazy danych materiałów, gdzie można je przeglądać, importować lub aktualizować. Na tej stronie wyjaśniono, co przedstawia widmo emisyjne, jak jest przechowywane i importowane, a na koniec, jak wygenerować przybliżone widmo za pomocą języka Python, gdy brak dostępnych danych pomiarowych.

1. Co to jest widmo emisyjne?

Gdy elektrony i dziury rekombinują w procesie promieniowania, emitowane są fotony o różnych energiach, a nie tylko o jednej, określonej długości fali. Widmo emisji opisuje względną intensywność tego światła w funkcji długości fali. Może pochodzić z eksperymentu, takiego jak fotoluminescencja (PL) lub elektroluminescencja (EL), lub z modelu teoretycznego. Widmo to nie jest tym samym, co współczynnik absorpcji lub współczynnik załamania materiału.

Kształt widma zależy od struktury elektronicznej półprzewodnika, temperatury, składu oraz, w przypadku rzeczywistego urządzenia, od koncentracji nośników ładunku i efektów optycznych. Znormalizowane widmo emisji przedstawia względny rozkład długości fal, a nie bezwzględną moc optyczną ani efektywność diody LED.

2. Widma emisyjne w bazie danych materiałów

Każdy materiał ma swój własny katalog w bazie danych OghmaNano Materials. Gdy dostępne są dane dotyczące emisji, są one zapisywane w pliku o nazwie emission.csv obok plików takich jak alpha.csv i n.csv. Na przykład, folder materiału może zawierać:

materials/
  GaAs/
    emission.csv
    alpha.csv
    n.csv

Baza danych materiałów, z której korzystają symulacje, znajduje się w katalogu użytkownika oghma_local/materials. Opis struktury katalogu i formatów plików materiałów można znaleźć w dokumencie Baza danych materiałów: Część C – Sposób przechowywania materiałów. Wprowadzenie do przeglądania i edycji materiałów znajduje się w dokumencie Baza danych materiałów: Część A.

Plik emission.csv zawiera informacje o długości fali w metrach oraz o względnej intensywności emisji wyrażonej w jednostkach umownych. Pliki w formacie OghmaNano zawierają również nagłówek metadanych; wartość y_len w nagłówku określa liczbę par danych dotyczących długości fali i intensywności, które występują po nim.

3. Importowanie zmierzonych widm emisji.

Jeśli dostępne są dane dotyczące zmierzonej fotoluminescencji (PL) lub elektroluminescencji (EL), preferowane jest ich wykorzystanie zamiast przybliżonego, generowanego spektrum, pod warunkiem że pomiary są odpowiednie dla danego materiału i przeznaczonego urządzenia. Otwórz odpowiedni materiał w bazie danych materiałów, wybierz jego spektrum emisji i użyj funkcji importu danych, aby zaimportować zmierzoną krzywą. Ogólny proces importowania zbioru danych składającego się z dwóch kolumn, wyboru jednostek długości fali i przeglądania przekonwertowanych wartości opisano w Baza danych materiałów: Część A – Import danych.

Jednostki: Zapisane wartości długości fali podawane są w metrach, nawet jeśli wykres jest wyświetlany w nanometrach. Do reprezentacji danych dotyczących kształtu widma emisji należy użyć znormalizowanej intensywności (jednostki umowne). Po zaimportowaniu lub wygenerowaniu widma należy sprawdzić metadane pliku oraz liczbę punktów.

4. Szacowanie widm emisji, gdy brak dostępnych danych pomiarowych.

Jeśli nie dysponujemy odpowiednim, zmierzonym widmem, poniższy skrypt w języku Python może wygenerować tymczasowe, znormalizowane widmo emisji półprzewodnika. Wykorzystuje on uproszczony model termicznego przejścia między pasmami dla materiałów o bezpośredniej przerwie energetycznej:

\(S_E(E) \propto \sqrt{E-E_g}\,\exp[-(E-E_g)/(k_B T)]\) dla \(E \geq E_g\).

W tym wzorze \(E_g\) oznacza przerwę energetyczną, a \(T\) – temperaturę. Skrypt przekształca obliczony profil emisji w dziedzinie energii na intensywność w jednostce długości fali, normalizuje jego wartość maksymalną do wartości 1 i zapisuje emission.csv w tym samym formacie metadanych i danych, którego używa OghmaNano. Domyślnie generuje 2036 punktów odpowiadających zależności długości fali od intensywności przy temperaturze 300 K.

Dostarczony skrypt tworzy jeden katalog dla każdego z 29 różnych materiałów półprzewodnikowych, w tym GaAs, AlGaAs, GaN, InGaN, InP i InGaAs. Wartości szerokości pasma energetycznego materiałów stanowią przykładowe wartości początkowe; w przypadku stopów, których właściwości zależą od składu, wygenerowane spektrum reprezentuje tylko jeden nominalny skład.

Kiedy można je stosować? Wykorzystaj wygenerowane krzywe jako przykładowe profile emisji, szczególnie do testowania systemu pomiaru emisji lub do momentu, gdy dostępne będą lepsze dane lub możliwość przeprowadzenia obliczeń opartych na strukturze pasmowej. Nie są to zmierzone widma i nie należy ich traktować jako ilościowych prognoz dotyczących konkretnej diody LED.

Model ten nie uwzględnia zjawiska kwantowego ograniczenia w warstwach półprzewodnikowych, nieuporządkowania w stopach, właściwości eksytonowych, emisji związanej z defektami, naprężeń ani optycznego sprzężenia. Jest szczególnie nieodpowiedni do analizy przejść w materiałach o pośredniej przerwie energetycznej, w tym w przypadku GaP: generowana przez niego krzywa przedstawia jedynie przykładowe przejście bezpośrednie, a nie typową emisję diody LED wykonanej z GaP.

5. Przykład: generowanie widm emisyjnych za pomocą języka Python.

Zapisz poniższy kod jako generate_emission_spectra.py i uruchom go:

python3 generate_emission_spectra.py

Domyślny folder wyjściowy to emission_generated. Aby wybrać inny folder lub zmienić liczbę punktów:

python3 generate_emission_spectra.py --output my_emission_database --points 2036

Aby zmienić temperaturę pracy lub użyć własnych wartości napięć referencyjnych:

python3 generate_emission_spectra.py --temperature 300 --bandgap-file bandgaps.json

Przykładowy plik bandgaps.json wygląda następująco:

{
  "GaAs": 1.424,
  "AlGaAs": 1.80,
  "InGaN": 2.75
}

Przed umieszczeniem odpowiednich plików emission.csv w odpowiednich folderach materiałów należy przeanalizować uzyskane widma. Wartości przerw energetycznych w tym skrypcie są określane ręcznie i stanowią wartości reprezentatywne; skrypt nie wykorzystuje skryptów materiałowych Lua do ich obliczania.

6. Pełny kod źródłowy w języku Python.

Poniżej znajduje się kompletny kod generatora, wykorzystujący wyłącznie standardową bibliotekę Pythona. Skopiuj kod i wklej go do lokalnego pliku Pythona.

Wyświetl kompletny generator spektrum emisyjnego w języku Python.
#!/usr/bin/env python3
"""Generate illustrative bulk band-edge emission.csv files for OghmaNano.

No external Python dependencies. Each directory contains a 2036-point
OghmaNano-format emission.csv. Spectra are normalised per wavelength and
are NOT measured or k.p-calculated spectra. Alloy bandgaps below represent
one nominal composition only; edit MATERIALS or use --bandgap-file.
"""
import argparse
import json
import math
from pathlib import Path

# Representative, approximate 300 K bulk DIRECT-transition gaps (eV).
# NOT universal values for alloys. Entries such as AlInP and AlInAs may be
# indirect at common compositions: their curves are illustrative ONLY.
# One directory per unique material; InSb was duplicated in the supplied list.
MATERIALS = {
    "InP":       (1.344, "InP/InP.lua"),
    "GaP":       (2.78,  "GaP/GaP.lua"),  # direct transition; GaP fundamental gap is indirect!
    "AlGaInP":   (2.05,  "AlGaInP.lua"),
    "GaAs":      (1.424, "GaAs/GaAs.lua"),
    "AlInP":     (2.35,  "AlInP.lua"),  # illustrative; verify direct-gap composition
    "InSb":      (0.17,  "InSb/InSb.lua"),
    "GaSb":      (0.726, "GaSb/GaSb.lua"),
    "CdS":       (2.42,  "CdS/CdS.lua"),
    "GaN":       (3.40,  "GaN/GaN.lua"),
    "AlN":       (6.03,  "AlN.lua"),
    "ZnS":       (3.68,  "ZnS.lua"),
    "InAs":      (0.354, "InAs/InAs.lua"),
    "AlGaAs":    (1.80,  "AlGaAs/AlGaAs.lua"),  # nominal Al x~0.3
    "InAsP":     (0.95,  "InAsP.lua"),
    "InGaAsP":   (0.80,  "InGaAsP.lua"),
    "AlInAs":    (1.45,  "AlInAs.lua"), # composition-dependent and possibly indirect
    "GaAsP":     (1.90,  "GaAsP.lua"),
    "InGaAs":    (0.75,  "InGaAs/InGaAs.lua"), # nominal In0.53Ga0.47As
    "ZnTe":      (2.26,  "ZnTe.lua"),
    "InGaN":     (2.75,  "InGaN.lua"),
    "GaInNAs":   (0.95,  "GaInNAs.lua"),
    "InGaP":     (1.90,  "InGaP.lua"),
    "GaInAs":    (0.75,  "GaInAs.lua"),
    "InN":       (0.69,  "InN.lua"),
    "AlGaN":     (4.43,  "AlGaN.lua"),
    "AlGaInAs":  (0.80,  "AlGaInAs.lua"),
    "CdSe":      (1.74,  "CdSe.lua"),
    "ZnSe":      (2.70,  "ZnSe.lua"),
    "CdTe":      (1.50,  "CdTe/CdTe.lua"),
}

HC_EV_NM = 1239.8419843320026
KB_EV_K = 8.617333262145e-5


def make_spectrum(eg, temp, points):
    """3D nondegenerate direct-gap model, intensity per unit wavelength.

    S_E(E) ~ sqrt(E-Eg)*exp(-(E-Eg)/kT), E>=Eg.
    Convert using dE/dlambda ~ 1/lambda**2, then peak-normalise.
    Span covers Eg to Eg + max(0.35 eV, 12 kT); wavelength increases.
    """
    kt = KB_EV_K * temp
    upper = eg + max(0.35, 12.0 * kt)
    lo_nm = HC_EV_NM / upper
    hi_nm = HC_EV_NM / eg
    values = []
    for i in range(points):
        wavelength_nm = lo_nm + (hi_nm - lo_nm) * i / (points - 1)
        e = HC_EV_NM / wavelength_nm
        de = max(0.0, e - eg)
        intensity = math.sqrt(de) * math.exp(-de / kt) / (wavelength_nm * wavelength_nm)
        values.append((wavelength_nm * 1e-9, intensity))
    top = max(v for _, v in values)
    return [(lam, value / top) for lam, value in values]


def generate(out, material, eg, lua_path, temp, points):
    folder = out / material
    folder.mkdir(parents=True, exist_ok=True)
    metadata = {
        "title": "Illustrative band-edge emission of " + material,
        "type": "xy",
        "y_label": "Wavelength",
        "data_label": "Intensity",
        "y_units": "nm",
        "y_mul": 1e9,
        "data_units": "au",
        "icon": "spectra_file",
        "time ": 0.0,
        "Vexternal": 0.0,
        "x_len": 1,
        "y_len": points,
        "z_len": 1,
        "cols": "yd",
    }
    values = make_spectrum(eg, temp, points)
    path = folder / "emission.csv"
    with path.open("w", encoding="utf-8", newline="\n") as f:
        f.write("#oghma_csv " + json.dumps(metadata, ensure_ascii=False, separators=(",", ":")) + "*\n")
        for lam, value in values:
            f.write(f"{lam:.12e}\t{value:.12e}\n")
    return path


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--output", type=Path, default=Path("emission_generated"))
    parser.add_argument("--points", type=int, default=2036)
    parser.add_argument("--temperature", type=float, default=300.0)
    parser.add_argument("--bandgap-file", type=Path,
                        help='Optional JSON map e.g. {"GaAs":1.424,"AlGaAs":1.80} to override nominal gaps')
    args = parser.parse_args()
    if args.points < 3 or args.temperature <= 0:
        parser.error("--points must be >=3 and --temperature must be positive")
    gap_overrides = {}
    if args.bandgap_file:
        gap_overrides = json.loads(args.bandgap_file.read_text(encoding="utf-8"))
        unknown = set(gap_overrides) - set(MATERIALS)
        if unknown:
            parser.error("Unknown material(s): " + ", ".join(sorted(unknown)))
    args.output.mkdir(parents=True, exist_ok=True)
    for material, (nominal_eg, lua_path) in MATERIALS.items():
        eg = float(gap_overrides.get(material, nominal_eg))
        if not math.isfinite(eg) or eg <= 0:
            parser.error(f"Invalid bandgap for {material}: {eg}")
        path = generate(args.output, material, eg, lua_path, args.temperature, args.points)
        print(f"{path}  Eg={eg:g} eV  (source: {lua_path})")
    print(f"Generated {len(MATERIALS)} unique material directories with {args.points} points each.")
    print("CAUTION: nominal/illustrative bulk direct-transition profiles; validate alloy composition and gap type.")


if __name__ == "__main__":
    main()

Uwaga: Generowane widma emisji stanowią tymczasowe rozwiązanie. W przypadku ilościowych symulacji urządzeń zaleca się stosowanie zmierzonych danych dotyczących emisji lub widm obliczonych przy użyciu odpowiedniego modelu struktury pasmowej i przejść optycznych, takiego jak obliczenia oparte na metodzie k·p.