OghmaNano 내의 방출 스펙트럼
방출 스펙트럼이란 물질에서 방출되는 빛이 파장에 따라 어떻게 분포하는지를 나타냅니다. OghmaNano는 이러한 스펙트럼들을 재료 데이터베이스에 저장하여 확인 및 가져오기, 업데이트가 가능하도록 합니다. 본 페이지에서는 방출 스펙트럼의 의미와 저장 및 가져오기 방법, 그리고 측정 데이터가 없는 경우 Python을 이용해 근사적인 스펙트럼을 생성하는 절차에 대해 설명합니다.
1. 방출 스펙트럼이란 무엇인가?
전자와 정공이 복사적으로 재결합할 때, 광자는 단일 파장이 아닌 다양한 에너지 값을 가지며 방출된다. 방출 스펙트럼이란 파장에 따른 이러한 빛의 상대 강도를 나타내는 값이다. 이 방출 스펙트럼은 광발광(PL)이나 전기발광(EL)과 같은 실험적 측정을 통해 얻어질 수도 있고, 이론적 모델을 통해 산출될 수도 있다. 다만 이 방출 스펙트럼은 물질의 흡수 계수나 굴절률과는 다른 개념이다.
방출 스펙트럼의 형태는 반도체의 전자 구조, 온도, 조성 그리고 실제 소자에서는 전하 캐리어 분포 및 광학적 효과에 따라 결정된다. 정규화된 방출 스펙트럼은 파장에 따른 상대적 분포만을 나타낼 뿐 절대적인 광출력이나 LED 효율을 반영하지는 않는다.
2. 재료 데이터베이스 내 방출 스펙트럼
각 재료마다 OghmaNano 재료 데이터베이스 내에 고유한 디렉터리가 존재합니다. 방출 데이터가 존재할 경우 이 데이터는 emission.csv이라는 파일에 alpha.csv, n.csv와 같은 다른 파일들과 함께 저장됩니다. 예를 들어, 특정 재료의 폴더에는 다음과 같은 파일들이 포함될 수 있습니다:
materials/
GaAs/
emission.csv
alpha.csv
n.csv
시뮬레이션에 사용되는 재료 데이터베이스는 사용자의 oghma_local/materials 디렉터리 하위에 위치합니다. 디렉터리 구조와 재료 파일 형식에 대한 설명은 재료 데이터베이스: 파트 C – 재료의 저장 방식을 참조하십시오. 재료 탐색 및 편집 방법에 대한 소개는 재료 데이터베이스: 파트 A를 참조하십시오.
emission.csv 파일에는 미터 단위의 파장값과 임의 단위로 표기된 상대 방출 강도가 기재되어 있습니다. OghmaNano 형식의 파일에는 메타데이터 헤더도 포함되는데, 해당 헤더 내의 y_len 값은 그 뒤에 나오는 파장-강도 데이터의 개수를 나타냅니다.
3. 측정된 방출 스펙트럼의 가져오기
측정된 광발광(PL) 또는 전기발광(EL) 데이터가 존재하는 경우, 해당 데이터가 소재 및 설계 목적에 적합하다면 생성된 근사적 방출 스펙트럼보다 우선적으로 사용하는 것이 바람직합니다. 먼저 재료 데이터베이스에서 해당 소재를 열고 그 방출 스펙트럼을 선택한 뒤 데이터 가져오기 기능을 이용해 측정값을 불러오시기 바랍니다. 두 개의 열로 구성된 데이터셋을 가져오고 파장 단위를 지정하며 변환된 값들을 검토하는 전반적인 절차는 재료 데이터베이스: 파트 A – 데이터 가져오기에 설명되어 있습니다.
단위: 저장된 파장 값은 미터 단위로 기록되나 그래프에는 나노미터 단위로 표시됩니다. 방출 형태를 나타내는 데이터로는 정규화된 강도(a.u.)를 사용하십시오. 스펙트럼을 가져오거나 생성한 후에는 파일의 메타데이터와 데이터 포인트 수를 반드시 확인해야 합니다.
4. 측정 데이터가 없는 경우 방출 스펙트럼 추정 방법
측정된 방출 스펙트럼 데이터가 없는 경우 아래의 파이썬 스크립트를 이용하여 임시적으로 정규화된 벌크 반도체 방출 스펙트럼을 생성할 수 있다. 이 스크립트는 직접 밴드갭을 갖는 물질에 대해 단순화된 열적 밴드-투-밴드 모델을 활용한다.
\(S_E(E) \propto \sqrt{E-E_g}\,\exp[-(E-E_g)/(k_B T)]\)은 \(E \geq E_g\)용으로 사용됩니다.
여기서 \(E_g\)은 밴드갭이며 \(T\)는 온도입니다. 이 스크립트는 계산된 에너지 영역상의 방출 스펙트럼을 단위 파장당 강도 값으로 변환한 뒤, 그 최대값을 1로 정규화하여 OghmaNano에서 사용하는 메타데이터 및 데이터 형식에 맞춰 emission.csv을 작성합니다. 기본적으로 300 K 조건에서 2,036개의 파장-강도 데이터 쌍이 생성됩니다.
제공된 스크립트는 GaAs, AlGaAs, GaN, InGaN, InP, InGaAs를 포함한 29종의 서로 다른 반도체에 대해 각각 하나씩 디렉터리를 생성합니다. 각 재료의 밴드갭 값은 대표적인 기준값이며, 조성에 따라 특성이 변하는 합금의 경우 생성된 방출 스펙트럼은 단지 하나의 명목상 조성만을 나타냅니다.
이 방법은 언제 적절하게 사용될 수 있는가? 생성된 방출 스펙트럼 곡선들은 예시적인 벌크형 방출 프로파일로 활용하는 것이 적절하며, 특히 방출 처리 과정을 테스트하거나 보다 정확한 측정 데이터 혹은 밴드 구조 기반 계산 결과가 확보될 때까지 사용하는 것이 바람직하다. 이 곡선들은 실제 측정된 스펙트럼이 아니므로 특정 LED의 방출 특성을 정량적으로 예측하는 수치로 간주해서는 안 된다.
이 모델은 양자우물 구속 효과, 합금 무질서 현상, 엑시톤 관련 특성, 결함에 의한 방출 현상, 응력 및 광학적 방출 특성을 포함하지 않는다. 특히 GaP의 경우와 같이 간접 밴드갭 전이에 적합하지 않은데, 이 모델에서 생성된 곡선은 일반적인 GaP LED의 방출 스펙트럼이 아니라 설명용 직접 전이 곡선에 해당한다.
5. 예시: Python을 이용한 방출 스펙트럼 생성
아래 코드를 generate_emission_spectra.py로 저장한 뒤 실행하십시오:
python3 generate_emission_spectra.py
기본 출력 디렉터리는 emission_generated입니다. 다른 디렉터리를 선택하거나 데이터 포인트 수를 변경하려면:
python3 generate_emission_spectra.py --output my_emission_database --points 2036
작동 온도를 변경하거나 사용자 정의 밴드갭 값을 입력하려면:
python3 generate_emission_spectra.py --temperature 300 --bandgap-file bandgaps.json
예시 bandgaps.json 파일의 내용은 다음과 같습니다:
{
"GaAs": 1.424,
"AlGaAs": 1.80,
"InGaN": 2.75
}
생성된 방출 스펙트럼들을 검토한 후, 적절한 emission.csv 파일들을 대응하는 재료 폴더에 배치하십시오. 이 스크립트에서 사용된 밴드갭 값들은 수동으로 지정된 대표적 값들이며, 스크립트는 이 값들을 계산하기 위해 Lua 기반 재료 스크립트들을 호출하지 않습니다.
6. 완전한 파이썬 소스 코드
다음은 Python 표준 라이브러리만을 활용하여 구현된 방출 스펙트럼 생성기 전체 코드입니다. 해당 소스 코드를 확장한 뒤 로컬 Python 파일에 복사하시기 바랍니다.
전체 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()
참고사항: 생성된 방출 스펙트럼은 임시적인 해결책에 불과합니다. 정량적인 소자 시뮬레이션을 위해서는 측정된 방출 데이터나 k·p 기반 계산과 같은 적절한 전자 밴드 구조 및 광학적 전이 모델을 활용하여 산출된 스펙트럼을 사용하는 것이 바람직합니다.