from re import A
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import json
import os
import math
import numpy as np
class OpticalSystem:
def __init__(self):
self.surfaces = [] # 存储光学表面对象
self.entrance_pupil_diameter = None # 入瞳直径 (mm)
self.entrance_pupil_position = None # 入瞳位置 (相对第一个面顶点) (mm)
self.object_infinite = True # 物在无穷远
self.field_angle = None # 半视场角 (度)
self.object_distance = None # 物距 (有限远) (mm)
self.object_height = None # 物高 (有限远) (mm)
self.aperture_angle = None # 孔径角 (有限远) (度)
self.light_type = "d" # 色光类型,默认d光
self.aperture_coefficient = 1.0 # 孔径系数
self.field_coefficient = 1.0 # 视场系数
# 计算结果存储
self.results = {
"focal_length": None, # 焦距 f'
"ideal_image_distance": None, # 理想像距 l'
"actual_image_position": None, # 实际像位置
"image_principal_plane": None, # 像方主面位置 lH'
"exit_pupil_distance": None, # 出瞳距 lp'
"ideal_image_height": None, # 理想像高 y0'
"spherical_aberration": None, # 球差
"longitudinal_chromatic": None, # 位置色差
"tangential_field_curvature": None, # 子午场曲 xt'
"sagittal_field_curvature": None, # 弧矢场曲 xs'
"astigmatism": None, # 像散 Δxts'
"actual_image_height": None, # 实际像高
"relative_distortion": None, # 相对畸变
"absolute_distortion": None, # 绝对畸变
"lateral_chromatic": None, # 倍率色差
"tangential_coma": None # 子午慧差
}
class Surface:
def __init__(self, r=float('inf'), d=0.0, nd=1.0, vd=0.0):
self.r = r # 曲率半径 (mm)
self.d = d # 厚度/间隔 (mm)
self.nd = nd # d光折射率
self.vd = vd # 阿贝数
def to_dict(self):
"""将表面数据转换为字典"""
return {
"r": self.r,
"d": self.d,
"nd": self.nd,
"vd": self.vd
}
@classmethod
def from_dict(cls, data):
"""从字典创建表面对象"""
return cls(
r=data.get('r', float('inf')),
d=data.get('d', 0.0),
nd=data.get('nd', 1.0),
vd=data.get('vd', 0.0)
)
class calculate:
def trace_paraxial_ray(surfaces, h0, u0, n0=1.0):
"""
近轴光线追迹函数
:param surfaces: 光学表面列表
:param h0: 初始光线高度
:param u0: 初始光线角度(弧度)
:param n0: 初始介质折射率
:return: 最后的光线高度和角度
"""
h = h0
u = u0
n = n0 # 当前介质折射率
for i, surf in enumerate(surfaces):
# 计算曲率(平面时曲率为0)
c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r
# 折射公式:n'u' = nu + (n - n') * c * h
n_prime = surf.nd # 折射后折射率
u_prime = (n * u + (n - n_prime) * c * h) / n_prime
# 如果当前不是最后一个面,计算传播到下个面的高度
if i < len(surfaces) - 1:
d = surf.d # 到下一个面的距离
h_next = h + d * u_prime
else:
h_next = h # 最后一个面后不需要传播
# 更新参数
h = h_next
u = u_prime
n = n_prime # 更新为当前面后的折射率
return h, u
def calculate_focal_length(surfaces):
"""
计算系统焦距
:param surfaces: 光学表面列表
:return: 焦距值(mm)
"""
# 追迹平行于光轴的光线(无穷远物)
h0 = 1.0 # 任意高度,取1便于计算
u0 = 0.0 # 平行于光轴
h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0)
# 焦距 f' = -h0 / u_final
if abs(u_final) < 1e-10: # 防止除零错误
return float('inf')
return -h0 / u_final
def calculate_ideal_image_distance(surfaces, object_infinite, object_distance=None):
"""
计算理想像距
:param surfaces: 光学表面列表
:param object_infinite: 物是否在无穷远
:param object_distance: 物距(有限远时)
:return: 理想像距(mm)
"""
if object_infinite:
# 无穷远物:理想像距等于焦距对应的像距
return calculate.calculate_focal_length(surfaces)+calculate.calculate_principal_plane_position(surfaces)
else:
# 有限远物:使用高斯公式计算理想像距
if object_distance is None:
raise ValueError("有限远物需要提供物距")
# 计算系统焦距
f_prime = calculate.calculate_focal_length(surfaces)
# 高斯公式:1/f' = 1/l' - 1/l
# 其中 l 为物距(负值),l' 为像距
l = -object_distance # 物距为负值(物在左侧)
# 计算像距 l'
if abs(f_prime) < 1e-10:
return float('inf')
l_prime = 1 / (1/f_prime + 1/l)
l_prime = l_prime+calculate.calculate_principal_plane_position(surfaces)
return l_prime
def calculate_principal_plane_position(surfaces):
"""
计算像方主面位置
:param surfaces: 光学表面列表
:return: 主面位置(相对于最后一个面顶点,正值表示在右侧)
"""
# 计算焦距
f_prime = calculate.calculate_focal_length(surfaces)
# 追迹平行于光轴的光线
h0 = 1.0 # 初始高度
u0 = 0.0 # 平行于光轴
h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0)
# 主面位置 lH' = -h_final / u_final - f_prime
if abs(u_final) < 1e-10:
return float('inf')
return -h_final / u_final - f_prime
def calculate_exit_pupil_distance(surfaces, entrance_pupil_position):
"""
计算系统的出瞳距
:param surfaces: 光学表面列表
:param entrance_pupil_position: 入瞳位置(相对于第一个面顶点)
:return: 出瞳距(相对于最后一个面顶点)
"""
# 定义初始光线参数
u0 = 0.01 # 小角度(弧度)
# 计算第一个面的光线高度
h0 = -entrance_pupil_position * u0
# 进行近轴光线追迹
h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0)
# 计算出瞳距:l' = -h_final / u_final
if abs(u_final) < 1e-10: # 防止除零错误
return float('inf')
return -h_final / u_final
def calculate_ideal_image_height(system):
"""
计算理想像高
:param system: OpticalSystem对象
:return: 理想像高(mm)
"""
# 获取系统焦距
focal_length = calculate.calculate_focal_length(system.surfaces)
if system.object_infinite: # 无穷远物
# 理想像高 y0' = -f' * tan(ω)
field_angle_rad = math.radians(system.field_angle)
return -focal_length * math.tan(field_angle_rad)
else: # 有限远物
# 获取理想像距
ideal_image_distance = calculate.calculate_ideal_image_distance(
system.surfaces,
system.object_infinite,
system.object_distance
)
# 获取主面位置
principal_plane = calculate.calculate_principal_plane_position(system.surfaces)
# 计算实际像位置(从最后一个面顶点)
actual_image_position = ideal_image_distance + principal_plane
# 计算放大率 β = l'/l
# l = -object_distance(物在左侧为负)
magnification = actual_image_position / (-system.object_distance)
# 理想像高 y0' = β * y
return magnification * system.object_height
def trace_real_ray(surfaces, h0, u0, l0):
"""
实际光线追迹函数
:param surfaces: 光学表面列表
:param h0: 初始光线高度
:param u0: 初始光线角度(弧度)
:param l0: 初始光线距离(mm)
:return: 最后的光线距离和角度
"""
h = h0
u = u0
L = l0 # 当前光线距离
npre = 1
LL = []
#初始化内部变量
si = 0
sii = 0
uu = 0
for i, surf in enumerate(surfaces):
# 计算曲率(平面时曲率为0)
c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r
if(i == 0 and u==0.0):
si = h/surf.r
else:
si = (L-surf.r)*np.sin(u)/surf.r
sii = npre*si/surf.nd
uu = u +np.arcsin(si)-np.arcsin(sii)
L = surf.r+surf.r*sii/np.sin(uu)
#传递到下一个表面
if i < len(surfaces) - 1:
u = uu
L = L -surf.d
npre = surf.nd # 折射后折射率
LL.append(L)
return LL, uu
def calculate_actual_image(system):
"""
计算轴上点的实际像位置(相对于最后一个面顶点)
参数:
system: OpticalSystem对象,包含:
- surfaces: 表面列表
- entrance_pupil_diameter: 入瞳直径 (mm)
- entrance_pupil_position: 入瞳位置 (相对第一个面顶点) (mm)
- aperture_coefficient: 孔径系数 (0~1)
- object_infinite: 物是否在无穷远
- object_distance: 物距 (有限远时) (mm)
- light_type: 色光类型 (这里只影响折射率选择)
返回:
实际像位置 (mm) (正值表示在最后一个面右侧)
"""
# 1. 计算实际入瞳半径
actual_entrance_radius = (system.entrance_pupil_diameter * system.aperture_coefficient) / 2
# 2. 根据物方情况设置初始光线参数
if system.object_infinite:
# 无穷远物:光线平行于光轴
u0 = 0.0 # 初始角度 (弧度)
h0 = actual_entrance_radius # 初始高度 (取入瞳边缘)
l0 = 0 # 物方截距 (无穷远)
L_final,uu= calculate.trace_real_ray(system.surfaces, h0, u0, l0)
else:
# 有限远物
# 计算物点到入瞳平面的距离
d_object_to_entrance = system.object_distance - system.entrance_pupil_position
# 计算初始角度 (物点发出的光线通过入瞳边缘)
u0 = math.atan(actual_entrance_radius / d_object_to_entrance)
l0 = system.object_distance # 负号表示在左侧
h0 = 0
L_final,uu = calculate.trace_real_ray(system.surfaces, h0, u0, l0)
return L_final[-1]
实际像高的计算思路是什么
最新发布