Files
2025AsianB/org/chatgpt2/q1_anaylis.py
2025-11-20 20:27:39 +08:00

329 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import CubicSpline
from scipy.stats import pearsonr
from sklearn.metrics import mean_squared_error
import warnings
from sklearn.metrics.pairwise import cosine_similarity
from org.chatgpt2.q1_2 import wl_max, wl_min
warnings.filterwarnings('ignore')
# -----------------------------
# 1. 通用工具函数(保持不变)
# -----------------------------
def make_strictly_increasing(wl, n, k):
unique_wl, indices = np.unique(wl, return_index=True)
if len(unique_wl) != len(wl):
print(f"Removed {len(wl) - len(unique_wl)} duplicate wavelength points")
wl, n, k = wl[indices], n[indices], k[indices]
is_increasing = np.diff(wl) > 0
if not all(is_increasing):
valid_indices = np.concatenate([[True], is_increasing])
wl, n, k = wl[valid_indices], n[valid_indices], k[valid_indices]
return wl, n, k
def read_split_data(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
lines = [line.strip() for line in f if line.strip() and not line.startswith('#')]
split_idx = None
for i, line in enumerate(lines):
if line == 'wl k':
split_idx = i
break
n_lines = lines[1:split_idx]
wl_n, n_list = [], []
for line in n_lines:
wl, n_val = line.split()
wl_n.append(float(wl)), n_list.append(float(n_val))
k_lines = lines[split_idx + 1:]
wl_k, k_list = [], []
for line in k_lines:
wl, k_val = line.split()
wl_k.append(float(wl)), k_list.append(float(k_val))
wl_n, n_list = np.array(wl_n), np.array(n_list)
wl_k, k_list = np.array(wl_k), np.array(k_list)
assert np.allclose(wl_n, wl_k), "n和k的波长列表不一致"
sorted_idx = np.argsort(wl_n)
return wl_n[sorted_idx], n_list[sorted_idx], k_list[sorted_idx]
def fresnel_reflectance(n1, k1, n2, k2):
m1 = n1 + 1j * k1
m2 = n2 + 1j * k2
return np.abs((m1 - m2) / (m1 + m2)) ** 2
def thin_film_emissivity(n_film, k_film, d, wl, n_air=1.0, k_air=0.0, n_sub=1.5, k_sub=0.0, r=0.0):
m_air = n_air + 1j * k_air
m_film = n_film + 1j * k_film
m_sub = n_sub + 1j * k_sub
R12 = np.abs((m_air - m_film) / (m_air + m_film)) ** 2
R23 = np.abs((m_film - m_sub) / (m_film + m_sub)) ** 2
beta = 2 * np.pi * m_film / wl
delta_complex = beta * d
alpha = 2 * np.imag(delta_complex)
sqrt_term = np.sqrt(R12 * R23 * np.exp(-alpha))
cos_term = np.cos(2 * np.real(delta_complex))
R_specular = (R12 + R23 * np.exp(-alpha) + 2 * sqrt_term * cos_term) / (
1 + R12 * R23 * np.exp(-alpha) + 2 * sqrt_term * cos_term)
R_diffuse = 0.05 * r
R_total = (1 - r) * R_specular + r * R_diffuse
T_total = (1 - R12) * (1 - R23) * np.exp(-alpha) / (1 + R12 * R23 * np.exp(-alpha) + 2 * sqrt_term * cos_term)
return np.clip(1 - R_total - T_total, 0, 1)
# -----------------------------
# 2. 新增:局部相似度计算函数(滑动窗口法)
# -----------------------------
def calculate_local_similarity(eps1, eps2, wl_common, window_size=0.5):
"""
计算逐波长的局部相似度(滑动窗口法)
输入:
eps1/eps2: 两个发射率数组
wl_common: 统一波长数组
window_size: 滑动窗口宽度μm默认0.5μm覆盖5个采样点保证平滑
输出:
local_corr: 逐波长皮尔逊相关系数(局部相似度)
local_cos_sim: 逐波长余弦相似度
local_mae: 逐波长局部平均绝对误差(相似度的互补指标)
"""
n_points = len(wl_common)
local_corr = np.zeros(n_points)
local_cos_sim = np.zeros(n_points)
local_mae = np.zeros(n_points)
# 滑动窗口计算局部相似度(窗口中心为每个波长点)
for i in range(n_points):
# 确定当前窗口的波长范围
wl_center = wl_common[i]
window_mask = (wl_common >= wl_center - window_size / 2) & (wl_common <= wl_center + window_size / 2)
if np.sum(window_mask) < 3: # 窗口内至少3个点才计算避免统计无意义
local_corr[i] = np.nan
local_cos_sim[i] = np.nan
local_mae[i] = np.nan
continue
# 提取窗口内的发射率数据
eps1_window = eps1[window_mask]
eps2_window = eps2[window_mask]
# 计算窗口内的相似度指标
corr, _ = pearsonr(eps1_window, eps2_window)
cos_sim = cosine_similarity(eps1_window.reshape(1, -1), eps2_window.reshape(1, -1))[0][0]
mae = np.mean(np.abs(eps1_window - eps2_window))
# 存储结果相关系数和余弦相似度归一化到0-1范围
local_corr[i] = (corr + 1) / 2 # 原始相关系数-1~1 → 映射为0~1
local_cos_sim[i] = cos_sim
local_mae[i] = mae
return local_corr, local_cos_sim, local_mae
# -----------------------------
# 3. 核心相似性分析函数(新增局部相似度计算)
# -----------------------------
def analyze_spectral_similarity(file1, file2, thicknesses=[1.0], n_sub=1.5, k_sub=0.0, r=0.0, window_size=0.5):
# Step 1: 数据读取与预处理
wl1, n1, k1 = read_split_data(file1)
wl2, n2, k2 = read_split_data(file2)
wl1, n1, k1 = make_strictly_increasing(wl1, n1, k1)
wl2, n2, k2 = make_strictly_increasing(wl2, n2, k2)
# Step 2: 统一波长范围
wl_min = max(wl1.min(), wl2.min())
wl_max = min(wl1.max(), wl2.max())
if wl_min >= wl_max:
raise ValueError("两个文件的波长范围无交集,无法进行相似性分析!")
wl_common = np.linspace(wl_min, wl_max, 1000)
# Step 3: 插值得到统一波长下的n和k
cs_n1 = CubicSpline(wl1, n1)
cs_k1 = CubicSpline(wl1, k1)
cs_n2 = CubicSpline(wl2, n2)
cs_k2 = CubicSpline(wl2, k2)
n1_common = cs_n1(wl_common)
k1_common = cs_k1(wl_common)
n2_common = cs_n2(wl_common)
k2_common = cs_k2(wl_common)
# Step 4: 计算发射率和局部相似度
emissivity_dict = {}
local_similarity_dict = {}
for d in thicknesses:
eps1 = thin_film_emissivity(n1_common, k1_common, d, wl_common, n_sub=n_sub, k_sub=k_sub, r=r)
eps2 = thin_film_emissivity(n2_common, k2_common, d, wl_common, n_sub=n_sub, k_sub=k_sub, r=r)
emissivity_dict[d] = (eps1, eps2)
# 计算局部相似度
local_corr, local_cos_sim, local_mae = calculate_local_similarity(eps1, eps2, wl_common, window_size)
local_similarity_dict[d] = (local_corr, local_cos_sim, local_mae)
# Step 5: 全局相似性指标计算
similarity_results = {}
for d in thicknesses:
eps1, eps2 = emissivity_dict[d]
pearson_corr, _ = pearsonr(eps1, eps2)
cos_sim = cosine_similarity(eps1.reshape(1, -1), eps2.reshape(1, -1))[0][0]
mse = mean_squared_error(eps1, eps2)
norm_mse = mse / (np.max([np.var(eps1), np.var(eps2)]) + 1e-8)
mae = np.mean(np.abs(eps1 - eps2))
# 大气窗口指标
window_corr, window_mae = None, None
if wl_min <= 13 and wl_max >= 8:
window_mask = (wl_common >= 8) & (wl_common <= 13)
eps1_window = eps1[window_mask]
eps2_window = eps2[window_mask]
window_corr, _ = pearsonr(eps1_window, eps2_window)
window_mae = np.mean(np.abs(eps1_window - eps2_window))
similarity_results[d] = {
"pearson_correlation": pearson_corr,
"cosine_similarity": cos_sim,
"normalized_mse": norm_mse,
"mae": mae,
"window_pearson_correlation": window_corr,
"window_mae": window_mae
}
# Step 6: 可视化(新增相似度曲线)
plot_spectral_comparison(wl_common, emissivity_dict, local_similarity_dict, thicknesses, wl_min, wl_max)
return similarity_results, wl_common, emissivity_dict, local_similarity_dict
# -----------------------------
# 4. 可视化函数(新增相似度曲线子图)
# -----------------------------
def plot_spectral_comparison(wl_common, emissivity_dict, local_similarity_dict, thicknesses, wl_min, wl_max):
n_plots = len(thicknesses)
fig, axes = plt.subplots(n_plots, 3, figsize=(18, 5 * n_plots)) # 新增1列用于相似度曲线
plt.rcParams['font.sans-serif'] = ['Arial']
for idx, d in enumerate(thicknesses):
eps1, eps2 = emissivity_dict[d]
local_corr, local_cos_sim, local_mae = local_similarity_dict[d]
diff = np.abs(eps1 - eps2)
# 子图1发射率光谱对比
ax1 = axes[idx, 0] if n_plots > 1 else axes[0]
ax1.plot(wl_common, eps1, linewidth=2, label='data.txt', color='darkblue')
ax1.plot(wl_common, eps2, linewidth=2, label='data2.txt', color='darkred', linestyle='--')
if wl_min <= 13 and wl_max >= 8:
ax1.axvspan(8, 13, alpha=0.15, color='orange', label='Atmospheric Window (8-13 μm)')
ax1.set_xlabel('Wavelength (μm)', fontsize=12)
ax1.set_ylabel('Emissivity ε(λ)', fontsize=12)
ax1.set_title(f'Emissivity Spectrum Comparison (Thickness = {d} μm)', fontsize=14, fontweight='bold')
ax1.grid(True, alpha=0.3)
ax1.legend(fontsize=10)
ax1.set_ylim(0, 1.05)
# 子图2发射率差异
ax2 = axes[idx, 1] if n_plots > 1 else axes[1]
ax2.plot(wl_common, diff, linewidth=2, color='darkgreen', label='Absolute Difference |ε1 - ε2|')
ax2.fill_between(wl_common, 0, diff, alpha=0.3, color='darkgreen')
if wl_min <= 13 and wl_max >= 8:
ax2.axvspan(8, 13, alpha=0.15, color='orange', label='Atmospheric Window (8-13 μm)')
ax2.set_xlabel('Wavelength (μm)', fontsize=12)
ax2.set_ylabel('Absolute Difference', fontsize=12)
ax2.set_title(f'Emissivity Difference (Thickness = {d} μm)', fontsize=14, fontweight='bold')
ax2.grid(True, alpha=0.3)
ax2.legend(fontsize=10)
ax2.set_ylim(0, np.nanmax(diff) * 1.2)
# 子图3相似度曲线核心新增
ax3 = axes[idx, 2] if n_plots > 1 else axes[2]
# 绘制局部皮尔逊相关系数归一化到0-1
ax3.plot(wl_common, local_corr, linewidth=2.5, color='#4B0082', label='Local Pearson Correlation (0-1)') # 绘制局部余弦相似度0-1
ax3.plot(wl_common, local_cos_sim, linewidth=2.5, color='orange', label='Local Cosine Similarity (0-1)',
linestyle='--')
# 标注相似度阈值线0.9为高相似0.8为中等相似)
ax3.axhline(y=0.9, color='red', linestyle=':', linewidth=1.5, label='High Similarity Threshold (0.9)')
ax3.axhline(y=0.8, color='orange', linestyle=':', linewidth=1.5, label='Medium Similarity Threshold (0.8)')
# 标注大气窗口
if wl_min <= 13 and wl_max >= 8:
ax3.axvspan(8, 13, alpha=0.15, color='orange', label='Atmospheric Window (8-13 μm)')
ax3.set_xlabel('Wavelength (μm)', fontsize=12)
ax3.set_ylabel('Local Similarity (0-1)', fontsize=12)
ax3.set_title(f'Wavelength-Dependent Similarity Curve (Thickness = {d} μm)', fontsize=14, fontweight='bold')
ax3.grid(True, alpha=0.3)
ax3.legend(fontsize=10)
ax3.set_ylim(0, 1.05) # 相似度范围0-1
ax3.set_xlim(wl_min, wl_max)
plt.tight_layout()
plt.savefig('spectral_similarity_complete.png', dpi=300, bbox_inches='tight')
plt.show()
# -----------------------------
# 5. 主程序执行
# -----------------------------
if __name__ == "__main__":
file1 = '/Users/spasolreisa/IdeaProjects/asiaMath/data.txt'
file2 = '/Users/spasolreisa/IdeaProjects/asiaMath/data2.txt'
target_thicknesses = [0.5, 1.0, 1.5, 2.0]
base_params = {
'n_sub': 1.5,
'k_sub': 0.0,
'r': 0.05
}
window_size = 0.5 # 滑动窗口宽度可调整建议0.3-0.8μm
print("=== 开始光谱相似性分析(含相似度曲线) ===")
print(f"文件1: {file1}")
print(f"文件2: {file2}")
print(f"分析厚度: {target_thicknesses} μm")
print(f"滑动窗口宽度: {window_size} μm")
print("-" * 50)
results, wl_common, emissivity_dict, local_similarity_dict = analyze_spectral_similarity(
file1, file2,
thicknesses=target_thicknesses,
n_sub=base_params['n_sub'],
k_sub=base_params['k_sub'],
r=base_params['r'],
window_size=window_size
)
# 输出全局指标
print("\n=== 全局相似性指标 ===")
for d in target_thicknesses:
res = results[d]
print(f"\n【厚度 {d} μm】")
print(f"全局皮尔逊相关系数: {res['pearson_correlation']:.4f}")
print(f"全局余弦相似度: {res['cosine_similarity']:.4f}")
print(f"归一化均方误差: {res['normalized_mse']:.4f}")
print(f"平均绝对误差: {res['mae']:.4f}")
if res['window_pearson_correlation'] is not None:
print(f"大气窗口全局相关系数: {res['window_pearson_correlation']:.4f}")
# 输出局部相似度统计(大气窗口内)
print("\n=== 大气窗口8-13μm局部相似度统计 ===")
for d in target_thicknesses:
local_corr, local_cos_sim, _ = local_similarity_dict[d]
if wl_min <= 13 and wl_max >= 8:
window_mask = (wl_common >= 8) & (wl_common <= 13)
window_local_corr = local_corr[window_mask]
window_local_cos = local_cos_sim[window_mask]
# 过滤NaN值
window_local_corr = window_local_corr[~np.isnan(window_local_corr)]
window_local_cos = window_local_cos[~np.isnan(window_local_cos)]
if len(window_local_corr) > 0:
print(f"\n【厚度 {d} μm】")
print(f"大气窗口局部相关系数均值: {np.mean(window_local_corr):.4f}")
print(f"大气窗口局部相关系数最小值: {np.min(window_local_corr):.4f}")
print(f"大气窗口局部余弦相似度均值: {np.mean(window_local_cos):.4f}")
# 结果解读
print("\n=== 结果解读 ===")
print("1. 相似度曲线子图3值越接近1对应波长下的发射率越相似")
print("2. 高相似区域≥0.9):两文件在该波段的辐射冷却性能几乎一致;")
print("3. 低相似区域(<0.8):需关注该波段的材料差异对冷却效果的影响;")
print("4. 大气窗口内相似度:优先关注该区域,直接决定辐射冷却核心性能是否一致。")