幾何光學光線資料結構的建立
利用numpy 可以非常友善的建立一個矩陣,用以存儲光路。
以幾何光學為例,光線是由一系列的射線和線段組成。
那麼比較直覺的建立其資料結構的方案就是建立一個歐式坐标系下的矩陣,并且以點法式為優
在空間中直線的方程可以表達為:

而一個輸入鏡頭的光線的集合主要包含以下幾個參數:視場角,波長,光線的相對分布。
對比zemax軟體。一般來說視場角可以自己定義,波長也可以,而光線的相對分布主要包括兩種形式,一種是環臂形式的最終計算loss函數用高斯距離,一種是方形分布,類似于一些繪圖軟體中的陣列操作
那麼構成的資料結構應該是一個這樣的:
視場角數量:f_number
波長數量:w_number
環:rings
臂:arms
或者點陣數量:rect_count
那麼其形狀為:shape = (f_number,w_number,rings,arms)或者(f_number,w_number,rect_count,rect_count)對于環臂結構,由于在優化過程中,鏡頭都是軸對稱的。是以沒有必要計算全部的arms
僅僅用計算一半+1是以最後一個參數修正為arms/2+1
import tensorflow as tf
import numpy as np
class CreateRays:
"""
which block to create the initial rays ;
type = ndarray
the last return is self.rays
you can create the init rays data by code:
dform = "ring_arms"# or "rect"
cr = CreateRays(
count_field,
count_wave,
max_field_x,
max_field_y,
min_field_x = 0,
min_field_y = 0,
init_site = -10,
dform
)
"""
def __init__(
self,
count_field,
count_wave,
max_field_x,
max_field_y,
min_field_x = 0,
min_field_y = 0,
init_site = -10,
dform = "ring_arms"
):
"""
params: max_field_x ,max_field_y,min_field_x,min_field_y,describe the range of field type = float
max_wave,min_wave ,the range of wavelength type = float
init site is the plant which the ray's start so it must <0
dform:data form include ring-arms and rects
"""
self.max_field_x = float(max_field_x)
self.min_field_x = float(min_field_x)
self.max_field_y = float(max_field_y)
self.min_field_y = float(min_field_y)
self.max_field = (self.max_field_x**2+self.max_field_y**2)**0.5
self.min_field = (self.min_field_x**2+self.min_field_y**2)**0.5
self.count_field = int(count_field)
self.count_wave = int(count_wave)
self.dform = dform
if init_site >= 0:
raise ValueError("init_site must < 0!!!!")
self.init_site = init_site
if self.dform == "ring_arms":
self.rings_num = 3
self.arms_num = 6
self.__set_ring_arms()
elif self.dform == 'rect':
self.rect_shape_num = 4
self.__set_rect()
init 的部分主要搜集光線的點和向量的形狀參數,可以看到的是,歐式坐标并沒有被直接整體封裝結構中,這是因為光學器件表面并不都是球面或者中心旋轉對稱的結構,有時候可能要構造非常複雜的方程。而如果将所有坐标統一封裝,就會失去靈活性。而tensorflow對索引的操作又是衆所周知的坑。。。
設定光線在同一表面的分布
- 用以高斯積分和圓、環孔徑的環臂結構
LasyOpticalDesigner 0.1.0開發者日志(壹)幾何光學光線資料結構的建立
def __set_ring_arms(self):
self.x = self.y = self.z = np.zeros((
self.count_field,
self.count_wave,
self.rings_num,
int(self.arms_num/2+1)
))
self._angles = np.linspace(0.0,np.pi,int(self.arms_num/2+1))
self._ring_layer = np.linspace(0.0,1.0,self.rings_num)
self._ring_layer = self._ring_layer[1:]
self.kx = self.ky = self.kz = np.array(np.zeros_like(self.x))
- 用以方形孔徑的方陣結構 方形陣列分布
LasyOpticalDesigner 0.1.0開發者日志(壹)幾何光學光線資料結構的建立
def __set_rect(self):
self.x = self.y = self.z = np.zeros((
self.count_field,
self.count_wave,
self.rect_shape_num,
self.rect_shape_num
))
self.kx = self.ky = self.kz = np.array(np.zeros_like(self.x))
也可以自定義或者更改你的輸入
def get_rect(self,node_num):
self.rect_shape_num = node_num
self.__set_rect()
def get_ring_arms(self,rings_num,arms_num):
"""
set the rings and arms
"""
self.rings_num = rings_num
self.arms_num = arms_num
self.__set_ring_arms()
這裡獲得的最開始的參考點是經過一個manul2D.py子產品進行計算得到的
def get_init_reference_point(self,rp_x,rp_y,rp_z):
"""
you can directly create set of reference points by this method independence
"""
self.reference_x,self.reference_y,self.reference_z = rp_x,rp_y,rp_z
def __set_init_ring_arms(self,rp_x,rp_y,rp_z,init_radio):
"""
for every ray to set the initial data
for dtype = ring_arms
make the ring and arms at stop
params: rp_x,rp_y,rp_z:the start which the ray sent from
init_radio:define the range of ray starts
return:beam_ shape = self.rings_num,(self.arms_num/2+1),1;
type = ndarray
"""
x = y = z = np.array(np.zeros((self.rings_num,int(self.arms_num/2+1))))
for r_i in range(len(self._ring_layer)):
for angle_i in range(len(self._angles)):
x[r_i,angle_i] = rp_x + self._ring_layer[r_i]*np.cos(self._angles[angle_i])
y[r_i,angle_i] = rp_y + self._ring_layer[r_i]*np.sin(self._angles[angle_i])
z[r_i,angle_i] = rp_z
return x,y,z
将(從2D操作得來的)資料輸入,按照兩種光線分布展開。并計算出真正的出發點和初始光線方向。建構ndarray
def feed_init_data(self,init_x,init_y,init_z,init_radio):
"""
params: init_x,y,z :the ray's start which caculate by 2Dmanul.py or define by yourself
init_radio : the ray's start range which define by 2Dmanul.py or by yourself
the main function!!
init reference points : from block 2D,manul.py
"""
if len(init_x) != self.count_field:
raise ValueError("the input has sth. length error")
for f_index in range(len(init_x)):
for w_index in range(self.count_wave):
if self.dform == "ring_arms":
self.x[f_index,w_index],self.y[f_index,w_index],self.z[f_index,w_index]=self.__set_init_ring_arms(
init_x[f_index],init_y[f_index],init_z[f_index],init_radio
)
elif self.dform == "rect":
self.x[f_index,w_index],self.y[f_index,w_index],self.z[f_index,w_index]=self.__set_init_rect(
init_x[f_index],init_y[f_index],init_z[f_index],init_radio
)
self.__caculate_direct()
賦初值操作
def __set_init_rect(self,init_x,init_y,init_z,init_radio):
"""
for dtype = rect
make the rect matrix at stop
params: init_rp,init_radio:
return:beam_ shape = self.rect_shape_num,self.rect_shape_num;
type = ndarray
"""
_x = init_x-init_radio
x = init_x+init_radio
_y = init_y-init_radio
y = init_y+init_radio
xs = np.linspace(_x,x,self.rect_shape_num)
ys = np.linspace(_y,y,self.rect_shape_num)
x_ = y_ = z_ = np.array(np.zeros((self.rect_shape_num,self.rect_shape_num)))
for i in range(self.rect_shape_num+1):
for j in range(self.rect_shape_num+1):
x_[i,j] = xs[i]
y_[i,j] = ys[i]
z_[i,j] = 0.0
return x_,y_,z_
建立視場角
def __create_field(self):
dfield =self.max_field - self.min_field
dfields = [self.min_field+dfield*0.7071**i for i in range(self.count_field-1)]
dfields.reverse()
fields = [self.min_field] + dfields
return fields
計算初始方向
def __caculate_direct(self):
fields = self.__create_field()
directs = []
for each in fields:
directs.append([
0.0,-np.tan(each),1.0
])
for field_i in range(self.count_field):
for wave_i in range(self.count_wave):
for row in range(len(self.kx[field_i,wave_i])):
for col in range(len(self.kx[field_i,wave_i,row])):
self.kx[field_i,wave_i,row,col] = directs[field_i][0]
self.ky[field_i,wave_i,row,col] = directs[field_i][1]
self.kz[field_i,wave_i,row,col] = directs[field_i][2]
為給2dmanul提供資料的形狀
def get_ray_2D(self):
self.rp_2D_r = self.rp_2D_z = np.array(np.zeros((self.count_field, 3)))
fields = self.__create_field()
self.ray_2D_r = -np.tan(np.array(fields))
self.ray_2D_z = np.array(np.ones_like(self.ray_2D_r))
for i in range(len(self.rp_2D_z)):
self.rp_2D_z[i] = self.init_site
self.ray_2D_r = self.ray_2D_r*self.ray_2D_z