More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  光学设计的秘密花园ProfileFriendsBlogMore Tools Explore the Spaces community

Blog

November 26

先生归去后 谁坐此船来

  张大千临摹了几百张明代石涛的山水,画出的画以假乱真,后来他去敦煌潜心临摹几年,回来画风大变,终成大家。

  那我就转载一下百度百科的词条警醒一下自己。微笑

...

  对于石涛他尤为推崇,他用了大量精力去学习石涛的绘画艺术,把石涛的艺术比喻成万里长城。他还从李瑞清之弟李筠庵学会仿制古画的方法,并做了许多石涛的赝品,曾多次骗过程霖生。石涛画境变化无尽,新颖怪奇而又法度严谨,大千正是通过石涛而涵泳了唐宋元明百家之长。在二十年代的上海他获得了"石涛专家"的美誉。

...

  40年代,张大千自费赴敦煌,耗时三年大量临摹了石窟壁画,并将之宣传介绍,使敦煌艺术宝库从此为国人和世界广为瞩目。从此,张大千的画风也为之一变,善用复笔重色,高雅华丽,潇洒磅礴,被誉为“画中李白”、“今日中国之画仙”。1942年,春末,他决定举家赴敦煌临摹壁画。在敦煌的生活是艰苦的,恶劣的气候条件,再加上住在与世隔绝的石洞子里对于一般人是无法忍受的,但对于一个艺术家却可能是有益的。大千在此时画风为之一变,他善用复笔重色,笔力也变得丰厚浓重。可以说在敦煌时期对他风格形成起到了至关重要的作用。他不仅考察莫高窟的壁画佛像,还对莫高窟进行了编号,成为了为莫高窟编号的第一人,为保存文化遗产做了积极的贡献。他还到达青海西宁,邀请藏族画师共同赴敦煌协助临摹工作。为尊重他人劳动成果和对摹品的负责,每幅画上都注明了画家的名字,凡与他合作也注明了作者的名字,所以在他许多临摹的敦煌壁画中都标有"番僧某某同画"。两年后他结束了在莫高窟的临摹工作,同时开始了对安西榆林窟的临摹工作。

  在离开莫高窟后,他花了大量时间对十六国、北魏、北周、隋、唐、五代、宋、西夏、元各朝的壁画代表作及雕塑进行了临摹,共有摹品共记三百多幅。...

November 24

流年暗中偷换 之一

  从入行以来,一直都有这样几个疑问,盘桓在我的心头,挥之不去。

  一, 高斯光束通过实际透镜的情况下,高斯光束变换和像差的综合作用是什么?

  二, 厄米高斯光束和拉盖儿高斯光束在用几何光学的处理方法上有什么不同?

  三, 基于光线追迹的变换处理方法得到物理光学演算结论的能力极限在哪里?

  在这里,我刻下一个对明年的承诺:明年年底的时候,我要解决这三个疑问。

  赤手缚虎?不,我不是周处。我需要找到一些工具。首先就是“the ray and wave theory of lenses”。最早知道这本书,是陈志隆老师的推荐。

…报告完这本书之后, 会再念另一本书;念的是A. Walther, "the ray and wave theory of lenses",(习题要作;写程序的要用Mathematica与OSLO's ccl或dll programming);之后才会读期刊论文.谈作论文研究.

--- Walther的书是作进阶开发的基础

--- Mathematica 是为了symbolic calculation用

--- OSLO's ccl 与 dll programming 是为作 optical module 研发的implementation用

  看起来这本书很是被重视。究竟内容如何呢,我在这里下载了部分内容,并翻译在下面。

  现代光学的很多书籍,常常局限于近轴范围来处理透镜理论。像差则被当作近轴理想的一个补丁。这些书中一直没有解释清楚的是,像差的存在是由于物理法则还是由于设计者有限的技艺。读者一直被灌输这样的观点,镜头的设计必须尽可能的遵循近轴光学的成像规律。这种说法令人遗憾。因为从十八世纪我们就知道,如果将近轴光学的公式用于有限的高度和角度,则会导出投影几何。这是数学中一个重要分支。但对于实际透镜的行为而言,这是一个糟糕的描述。

  过去四十年傅立叶光学的发展让透镜理论和物理实际之间更加接近。但由于许多作者不顾及实验室中大孔径镜头的普遍存在,在处理成像公式理论时满足于近轴近似,导致有很多光学见解的遗漏。笔者认为,要么能够提供一个清晰且令人信服的验证,说明近轴近似可靠的适用于大孔径和大视场;要么应该可靠的发展一套没有近轴近似的光学理论。这套可靠的理论是存在的,不过被埋没于充满细节描述的书籍和论文中,以致于初学者迷失于数学描述的错综复杂之中。

  本书的主要目的是描述古老而完备的eikonal函数可以用来发展一套镜头的理论,可同时在几何光学和波动光学成像理论中,很好的处理于大孔径大视场的情况。笔者尽力遵循一下三条原则:

  • 几何光学和物理光学之间的联系不能只是无实际意义的数学推导,而必须是一个有力的工程工具,使得读者可以在几何光学和物理光学中互相推导切换。
  • 能量守恒必须是这套理论的组成部分。避免出现神秘而不确定的振幅因子。
  • 不考虑只是优雅的理论。任何获得的结果必须有助于讨论更深入,或者有其实际应用。

  很好,就是它了!

October 05

用CCL实现手工设计Cooke Triplet

  《透镜设计基础》中第314页到第321页详述了用手工计算的方法设计一个Cooke式三片镜,也就是K. Schwarzschild方法。在以下的内容中,首先演示如何cooke_triplet命令进行Cooke式三片镜的设计,然后讲解如何将这一方法整合到OSLO的环境中。

  启动OSLO,在lens spreadsheet关闭时按Ctrl+D,出现如下对话框,每一参数的意义请参照《透镜设计基础》中的解释。

Cooke triplet command

  点选OK,然后在命令行中依照提示依次输入三个镜片的中心厚度,比如0.40.250.45,分别按回车键确认。这时,当前的OSLO环境中已经生成了一个符合参数要求的Cooke式三片镜,分析图如下。

 

RIC

  从图中可以看出子午像面过于前倾,可以适当调整一下。将AC的预设值从-0.09调整到-0.06

 

Cooke triplet command

  分析新的镜头,可以看到子午像面不再严重前倾,像散有所改善。

 

RIC

  讲解如何将这一方法整合到OSLO的环境中。首先打开\private\ccl\a_menu.ccl文件,加入下图中的高亮部分。

 

Hotkey

  再打开\private\ccl\a_global.ccl加入下列内容。

 

double y1 {default(noquery) = 1.111111};

double y2 {default(noquery) = 0.888888};

double y3 {default(noquery) = 0.999999};

double rn1 {default(noquery) = 1.620318};

double vn1 {default(noquery) = 60.31};

double rn2 {default(noquery) = 1.616445};

double vn2 {default(noquery) = 36.62};

double rn3 {default(noquery) = 1.620318};

double vn3 {default(noquery) = 60.31};

double total_efl {default(noquery) = 10};

double lch {default(noquery) = -0.02};

double Petzval {default(noquery) = 0.035};

double K_aim {default(noquery) = 1};

double fie_ang {default(noquery) = 20};

int step {default(noquery) = 500};

double c1_start {default(noquery) = 0.2};

double c1_end {default(noquery) = 0.4};

double SC_target {default(noquery) = -0.08};

double CC_target {default(noquery) = 0.0025};

double AC_target {default(noquery) = -0.09};

double TchC_target {default(noquery) = 0.0};

double Wav1 {default(noquery) = 0.5892938};

double Wav2 {default(noquery) = 0.4861327};

double Wav3 {default(noquery) = 0.6562725};

最后是函数的主体部分,编译后就可以了。

cmd scalecv(int start_surf, int end_surf, float efl)

{

float feedback=1.0;

stp outp off;

int counter;

do{

for(counter=start_surf;counter<end_surf+1;counter++)

cv(counter,cv[counter]*feedback);

feedback=pe_efl(start_surf,end_surf)/efl;

}

while(fabs(feedback-1)>0.00000001);

stp outp on;

}

cmd Gsum ( float refra_index, float result[] )

{

result[0] = 0;

result[1] = refra_index * refra_index * ( refra_index - 1 ) / 2 ;

result[2] = ( 2 * refra_index + 1 ) * ( refra_index - 1 ) / 2 ;

result[3] = ( 3 * refra_index + 1 ) * ( refra_index - 1 ) / 2 ;

result[4] = ( refra_index + 2 ) * ( refra_index - 1 ) / ( 2 * refra_index ) ;

result[5] = 2 * ( refra_index + 1 ) * ( refra_index - 1 ) / refra_index ;

result[6] = ( 3 * refra_index + 2 ) * ( refra_index - 1 ) / ( 2 * refra_index ) ;

result[7] = ( 2 * refra_index + 1 ) * ( refra_index - 1 ) / ( 2 * refra_index );

result[8] = refra_index * ( refra_index - 1 ) / 2;

}

double SC_coef[3];

double CC_coef[3];

double AC_coef[3];

double SC_ap_coef[3];

double CC_ap_coef[3];

double AC_ap_coef[3];

cmd sc_sei(double sc_sei_coef[], double y_para, double u_prime_0, double G_sum[], double curvature, double inv_objdist)

{

//calculate the constant

double temp_coef_for_all;

int ii;

temp_coef_for_all = -1 * y_para * y_para * y_para * y_para / ( u_prime_0 * u_prime_0 );

sc_sei_coef[0] = G_sum[1] * curvature * curvature * curvature;

sc_sei_coef[1] = -1 * G_sum[2] * curvature * curvature;

sc_sei_coef[0] += G_sum[3] * curvature * curvature * inv_objdist;

sc_sei_coef[2] = G_sum[4] * curvature;

sc_sei_coef[1] += -1 * G_sum[5] * curvature * inv_objdist;

sc_sei_coef[0] += G_sum[6] * curvature * inv_objdist * inv_objdist;

for (ii = 0; ii < 3; ii++)

{

sc_sei_coef[ii] *= temp_coef_for_all;

}

}

cmd cc_sei(double cc_sei_coef[], double y_para, double h_prime_0, double G_sum[], double curvature, double inv_objdist)

{

double temp_coef_for_all;

int ii;

temp_coef_for_all = -1 * y_para * y_para * h_prime_0;

cc_sei_coef[1] = 0.25 * G_sum[5] * curvature;

cc_sei_coef[0] = -1 * G_sum[7] * curvature * inv_objdist;

cc_sei_coef[0] += -1 * G_sum[8] * curvature * curvature;

cc_sei_coef[2] = 0;

for (ii = 0; ii < 3; ii++)

{

cc_sei_coef[ii] *= temp_coef_for_all;

}

}

cmd ac_sei(double ac_sei_coef[], double h_prime_0, double fl )

{

ac_sei_coef[0] = -0.5 * h_prime_0 * h_prime_0 / fl;

ac_sei_coef[1] = 0;

ac_sei_coef[2] = 0;

}

cmd sc_ap(double ap_shift[], double ap_attached[])

{

for (ii = 0; ii < 3; ii++)

{

ap_shift[ii] = ap_attached[ii];

}

}

cmd cc_ap(double cc_ap_shift[], double cc_ap_attached[], double sc_ap_attached[], double q_factor, double u_prime_0)

{

for (ii = 0; ii < 3; ii++)

{

cc_ap_shift[ii] = cc_ap_attached[ii] + sc_ap_attached[ii] * q_factor * u_prime_0;

}

}

cmd ac_ap(double ac_ap_shift[], double ac_ap_attached[], double cc_ap_attached[], double sc_ap_attached[], double q_factor, double u_prime_0)

{

for (ii = 0; ii < 3; ii++)

{

ac_ap_shift[ii] = ac_ap_attached[ii] + cc_ap_attached[ii] * 2 * q_factor / u_prime_0 + sc_ap_attached[ii] * q_factor * q_factor;

}

}

cmd cooke_triplet(double y1, double y2, double y3, double wav1, double wav2, double wav3, double rn1, double vn1, double rn2, double vn2,

double rn3, double vn3, double total_efl, double SC_target, double CC_target, double AC_target,

double Petzval, double lch, double TchC_target, double K_aim, double fie_ang, double c1_start, double c1_end, int step)

{

stp outp off;

double phi[3];

double y[3];

y[0] = y1; y[1] = y2; y[2] = y3;

double v[3];

v[0] = vn1; v[1] = vn2; v[2] = vn3;

double n[3];

n[0] = rn1; n[1] = rn2; n[2] = rn3;

double phi_total;

phi_total = 1/total_efl;

static double u0_obj = 0, u0_ims;

u0_ims = y1/total_efl;

double ptz;

ptz=Petzval;

double coef_phi[3][3], verctor_aber[3];

double ua, ub, uc;

ua=u0_obj;

double airspace_1, airspace_2;

double K;

double k_new, delta_yb, delta_yc;

double upr[4], ypr[3];

upr[0] = tan(-1*fie_ang*dr);

double TchC[3];

double TchC_total, TchC_total_new, TchC_aim;

TchC_aim = TchC_target;

for ( ii = 0, TchC_total = -0.02, delta_yc = 0.01, k = 0.5, delta_yb = 0.01 ; ii < 200; ii++)

{

y[2] += delta_yc;

for ( jj = 0; jj < 200; jj++)

{

y[1] += delta_yb;

for ( i = 0; i < 3; i++) coef_phi[0][i] = y[i];

for ( i = 0; i < 3; i++) coef_phi[1][i] = y[i] * y[i] / v[i];

for ( i = 0; i < 3; i++) coef_phi[2][i] = 1 / n[i];

verctor_aber[0] = y[0] * phi_total;

verctor_aber[1] = -1 * lch * u0_ims * u0_ims;

verctor_aber[2] = Ptz;

slveqs( coef_phi, phi, verctor_aber);

/////////////////////////

//ub uc is at object-side

/////////////////////////

ub = ua + y[0] * phi[0];

uc = ub + y[1] * phi[1];

airspace_1 = ( y[0] -y[1]) / ub;

airspace_2 = ( y[1] -y[2]) / uc;

K_new = airspace_1 / airspace_2;

if ( fabs( K_new - K_aim ) < 0.000001 ) break;

delta_yb = ( K_aim - K_new ) * delta_yb / ( K_new - K );

k = k_new;

}

ypr[0] = airspace_1 * upr[0] / ( 1 - airspace_1 * phi[0] ); ypr[1] = 0; ypr[2] = -1 * ypr[0] / k_new;

upr[1]= upr[0] + ypr[0] * phi[0];

upr[2]= upr[1] + ypr[1] * phi[1];

upr[3]= upr[2] + ypr[2] * phi[2];

TchC[0] = ( -1 * y[0] * ypr[0] * phi[0] ) / ( V[0] * u0_ims);

TchC[1] = 0;

TchC[2] = ( -1 * y[2] * ypr[2] * phi[2] ) / ( V[2] * u0_ims);

TchC_total_new = TchC[0] + TchC[1] + TchC[2];

if ( fabs( TchC_total_new - TchC_aim ) < 0.000001 ) break;

delta_yc = ( TchC_aim - TchC_total_new ) * delta_yc /( TchC_total_new - TchC_total );

TchC_total = TchC_total_new;

}

int lensID;

double g_coef[9];

double sc_coef[3][3];

double cc_coef[3][3];

double ac_coef[3][3];

double sc_ap_coef[3][3];

double cc_ap_coef[3][3];

double ac_ap_coef[3][3];

double temp_sc_coef[3];

double temp_cc_coef[3];

double temp_ac_coef[3];

double temp_sc_ap_coef[3];

double temp_cc_ap_coef[3];

double temp_ac_ap_coef[3];

double u0_=u0_ims;

double c[3];

c[0] = phi[0]/(n[0]-1);

c[1] = phi[1]/(n[1]-1);

c[2] = phi[2]/(n[2]-1);

double inv[3];

inv[0] = ua/y[0];

inv[1] = ub/y[1];

inv[2] = uc/y[2];

double h0_;

h0_= (ypr[2]-upr[3]*(y[2]/(uc+y[2]*phi[2])));

double q[3];

q[0] = ypr[0]/y[0];

q[1] = ypr[1]/y[1];

q[2] = ypr[2]/y[2];

for (lensID=0; lensID<3; lensID++)

{

gsum(n[lensID], g_coef);

//for(i=1; i<9; i++) prt g_coef[i];

//prt "=============================";

sc_sei(temp_sc_coef, y[lensID], u0_, g_coef, c[lensID], inv[lensID]);

for(i=0; i<3; i++)

{

sc_coef[i][lensID]=temp_sc_coef[i];

//aprt sc_coef[i][lensID];

};

//prt;

cc_sei(temp_cc_coef, y[lensID], h0_, g_coef, c[lensID], inv[lensID]);

for(i=0; i<3; i++)

{

cc_coef[i][lensID]=temp_cc_coef[i];

//aprt cc_coef[i][lensID];

};

//prt;

ac_sei(temp_ac_coef, h0_, (1/phi[lensID]));

for(i=0; i<3; i++)

{

ac_coef[i][lensID]=temp_ac_coef[i];

//aprt ac_coef[i][lensID];

};

//prt;

sc_ap(temp_sc_ap_coef, temp_sc_coef);

for(i=2; i>-1; i--)

{

sc_ap_coef[i][lensID]=temp_sc_ap_coef[i];

//aprintf("%f\t", sc_ap_coef[i][lensID]);

};

//prt;

cc_ap(temp_cc_ap_coef, temp_cc_coef, temp_sc_coef, q[lensID], u0_);

for(i=2; i>-1; i--)

{

cc_ap_coef[i][lensID]=temp_cc_ap_coef[i];

//aprintf("%f\t", cc_ap_coef[i][lensID]);

};

//prt;

ac_ap(temp_ac_ap_coef, temp_ac_coef, temp_cc_coef, temp_sc_coef, q[lensID], u0_);

for(i=2; i>-1; i--)

{

ac_ap_coef[i][lensID]=temp_ac_ap_coef[i];

//aprintf("%f\t", ac_ap_coef[i][lensID]);

};

//prt;

}

double surf_curv[6];

double AC_1_2;

double c5_coef[3];

double a,b,cc;

double c5[3];

double CC_1_3;

double c3;

double SC_total;

int srfID;

for (ii=1; ii<step; ii++)

{

surf_curv[0] = c1_start + ii*(c1_end - c1_start)/(step-1) ;

//prt surf_curv[0];

//change the C1, to get the C5;

//caculate AC*_1

AC_1_2 = ac_ap_coef[2][0] * surf_curv[0] * surf_curv[0] + ac_ap_coef[1][0] * surf_curv[0] + ac_ap_coef[0][0];

AC_1_2 += ac_ap_coef[0][1];

//prt "AC*_1_2=" AC_1_2;

c5_coef[2] = ac_ap_coef[2][2]; c5_coef[1] = ac_ap_coef[1][2];

c5_coef[0] = ac_ap_coef[0][2] + AC_1_2 - AC_target;

//prt "C5^2, C5^1, C5^0" (c5_coef[2]/c5_coef[2]) (c5_coef[1]/c5_coef[2]) (c5_coef[0]/c5_coef[2]);

a=c5_coef[2]; b=c5_coef[1]; cc=c5_coef[0];

//prt (b*b-4*a*cc);

if ( b*b-4*a*cc < 0 )

prt "No solution.";

else { c5[2] = (-1*b + sqrt(b*b-4*a*cc))/(2*a); c5[1] = (-1*b - sqrt(b*b-4*a*cc))/(2*a);}

//choose the less bending one, coef_calculating can be used

c5[0]=c5[1];

CC_1_3 = cc_ap_coef[2][0]*surf_curv[0]*surf_curv[0] + cc_ap_coef[1][0]*surf_curv[0] + cc_ap_coef[0][0];

CC_1_3 += cc_ap_coef[2][2]*c5[0]*c5[0] + cc_ap_coef[1][2]*c5[0] + cc_ap_coef[0][2];

//prt "CC_1_3=" CC_1_3;

c3 = (-1*cc_ap_coef[0][1]+(-1*CC_1_3)+CC_target)/cc_ap_coef[1][1];

//prt "C3=" c3;

sc_total = sc_ap_coef[2][0]*surf_curv[0]*surf_curv[0] + sc_ap_coef[1][0]*surf_curv[0] + sc_ap_coef[0][0];

sc_total += sc_ap_coef[2][1]*c3*c3 + sc_ap_coef[1][1]*c3 + sc_ap_coef[0][1];

sc_total += sc_ap_coef[2][2]*c5[0]*c5[0] + sc_ap_coef[1][2]*c5[0] + sc_ap_coef[0][2];

if (fabs(sc_total-SC_target)<0.001)

{

aprt "total SC = " sc_total;

aprt "C1, C3, C5" surf_curv[0] c3 c5[0];

break;

}

}

double th1;

double th2;

double th3;

input th1 "TH1";

input th2 "TH2";

input th3 "TH3";

len new "Cooke draft" total_efl;

ebr y1;

ang 1e-20;

des "ZhangJing";

uni 1.0;

sno1 "Produced by design_cooke.ccl";

wv wav1 wav2 wav3;

WW 1.0 1.0 1.0;

//srf 0

air;

ap 2e+19;

th 1.0e+20;

//srf 1

NXT;

gla mod "glass1" n[0] v[0];

cv surf_curv[0];

th th1;

ap noc y[0];

//srf 2

NXT;

air;

cv surf_curv[0]-c[0];

th airspace_1;

ap noc y[0];

//srf 3

NXT;

gla mod "glass3" n[1] v[1];

cv c3;

th th2;

ap noc y[1];

//srf 4

NXT;

air;

cv c3-c[1];

th airspace_2;

ap noc y[1];

ast;

//srf 5

NXT;

gla mod "glass5" n[2] v[2];

cv c5[0];

th th3;

ap noc y[2];

//srf 6

NXT;

air;

cv c5[0]-c[2];

th 0.0;

ap noc y[2];

//IMS

NXT;

air;

ap noc 0.0;

end;

stp outp on;

aprt (1/phi[0]);

aprt (1/phi[1]);

aprt (1/phi[2]);

scalecv(1,2, 1/phi[0]);

scalecv(3,4, 1/phi[1]);

scalecv(5,6, 1/phi[2]);

nodp(1,2,1);

e=ssb(sbrow-1,4);

nodp(3,4,1);

f=ssb(sbrow-1,3);

h=airspace_1+e-f;

th(2, h);

nodp(3,4,1);

e=ssb(sbrow-1,4);

nodp(5,6,1);

f=ssb(sbrow-1,3);

h=airspace_2+e-f;

th(4, h);

tra std loc All usr 1 0 n 1;

for (ii =1; ii<ims; ii++) ap(ii, chk, ssb(sbrow-8,1)+0.000001);

auf pxl;

ang fie_ang;

f 4 ins 1.2 0 0 0 0 -1.0 1.0 -1.0 1.0 1.0 0 0;

vig y y 5;

dlnr 1 0;

drw ims on;

stp outp on;

}

March 25

失落的命令

可以在帮助文档中找到关于text_toolbar_properties1的主题吗?
 
OSLO
March 07

找出合适光阑位置的辅助工具

一些光学设计方面经验较少的初学者常会难于合理地设置光阑位置。例如下图,是测绘一个镜头后构建的系统。容易看出来,光阑被设置在不正确的位置上了。

 

1,错误的光阑位置

下面以OSLO内置的\public\len\demo\edu\demotrip.len文件为例来说明如何使用ap_st函数来找到合适的光阑位置。

 

2demotrip.len

打开这个三片镜后,在命令行输入AP_ST(20, -5, 30)20即是镜头的视场角,-530是以镜头的第一个光学面顶点(图2中箭头所指处)为原点,在向左5mm,向右30mm的范围内搜索合适的光阑位置。文本窗口中输出结果如下。

$ The most possible position...

   8.571429

$ The most possible position...

  15.357143

$ The position below also can be tried...

  11.785714

输出的数值即是以镜头的第一个光学面顶点(图2中箭头所指处)为原点的位置。该三片镜原有光阑位置为9mm2mm + 6mm + 1mm),和第一个推荐的位置8.571429很接近。

现在用AP_ST(30, 0, 15)来寻找图一中合适的光阑位置。

$ The position below also can be tried...

   8.469388

比对原始结构的数值后,发现胶合镜片的后一面是最接近这一数值的可能设置光阑的面,如下图。

 

3,正确的光阑位置

源码如下

 cmd ap_st(float half_angle, float left_end, float right_end)
{
 int ii, anchor;
 int step=99;
 float step_length;
 
 float original_ang, original_th0, original_th_ims;
 float L_position[step], ray_height[step];
 float derivative1st[step], derivative2nd[step];
 
 //check whether obj dist is infinity
 if(th[0]<1e20) abort("This is not an infinite conjugate system.");
 
 original_ang=ang/dr;
  
 stp outp off;
 anchor=sbrow;
 
 sbr anchor 1; 
 half_angle *= 0.7;
 ang(half_angle);
 original_th0=th[0];
 original_th_ims=th[ims];
 auf pxl;
 //delete all the solve
 for ( ii = 1; ii <= Imsnbr; ii++ )
 {
  tsd(ii);                     // delete thickness solve on surface
  csd(ii);                     // delete curvature solve on surface
  if (apchk[ii]) ap(ii, noc, ap[ii]); // if aperture checking is on,                 
   
 } 

 th(0,-1*left_end);
 
 for ( ii = 0; ii < step; ii++)
 {
  L_position[ii]=ii*(right_end-left_end)/(step-1);
  trb ful loc 0 0 L_position[ii] sin(half_angle*dr) 0 cos(half_angle*dr) 1 0 ims n;
  ray_height[ii]=ssb(sbrow-3,1);
  L_position[ii]+=left_end;
 }

 //calculate the 1st and 2nd derivative
 step_length=(right_end-left_end)/(step-1);
 
 for ( ii = 0; ii < step; ii++)
 {
  if (ii==step-1)
  {
   derivative1st[ii]=derivative1st[ii-1];
   break;
  }
  derivative1st[ii]=(ray_height[ii+1]-ray_height[ii])/step_length;
 }
 
 prt; prt  "*********************************"; prt;
 for ( ii = 1; ii < step-1; ii++)
 {
    if((ray_height[ii]-ray_height[ii-1])*(ray_height[ii]-ray_height[ii+1])>0)
    { 
     prt  "$ The most possible position...";
     prt  L_position[ii];
  }
 }

 for ( ii = 0; ii < step-2; ii++)
 {
  if (ii==step-1)
  {
   derivative2nd[ii]=derivative2nd[ii-1];
   break;
  }
  derivative2nd[ii]=(derivative1st[ii+1]-derivative1st[ii])/step_length;

 }

 for ( ii = 1; ii < step-1; ii++)
 {
    if((derivative1st[ii]-derivative1st[ii-1])*(derivative1st[ii]-derivative1st[ii+1])>0)
    { prt  "$ The position below also can be tried...";
     prt  L_position[ii];
  }
 }
 prt; prt  "*********************************";
 th(0, original_th0);
 th(ims, original_th_ims);
 ang(original_ang);
 
 sbr -1*anchor 0;
 stp outp on;
 return;
}

December 26

GENII zoom version

  1993年,Sinclair Optics收购Genesee Optics Software后,OSLO获得了GENII中很多有特色的功能。 简洁、高效的GENII评价函数就是其中之一。随着OSLO历次升级,GENII评价函仅在细节上略有演化——光线数减少等等。
  然而,内置的GENII始终不支持zoom结构。或许OSLO原厂有其在光学设计实际意义上的考虑。但能将高效的GENII用于相对收敛较慢的zoom优化,总是一件好事。出于这个考虑我改写了可用于zoom结构的GENII评价函数生成程序。这个程序是对OSLO内置的geniierf修改而来,并且参考了Doffery的工作完成的,在此一并感谢。
 

#ifndef _OSLO_LIGHT_

#include "../../public/ccl/inc/gendefs.h"

cmd geniierf_zoom(double design_frequency_z, double f1_fymax_z, double f2_fymin_z,
             double f2_fymax_z, double f2_fx_z, double f3_fymin_z, double f3_fymax_z, double f3_fx_z,
             double f2_distol_z, double f3_distol_z, int max_cfg)
// hlp:  <P class="Edition">OSLO Premium/OSLO Standard</P>
// hlp:  <P>Generates a <a href="../optim/generation/genii.htm">Genii error function</a>.</P>
// kwd:  genii, error function, OCM, optimisation, error function builder
// cat:  optimization
{
 double uprime, dy, tmp;
 int    ssrow;
 char   tmpstr[32];
 int   opr_grp = 43;  /* operands number for one configuration */

 set_preference(output_text, off);
 ssrow = sbrow();
 ssbuf_reset(ssrow, 50);
 
 /* basic transverse tolerance Dy */
 dy = 1.0/(6.0*design_frequency_z);

 /* delete old operands to enable new ray set */
 operands(new);
 end;

 /* construct new ray set */
 rayset(new);
 /* field points <fby fbx fbz fyrf fxrf fymin fymax fxmin fxmax wgt> */
 f(1, 0.0, 0.0, 0.0, 0.0, 0.0, -f1_fymax_z, f1_fymax_z, -f1_fymax_z, f1_fymax_z, 1.0);
 f(2, 0.7, 0.0, 0.0, 0.0, 0.0, f2_fymin_z, f2_fymax_z, -f2_fx_z, f2_fx_z, 1.0);
 f(3, 1.0, 0.0, 0.0, 0.0, 0.0, f3_fymin_z, f3_fymax_z, -f3_fx_z, f3_fx_z, 1.0);
 /* rays <type fy fx> */ 
 r(1, ref,  0.0, 0.0);
 r(2, ord,  1.0, 0.0);
 r(3, ord, -1.0, 0.0);
 r(4, ord,  0.0, 1.0);
 end(); 

  /* new operand set */
 operands(new);
 end;
 for ( i = 1; i < maxcfg + 1; i++)
 {
  /* switch to different configuration*/

  cfg chg i;

  /* get current paraxial axial ray slope */
  paraxial_trace();
  uprime = -ssb(sbrow-1, 2);

  /* GENII "tolerances" */
  sprintf(tmpstr, "%.11e", dy); 
  o(1 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_Dy tol");
 
  sprintf(tmpstr, "%.11e", 2.1*dy); 
  o(2 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_2.1 Dy");
 
  sprintf(tmpstr, "%.11e", 2.8*dy); 
  o(3 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_2.8 Dy");
 
  sprintf(tmpstr, "%.11e", 3.0*dy); 
  o(4 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_3 Dy");
 
  sprintf(tmpstr, "%.11e", 4.0*dy); 
  o(5 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_4 Dy");  
     
  if (opdw)
   tmp = 1000.0*uni/wv[1];
  else
   tmp = 1.0;
  sprintf(tmpstr, "%.11e", tmp*uprime*dy/3.0); 
  o(6 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_up Dy/3");
  sprintf(tmpstr, "%.11e", tmp*3.2*uprime*dy); 
  o(7 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_3.2 up Dy"); 

 /* on-axis targets */
 /* pu(wvn, srf, cfg) axial ray slope (after refraction/reflection) */
  if (uprime < 0.0)
   sprintf(tmpstr, "%.11e+PU(1,%d,%d)", uprime, ims_1, i);
  else
   sprintf(tmpstr, "PU(1,%d,%d)+%.11e", ims_1, i, uprime);
 
  o(8 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_uprime");             /* paraxial axial ray slope in image space */
  
  sprintf(tmpstr, "O%d/0.0001", 8 + ( i - 1 ) * opr_grp);                   /* 0.0001 is experimental magic number */
  o(9 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0, "Fnb diff");    

  /* dyy(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DYY(1,1,1,%d)/O%d", i, 4 + ( i - 1) * opr_grp);
  o(10 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "Focus diff");  /* focus shift penalty */
  
    /* dy(fpt, ray, wvn, cfg) */
    sprintf(tmpstr, "DY(1,2,1,%d)/O%d", i, 1 + ( i - 1) * opr_grp);
  o(11 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "Axial DY");     /* transverse aberration */
  
  
  /* opd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "OPD(1,2,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(12 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "Axial OPD");   /* OPD on-axis */
  
  /* dmd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DMD(1,2,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(13 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "Axial DMD");   /* axial color (DMD) */
  
 /* 0.7 field targets */
  sprintf(tmpstr, "%.11e", f2_distol_z);
  o(14 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_0.7 Dstol");
  
  /* dist(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "100*DIST(2,1,1,%d)", i );
  o(15 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_0.7 Dist");
  
  sprintf(tmpstr, "O%d/O%d", 15 + ( i - 1) * opr_grp, 14 + ( i - 1) * opr_grp);
  o(16 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 Dist");        /* Distortion */
   
  /* dyy(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DYY(2,1,1,%d)/O%d", i, 2 + ( i - 1) * opr_grp);
  o(17 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 YFS");     /* tangential field curvature */
  
  /* dxx(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DXX(2,1,1,%d)/O%d", i, 2 + ( i - 1) * opr_grp);
  o(18 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 XFS");     /* sagittal field curvature */
  
  /* s2t(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "S2T(2,1,1,%d)/O%d", i, 7 + ( i - 1) * opr_grp);
  o(19 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 Coma");    /* primary aperture coma */
  
    /* dy(fpt, ray, wvn, cfg) */
    sprintf(tmpstr, "DY(2,2,1,%d)/O%d", i, 3 + ( i - 1) * opr_grp);
  o(20 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 DY U");     /* transverse aberration in upper aperture */

  /* opd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "OPD(2,2,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(21 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 OPD U");   /* OPD in upper aperture */

    /* dmd(fpt, ray, wvn, cfg) */
    sprintf(tmpstr, "DMD(2,2,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(22 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 DMD U");   /* DMD for lateral color in upper aperture */
  
  /* dy(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DY(2,3,1,%d)/O%d", i, 3 + ( i - 1) * opr_grp);
  o(23 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 DY L");     /* transverse aberration in lower aperture */
  
  /* opd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "OPD(2,3,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(24 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 OPD L");   /* OPD in lower aperture */
  
  /* dmd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DMD(2,3,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(25 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 DMD L");   /* DMD for lateral color in lower aperture */
    
  /* dx(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DX(2,4,1,%d)/O%d", i, 3 + ( i - 1) * opr_grp);
  o(26 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 Sag DX");   /* transverse aberration x-component for sagittal ray */
    
  /* dy(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DY(2,4,1,%d)/O%d", i, 1 + ( i - 1) * opr_grp);
  o(27 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "0.7 Sag DY");   /* transverse aberration y-component for sagittal ray */
    
  /* opd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "OPD(2,4,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(28 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, ".7 Sag OPD");  /* OPD for sagittal ray */
  
 /* 1.0 field targets */
  sprintf(tmpstr, "%.11e", f3_distol_z);                  
  o(29 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_1.0 Dstol");
  
  /* dist(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "100*DIST(3,1,1,%d)", i);
  o(30 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 0.0, "_1.0 Dist");
  
  sprintf(tmpstr, "O%d/O%d", 30 + ( i - 1) * opr_grp, 29 + ( i - 1) * opr_grp);
  o(31 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 Dist");        /* Distortion */
  
  /* dyy(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DYY(3,1,1,%d)/O%d", i, 4 + ( i - 1) * opr_grp);
  o(32 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 YFS");     /* tangential field curvature */
  
  /* dxx(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DXX(3,1,1,%d)/O%d", i, 1 + ( i - 1) * opr_grp);
  o(33 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 XFS");     /* sagittal field curvature */

  /* s2t(fpt, ray, wvn, cfg) */
    sprintf(tmpstr, "S2T(3,1,1,%d)/O%d", i, 7 + ( i - 1) * opr_grp);
  o(34 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 Coma");    /* primary aperture coma */
  
  /* dy(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DY(3,2,1,%d)/O%d", i, 5 + ( i - 1) * opr_grp);
  o(35 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 DY U");     /* transverse aberration in upper aperture */

  /* opd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "OPD(3,2,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(36 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 OPD U");   /* OPD in upper aperture */

    /* dmd(fpt, ray, wvn, cfg) */
    sprintf(tmpstr, "DMD(3,2,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(37 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 DMD U");   /* DMD for lateral color in upper aperture */
  
    /* dy(fpt, ray, wvn, cfg) */
    sprintf(tmpstr, "DY(3,3,1,%d)/O%d", i, 5 + ( i - 1) * opr_grp);
  o(38 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 DY L");     /* transverse aberration in lower aperture */
  
  /* opd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "OPD(3,3,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(39 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 OPD L");   /* OPD in lower aperture */
    
  /* dmd(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DMD(3,3,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(40 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 DMD L");   /* DMD for lateral color in lower aperture */
  
  /* dx(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DX(3,4,1,%d)/O%d", i, 5 + ( i - 1) * opr_grp);
  o(41 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 Sag DX");   /* transverse aberration x-component for sagittal ray */
  
  /* dy(fpt, ray, wvn, cfg) */
  sprintf(tmpstr, "DY(3,4,1,%d)/O%d", i, 1 + ( i - 1) * opr_grp);
  o(42 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1.0 Sag DY");   /* transverse aberration y-component for sagittal ray */
    
    /* opd(fpt, ray, wvn, cfg) */
    sprintf(tmpstr, "OPD(3,4,1,%d)/O%d", i, 6 + ( i - 1) * opr_grp);
  o(43 + ( i - 1 ) * opr_grp, ins, tmpstr, min, 1.0, "1 Sag OPD");   /* OPD for sagittal ray */
 
 }
 /* end of new operand set*/ 

 ssbuf_reset(-ssrow, 0);
 set_preference(output_text, on);
}

#endif

November 08

锄其本而耘其末

  工作的转换占用了最近大部分的时间和精力,以至于很久没有更新blog,这一点很是惭愧。转换工作的起因在之前的blog内容中有所提及,这里也有来自互联网的引证

  现在,我离开显示技术部门,服务于显微成像部门。新的显微镜部门尚在筹建过程中,工作不免繁重。接下来,我会尽量挤出时间按照自己的计划来更新blog。

August 20

2006年度Glassmap最佳伴侣

  新的命令GN可以实现以下功能,一,定位玻璃所在行数;二,根据当前波长选择计算折射率和色散;三,查询玻璃图中相邻玻璃的参数,而不引起玻璃图刷新。

  例如,在Schott目录中查询K11玻璃,可以在Schott玻璃数据库打开的状态下输入gn k11。在文本窗口中可以看到K11玻璃在第10行,同时也输出按照当前波长计算的n和v。另外,键入gn bk7,就可以在玻璃图没有任何刷新,焦点没有变化的情况下输出BK7的参数。

GN

double dispersion(double lambda, int disp_model, double c0, double c1, double c2, double c3, double c4, double c5)
{
    double refractive_index;
    switch(disp_model)
    {
        case 1: //if (Dispersion model == Laurent)
            if((refractive_index = (c0+(c1*pow(lambda,2))+(c2*pow(lambda,-2))+(c3*pow(lambda,-4))+(c4*pow(lambda,-6))+(c5*pow(lambda,-8))))<0) 
            refractive_index = 1.0;
            refractive_index = sqrt(refractive_index);
            break;

        case 2: //if (Dispersion model == Sellmeier) 
            lambda *= lambda;
            refractive_index = sqrt(1+(c0*lambda/(lambda-c3))+(c1*lambda/(lambda-c4))+(c2*lambda/(lambda-c5)));
            break;

        case 3: //if (Dispersion model == Conrady)
            refractive_index = c0+(c1/lambda)+(c2*pow(lambda,-3.5));
            break;

        default:
            prt("error in dispersion mode %d", mode);
            refractive_index = 1.0;
            break;
    }
    return refractive_index;
}

cmd gn(char gn[])
{
    char glassname[2000][18], tmpstr[18];
    int rows_number, found = 0, model;
    double cf0, cf1, cf2, cf3, cf4, cf5;
    double wv_short = wv[2], wv_middle = wv[1], wv_long = wv[3];
    double n, delta_n, v;

    dbgsc(glassname,0,1);
    ary2strcpy(tmpstr, glassname, 0);
    rows_number = atol(tmpstr);
    for (i = 1; i < (rows_number + 1); i++ )
    {
        ary2strcpy(tmpstr, glassname, i);
        if (!stricmp(gn, tmpstr))
        {
            found = 1;
            dbgie(&model, i, 13);
            dbgre(&cf0, i, 15);
            dbgre(&cf1, i, 16);
            dbgre(&cf2, i, 17);
            dbgre(&cf3, i, 18);
            dbgre(&cf4, i, 19);
            dbgre(&cf5, i, 20);
            n = dispersion(wv_middle, model, cf0, cf1, cf2, cf3, cf4, cf5);
            delta_n = dispersion(wv_short, model, cf0, cf1, cf2, cf3, cf4, cf5) - dispersion(wv_long, model, cf0, cf1, cf2, cf3, cf4, cf5);
            v = (n-1)/delta_n;
            prt "*Row Glass N V"; 
            aprt i " " tmpstr n v;
            break;
        }
    }
    if (!found) message("Error in glass name!");
}

August 06

弯曲镜片并保持焦距的函数

 

  有时我们需要对镜片进行弯曲,而保持其单个镜片的焦距不变。如果我们仅将镜片两侧的曲率同时修改某个数值,是达不到这样的效果的。以下用OSLO安装路径中\public\len\demo\light\tutorial\dblgauss1.len为例说明。

Demo dblgauss1 弯曲4

  如果仅仅同时增加第一片镜片两侧的曲率,例如0.005:弯曲5

  使用以下提供的bend命令增加第一面的曲率,例如0.005:弯曲6  

  同时,bend函数中也演示了如何在CCL程序中切换优化变量和优化算子。因此,尽管bend函数调用的OSLO内置的ite,但仍保留了原有的变量和优化算子。

//Revised 2006-08-07; correct for negative component
#include "../../public/ccl/inc/vbdata.h"
#include "../../public/ccl/inc/strdefs.h"
cmd getvar(double current_variables[][])
{
 int error;
 if (error = getvdat(current_variables))
 {
  if (error == -1)    prt "No variables";
  else if (error == -2 ) prt "File opening error";
 }
}
cmd cleanup_var()

 for (i = varnbr-1; i > 0; i--) v(i, del);
}
cmd retrieve_var(double variable_list[][], int original_num)
{
 int tmp_srf_num;
 int tmp_cfg_num;
 int tmp_var_typ;
 
 for (i = 1; i < original_num; i++)
 {
  tmp_srf_num = r2int(variable_list[i][0]);
  tmp_cfg_num = r2int(variable_list[i][1]);
  tmp_var_typ = r2int(variable_list[i][2]);
  switch (tmp_var_typ)
  {
   case 1: v(i, ins, tmp_srf_num, tmp_cfg_num, CV, variable_list[i][3], variable_list[i][4], variable_list[i][5], variable_list[i][6]);
       break;
   case 2: v(i, ins, tmp_srf_num, tmp_cfg_num, CC, variable_list[i][3], variable_list[i][4], variable_list[i][5], variable_list[i][6]);
       break;   
   case 3: v(i, ins, tmp_srf_num, tmp_cfg_num, TH, variable_list[i][3], variable_list[i][4], variable_list[i][5], variable_list[i][6]);
       break;
   default: message("Variable type error!"); break;
  }  
 }
}
cmd getope(int op_num[], int op_mod[], double op_wgt[], double op_tgt[], char op_nam[][], char op_def[][])
{
 int error;
 char tmpstr[50];
 for (i = 1; i < oprnbr; i++)
 {
  op_num[i] = i;
  op_mod[i]=opmode[i-1];
  if (op_mod[i]) op_tgt[i]=optgt[i-1];
   else op_wgt[i]=opwgt[i-1];
  get_operand_name(i-1);
  if (error = str2arycpy(op_nam, operand_name, i)) message(error);
  get_operand_def(i-1);
  if (error = str2arycpy(op_def, operand_definition, i)) message(error);
 } 
}
cmd cleanup_ope()
{
 for (i = oprmax; i > 0; i--) o(i, del);
}
cmd retrieve_ope(int total, int number[], int mode[], double weight[], double target[], char name[][], char definition[][])
{
 char tmp_nam[11];
 char tmp_def[50];
 for (i = 1; i < total; i++)
 {
  ary2strcpy(tmp_nam, name, i);
  ary2strcpy(tmp_def, definition, i);
  switch (mode[i])
  {
   case 0: o(i, ins, tmp_def, min, weight[i], tmp_nam); break;
   case 1: o(i, ins, tmp_def, con, target[i], tmp_nam); break;
   default: message("Operand mode error!"); break;
  }
 }
}

cmd auto()
{
 int original_varnbr = varnbr;
 int original_oprnbr = oprnbr;
 double saved[original_varnbr][8];
 
 double original_efl;
 double original_opst=opst;
 double new_opst=0.000001;
 char set_operand[50];
 
 int O_op_num[original_oprnbr];
 int O_op_mod[original_oprnbr];
 double O_op_wgt[original_oprnbr];
 double O_op_tgt[original_oprnbr];
 char O_op_nam[original_oprnbr][11];
 char O_op_def[original_oprnbr][50];
 
 int tmp_srfnum, compensation;
 double delta_cv;
 int first, second;
 
 getvar(saved);
 getope(O_op_num, O_op_mod, O_op_wgt, O_op_tgt, O_op_nam, O_op_def);
 cleanup_var();
 cleanup_ope();
 input(&tmp_srfnum, "Which surface you change?");
 input(&delta_cv, "How much curvature you change?");
 input(&compensation, "Which surface compensate?");
 
 input(&first, "Which is the first surface?");
 input(&second, "Which is the second surface?");
 if ((original_efl=pe_efl(first, second)) >= 0)
  sprintf(set_operand, "EFL(%d,%d,1)-%.6f", first, second, original_efl);
  else sprintf(set_operand, "EFL(%d,%d,1)+%.6f", first, second, fabs(original_efl));
 
 
 
 
 cv(tmp_srfnum,cv[tmp_srfnum]+delta_cv);
 v(1, ins, compensation, 0, CV, 0, 0, 1, 0);
 prt set_operand;
 prt OK1;
 o(1, ins, set_operand, min, 100.0, "EFL");
 prt OK2;
 opst(new_opst);
 prt opst, new_opst;
 ite ful 100;
 opst(original_opst);
 cleanup_var();
 cleanup_ope(); 
 retrieve_var(saved, original_varnbr);
 retrieve_ope(original_oprnbr, O_op_num, O_op_mod, O_op_wgt, O_op_tgt, O_op_nam, O_op_def);
}
August 01

烛光花影两相宜

  OSLO 6.2.x没有提供vari_sfn等等的读取接口,范例程序中展示了读取该变量底层的实作技巧。OSLO 6.3.x的CCL global data就提供了这一项,非常简洁。
   这从另一角度说明了OSLO中“The lens is the document”的概念。
 
Variables interface
July 31

依照两主面间距离计算面间距

  这是依照两主面间距离计算面间距的一个小的SCP程序,由近轴计算换成厚透镜时用得上。
*PP
//set thickness according the principal plane distance
stp outp off;
input(&i, "Input the first surface of the first group:");
input(&j, "Input the last surface of the first group:");
input(&k, "Input the first surface of the second group:");
input(&l, "Input the last surface of the second group:");
nodp(i,j,1);
e=ssb(sbrow-1,4);
nodp(k,l,1);
f=ssb(sbrow-1,3);
input(&g, "Input the distance between two PP:");
h=g+e-f;
stp outp on;
aprt "The distance between" j "and" k "should be" h;
July 22

Petzval和Dallmeyer的不同

  Petzval镜头有两种基本的结构类型,Petzval和Dallmeyer。它们的像差特性略有区别,如下图所示。左边的Petzval结构利用了OSLO内置的DLS优化和Silder,右边的Dallmeyer结构只用了手工计算。即使这样,也仍然可以清晰的看到它们之间的不同。

 Petzval_Dallmeyer

May 17

小舟从此逝

  最近一段时间的工作量的确有些过载,不仅blog没能及时更新,而且也渐生疲倦之意。不禁向往起苏轼谪居黄州的岁月,能静观天地与人生,反思生命的意义。
 
临江仙 苏轼
 
夜饮东坡醒复醉 归来仿佛三更
 
家童鼻息已雷鸣
 
敲门都不应 倚杖听江声
 
 
长恨此身非我有 何时忘却营营
 
夜阑风静縠纹平
 
小舟从此逝 江海寄余生
April 19

当然,也可以说程序风格很好

  OSLO 的 xsource 源文件中有一小段重复代码,是为了良好的风格吗?
 
一个小问题
April 17

改进版本的xsource命令

  图一是OSLO中Source->Pixelated Object菜单(Xsource)的图形输出结果。当光线取样数增大到一定程度,xsource的输出已经无法让设计者清楚的了解成像情况。 

内置的xsource命令

图一
  修改后的输出如图二 。
 
 

改进的输出结果

图二