整合
This commit is contained in:
151
org/other/question1_pdms_emissivity.py
Normal file
151
org/other/question1_pdms_emissivity.py
Normal file
@@ -0,0 +1,151 @@
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List
|
||||
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
AIR_INDEX = 1.0 # normal incidence, non-absorbing ambient
|
||||
WAVELENGTH_MIN = 0.4 # µm
|
||||
WAVELENGTH_MAX = 25.0 # µm
|
||||
|
||||
|
||||
def cauchy_index(wavelength_um: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
Dispersion model for PDMS based on Cauchy equation fitted to literature data:
|
||||
n(λ) = A + B / λ^2 + C / λ^4
|
||||
The coefficients (A=1.385, B=0.0125, C=0.00045) match n≈1.43 @ 0.55 µm
|
||||
and n≈1.40 beyond 2 µm.
|
||||
"""
|
||||
A = 1.385
|
||||
B = 0.0125
|
||||
C = 0.00045
|
||||
lam2 = wavelength_um ** 2
|
||||
return A + B / lam2 + C / (lam2 * wavelength_um ** 2)
|
||||
|
||||
|
||||
def extinction_coeff(wavelength_um: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
Construct an approximate extinction coefficient profile by superposing
|
||||
Gaussians centered at the known vibrational bands of PDMS in the mid-IR.
|
||||
Peaks taken from FTIR measurements (Si-O-Si at ~9.2 µm, Si-CH3 rocking at
|
||||
12.7 µm, CH stretches at 3.4 µm, etc.).
|
||||
"""
|
||||
peaks = [
|
||||
# (center µm, amplitude, width µm)
|
||||
(3.4, 0.06, 0.25),
|
||||
(8.0, 0.30, 0.50),
|
||||
(9.2, 0.65, 0.60),
|
||||
(10.6, 0.35, 0.45),
|
||||
(12.7, 0.45, 0.35),
|
||||
(14.5, 0.25, 0.60),
|
||||
]
|
||||
k = np.full_like(wavelength_um, 5e-4)
|
||||
for center, amp, width in peaks:
|
||||
k += amp * np.exp(-0.5 * ((wavelength_um - center) / width) ** 2)
|
||||
# enforce plausible upper bound
|
||||
return np.clip(k, 0, 2.0)
|
||||
|
||||
|
||||
def thin_film_emissivity(
|
||||
wavelength_um: np.ndarray, thickness_um: float, n_complex: np.ndarray
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
Normal-incidence emissivity for a PDMS slab in air computed using
|
||||
the transfer-matrix solution for a single absorbing layer.
|
||||
"""
|
||||
n0 = AIR_INDEX
|
||||
ns = AIR_INDEX
|
||||
thickness_m = thickness_um * 1e-6
|
||||
# vacuum wavenumber
|
||||
beta = 2 * np.pi / (wavelength_um * 1e-6)
|
||||
delta = beta * n_complex * thickness_m
|
||||
|
||||
r01 = (n0 - n_complex) / (n0 + n_complex)
|
||||
r12 = (n_complex - ns) / (n_complex + ns)
|
||||
exp_term = np.exp(2j * delta)
|
||||
numerator_r = r01 + r12 * exp_term
|
||||
denominator = 1 + r01 * r12 * exp_term
|
||||
r = numerator_r / denominator
|
||||
|
||||
t01 = 2 * n0 / (n0 + n_complex)
|
||||
t12 = 2 * n_complex / (n_complex + ns)
|
||||
exp_half = np.exp(1j * delta)
|
||||
t = (t01 * t12 * exp_half) / denominator
|
||||
|
||||
R = np.abs(r) ** 2
|
||||
T = (ns.real / n0) * np.abs(t) ** 2
|
||||
A = 1 - R - T
|
||||
return np.clip(A.real, 0, 1)
|
||||
|
||||
|
||||
@dataclass
|
||||
class EmissivityResult:
|
||||
wavelengths: np.ndarray
|
||||
emissivity_map: Dict[float, np.ndarray]
|
||||
window_avg: Dict[float, float]
|
||||
|
||||
|
||||
def compute_emissivity(thicknesses_um: List[float]) -> EmissivityResult:
|
||||
wavelengths = np.linspace(WAVELENGTH_MIN, WAVELENGTH_MAX, 1200)
|
||||
n = cauchy_index(wavelengths)
|
||||
k = extinction_coeff(wavelengths)
|
||||
n_complex = n + 1j * k
|
||||
|
||||
emissivity_map = {}
|
||||
window_avg = {}
|
||||
window_mask = (wavelengths >= 8) & (wavelengths <= 13)
|
||||
|
||||
for d in thicknesses_um:
|
||||
eps = thin_film_emissivity(wavelengths, d, n_complex)
|
||||
emissivity_map[d] = eps
|
||||
window_avg[d] = float(np.trapz(eps[window_mask], wavelengths[window_mask]) /
|
||||
np.trapz(np.ones_like(wavelengths[window_mask]),
|
||||
wavelengths[window_mask]))
|
||||
|
||||
return EmissivityResult(wavelengths, emissivity_map, window_avg)
|
||||
|
||||
|
||||
def plot_emissivity(result: EmissivityResult, outdir: str) -> str:
|
||||
plt.figure(figsize=(9, 5))
|
||||
for d, eps in result.emissivity_map.items():
|
||||
label = f"{d:.0f} µm (ε̄₈₋₁₃={result.window_avg[d]:.2f})"
|
||||
plt.plot(result.wavelengths, eps, label=label)
|
||||
|
||||
plt.axvspan(8, 13, color="tab:gray", alpha=0.15, label="Atmospheric window")
|
||||
plt.xlabel("Wavelength (µm)")
|
||||
plt.ylabel("Spectral emissivity")
|
||||
plt.title("PDMS Thin-Film Emissivity vs. Wavelength")
|
||||
plt.ylim(0, 1.05)
|
||||
plt.xlim(WAVELENGTH_MIN, WAVELENGTH_MAX)
|
||||
plt.legend()
|
||||
plt.grid(alpha=0.3)
|
||||
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
output_path = os.path.join(outdir, "question1_emissivity.png")
|
||||
plt.tight_layout()
|
||||
plt.savefig(output_path, dpi=300)
|
||||
plt.close()
|
||||
return output_path
|
||||
|
||||
|
||||
def main():
|
||||
thicknesses = [1, 5, 10, 25, 50, 100]
|
||||
result = compute_emissivity(thicknesses)
|
||||
outdir = os.path.join(os.path.dirname(__file__), "outputs")
|
||||
figure_path = plot_emissivity(result, outdir)
|
||||
|
||||
summary_lines = ["thickness_um,avg_emissivity_8_13um"]
|
||||
for d in thicknesses:
|
||||
summary_lines.append(f"{d},{result.window_avg[d]:.4f}")
|
||||
csv_path = os.path.join(outdir, "question1_emissivity_summary.csv")
|
||||
with open(csv_path, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(summary_lines))
|
||||
|
||||
print(f"Figure saved to: {figure_path}")
|
||||
print(f"Summary saved to: {csv_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user