재료 데이터베이스(Material Database)
COMPASS는 픽셀 스택(Pixel Stack)의 모든 레이어의 광학 특성을 복소 굴절률 MaterialDB 클래스는 모든 재료 정의를 관리하고 파장 의존적 보간(Interpolation)을 제공합니다.
대화형 재료 광학 특성
재료를 선택하여 가시광선 영역에서의 굴절률(n)과 소광 계수(k)를 확인하세요.
아키텍처 개요
MaterialDB 인스턴스를 생성하면 자동으로 다음을 수행합니다:
- 내장 상수 및 해석적 재료(공기, 폴리머, 유전체)를 등록합니다
materials/디렉토리에서 표 형식 CSV 데이터(실리콘, 텅스텐, 컬러 필터)를 로드합니다- CSV 파일을 찾을 수 없으면 근사 내장 데이터로 폴백합니다
from compass.materials.database import MaterialDB
mat_db = MaterialDB()
print(mat_db.list_materials())
# ['air', 'cf_blue', 'cf_green', 'cf_red', 'hfo2', 'polymer_n1p56',
# 'si3n4', 'silicon', 'sio2', 'tio2', 'tungsten']내장 재료
| 재료 | DB 이름 | 타입 | 출처 / 모델 | 550 nm에서 |
|---|---|---|---|---|
| 공기 | air | constant | 1.000 | |
| 마이크로렌즈 폴리머 | polymer_n1p56 | cauchy | 1.573 | |
| 이산화규소 | sio2 | sellmeier | 3항 셀마이어(Sellmeier) (Malitson 1965) | 1.460 |
| 질화규소 | si3n4 | sellmeier | 2항 셀마이어 | 2.020 |
| 이산화하프늄 | hfo2 | cauchy | 1.966 | |
| 이산화티타늄 | tio2 | cauchy | 2.435 | |
| 결정질 실리콘 | silicon | tabulated | Green 2008 (350--1100 nm) | 4.082 |
| 텅스텐 | tungsten | tabulated | Palik 데이터 (380--780 nm) | 3.650 |
| 적색 컬러 필터 | cf_red | tabulated | 로렌츠 흡수 모델 | 1.550 |
| 녹색 컬러 필터 | cf_green | tabulated | 로렌츠 흡수 모델 | 1.550 |
| 청색 컬러 필터 | cf_blue | tabulated | 로렌츠 흡수 모델 | 1.550 |
재료 데이터 타입
COMPASS는
Constant (상수)
파장에 무관한 고정 굴절률입니다. 공기나 이상화된 유전체와 같은 비분산 매질에 적합합니다.
mat_db.register_constant("my_dielectric", n=1.45, k=0.0)
n, k = mat_db.get_nk("my_dielectric", 0.55)
# n=1.45, k=0.0 at any wavelengthTabulated (표 형식)
이산 데이터 점으로부터의 파장 의존적
# Internally, tabulated materials build scipy interpolators:
from scipy.interpolate import CubicSpline
n_interp = CubicSpline(wavelengths, n_data, extrapolate=True)
k_interp = CubicSpline(wavelengths, k_data, extrapolate=True)주요 동작:
- 데이터 범위 밖의 파장은 가장 가까운 경계값으로 **클램핑(Clamping)**됩니다
- 클램핑이 발생하면 경고가 로그에 기록됩니다
- 소광 계수는 비음수로 클램핑됩니다:
Cauchy (코시)
투명 유전체를 위한 해석적 분산 모델입니다. 강한 흡수 밴드가 없는 재료에서 가시광 범위에서 정확합니다.
여기서
mat_db.register_cauchy("my_polymer", A=1.56, B=0.004, C=0.0)
n, k = mat_db.get_nk("my_polymer", 0.55)
# n = 1.56 + 0.004 / 0.3025 = 1.573, k = 0.0내장 코시 계수:
| 재료 | |||
|---|---|---|---|
polymer_n1p56 | 1.56 | 0.004 | 0.0 |
hfo2 | 1.90 | 0.02 | 0.0 |
tio2 | 2.27 | 0.05 | 0.0 |
Sellmeier (셀마이어)
유리 및 유전체의 고정밀 분산 모델링을 위한 다항 셀마이어 방정식입니다:
여기서
mat_db.register_sellmeier(
"fused_silica",
B=[0.6961663, 0.4079426, 0.8974794],
C=[0.0684043**2, 0.1162414**2, 9.896161**2],
)내장 셀마이어 계수:
| 재료 | ||||||
|---|---|---|---|---|---|---|
sio2 | 0.6962 | 0.4079 | 0.8975 | 0.00468 | 0.01352 | 97.934 |
si3n4 | 2.8939 | 0.0 | -- | 0.01951 | 1.0 | -- |
유전율 변환
솔버는 굴절률이 아닌 복소 유전율(Permittivity)
# Single wavelength
eps = mat_db.get_epsilon("silicon", 0.55)
# eps = (4.082 + 0.028j)^2 ~ 16.66 + 0.229j
# Spectrum over multiple wavelengths
import numpy as np
wavelengths = np.arange(0.40, 0.701, 0.01)
eps_spectrum = mat_db.get_epsilon_spectrum("silicon", wavelengths)CSV를 통한 사용자 정의 재료 추가
내장 데이터베이스에 없는 재료를 추가하려면 세 개의 열(파장(um), #으로 시작하는 줄은 주석으로 처리됩니다.
CSV 형식
# Custom infrared filter material
# wavelength(um), n, k
0.380, 1.60, 0.12
0.400, 1.59, 0.10
0.440, 1.57, 0.05
0.480, 1.55, 0.01
0.520, 1.55, 0.002
0.560, 1.55, 0.002
0.600, 1.56, 0.01
0.650, 1.56, 0.03
0.700, 1.56, 0.05
0.750, 1.57, 0.08사용자 정의 CSV 로딩 및 사용
mat_db = MaterialDB()
# Load from file (sorts by wavelength, builds interpolators)
mat_db.load_csv("ir_cut_filter", "materials/ir_cut_filter.csv")
# Verify it loaded
print(mat_db.has_material("ir_cut_filter")) # True
n, k = mat_db.get_nk("ir_cut_filter", 0.55)
print(f"IR cut filter at 550nm: n={n:.3f}, k={k:.4f}")보간 방법을 오버라이드할 수도 있습니다:
mat_db.load_csv("my_mat", "data.csv", interpolation="linear")자동 CSV 검색
COMPASS는 materials/ 디렉토리(COMPASS_MATERIALS 환경 변수로 설정 가능)에서 알려진 파일명을 검색합니다:
| 재료명 | 검색되는 파일명 |
|---|---|
silicon | silicon_green2008.csv, silicon_palik.csv |
tungsten | tungsten.csv |
cf_red | color_filter_red.csv |
cf_green | color_filter_green.csv |
cf_blue | color_filter_blue.csv |
CSV를 찾을 수 없으면 근사 내장 폴백 데이터가 사용됩니다.
YAML 설정에서 사용자 정의 재료 사용
사용자 정의 재료를 등록한 후, 픽셀 설정에서 이름으로 참조합니다:
color_filter:
red:
material: "my_custom_red"
thickness: 0.62
contact_angle: 66.0
green:
material: "cf_green"
thickness: 0.60
contact_angle: 72.0
blue:
material: "cf_blue"
thickness: 0.65
contact_angle: 62.0GeometryBuilder를 호출하기 전에 재료가 등록되어 있는지 확인하십시오:
mat_db = MaterialDB()
mat_db.load_csv("my_custom_red", "materials/my_red_filter.csv")
builder = GeometryBuilder(config.pixel, mat_db)
pixel_stack = builder.build()보간 흐름
MaterialDB API 요약
class MaterialDB:
def __init__(self, db_path: str | None = None): ...
def register_constant(self, name: str, n: float, k: float = 0.0) -> None: ...
def register_cauchy(self, name: str, A: float, B: float = 0.0, C: float = 0.0) -> None: ...
def register_sellmeier(self, name: str, B: list[float], C: list[float]) -> None: ...
def load_csv(self, name: str, filepath: str, interpolation: str = "cubic_spline") -> None: ...
def get_nk(self, name: str, wavelength: float) -> tuple[float, float]: ...
def get_epsilon(self, name: str, wavelength: float) -> complex: ...
def get_epsilon_spectrum(self, name: str, wavelengths: np.ndarray) -> np.ndarray: ...
def list_materials(self) -> list[str]: ...
def has_material(self, name: str) -> bool: ...예시: 재료 분산 플롯
import numpy as np
import matplotlib.pyplot as plt
from compass.materials.database import MaterialDB
mat_db = MaterialDB()
wavelengths = np.linspace(0.38, 0.78, 100)
wavelengths_nm = wavelengths * 1000
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
for name in ["silicon", "sio2", "si3n4", "hfo2"]:
n_arr = np.array([mat_db.get_nk(name, wl)[0] for wl in wavelengths])
k_arr = np.array([mat_db.get_nk(name, wl)[1] for wl in wavelengths])
ax1.plot(wavelengths_nm, n_arr, label=name)
ax2.plot(wavelengths_nm, k_arr, label=name)
ax1.set_xlabel("Wavelength (nm)")
ax1.set_ylabel("n")
ax1.set_title("Refractive Index")
ax1.legend()
ax1.grid(True, alpha=0.3)
ax2.set_xlabel("Wavelength (nm)")
ax2.set_ylabel("k")
ax2.set_title("Extinction Coefficient")
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()