之前用过Matlab软件,采用了Fox-Li数值迭代法对平行平面腔的自再现模过程进行模拟,得到稳定模式的振幅分布,对自再现模进行过相应研究。最近在学习安卓过程中,便想也通过写一个app来实现,锻炼下自己,也可进一步加深理解。
自再现模
光波在平面腔内往返传播,每次传播横向场分布即横模都将受到一定的约束,产生一定的改变。当多次传播后,场分布不再改变,此时的横模就称为自再现模。图解如下:
条形镜的自再现模
通过菲涅耳——基尔霍夫衍射公式推导出自再现模公式,得到条形镜的自再现模公式如下:
u(x')是原镜面上的场分布。通过公式求出到达另一镜面上的场分布u(x),通过不断迭代计算,当u(x)趋于稳定时,就得到了自再现模。这里我们设初始u(x)=1。其中a为腔镜半宽度,L为腔长,k是波矢量。具体迭代操作就是,将-a到a的积分区间分割,初始u(x)=1,要求新的u(x),就是对[-a,a]上每一分割点都基于公式,将积分转换为累加计算得到,对得到的u(x)回代又能得到新的u(x),设置迭代100次,基本就能得到稳定的分布。
安卓实现
复数类
由于上面公式的数据是复数类型的,而Java没有这种数据类型,所以只能自己定义复数类,实际就是在这个类中包含两个double类型数据,一个表示实部,一个表示虚部,和各种方法用于后面进行操作,根据需要,我设置的方法有,重写toString方法、加法运算、乘法运算(为操作方便分别定义了与复数间的和与实数间的乘法)、以及实部与虚部数据的get和set。
public class Complex {
private double real;
private double img;
public Complex(double real,double img){
this.real = real;
this.img = img;
}
public Complex(double real){
this.real = real;
img = 0;
}
public Complex(){
real = 0;
img = 0;
}
@Override
public String toString() {
return real+" + "+img+"i";
}
public Complex plus(Complex b){
return new Complex(this.real+b.real,this.img+b.img);
}
public Complex multiply(double b){
return new Complex(this.real*b,this.img*b);
}
public Complex multiply(Complex c) {
double a = this.real;
double b = this.img;
double d = c.getReal();
double e = c.getImg();
return new Complex(a * d - b * e, a * e + b * d);
}
public double getReal(){
return this.real;
}
public double getImg(){
return this.img;
}
public void setReal(double real){
this.real = real;
}
public void setImg(double img){
this.img = img;
}
}
exp(Complex c)和sqrt(Complex c)方法
由公式可以知道,我们需要进行exp和sqrt计算。由于Math中的exp和sqrt方法都只能对double类型进行操作,所以需要自定义这两个方法,用于对复数类进行计算。对于exp方法,可以基于欧拉公式:exp(a+bi)=exp(a)(cosb+isinb)。而sqrt方法,则可以这样得到:设(m+ni)(m+ni)=(a+bi),得到m2-n2=a,2mn=b。求解得到用a,b表示的m和n,代码如下:
public Complex exp(Complex c){
Complex result = new Complex();
double a = c.getReal();
double b = c.getImg();
double expa = Math.exp(a);
result.setImg(expa*Math.sin(b));
result.setReal(expa*Math.cos(b));
return result;
}
public Complex sqrt(Complex c){
Complex result = new Complex();
double a = c.getReal();
double b = c.getImg();
//result = m + ni;
double m = Math.sqrt((a+Math.sqrt(a*a+b*b))/2);
double n = b/(2*m);
result.setReal(m);
result.setImg(n);
return result;
}
还需要定义复数求模方法abs()和归一化方法normalize()。定义完就可以进行迭代计算了。
自定义View类
完成上面数据计算工作,为了绘制曲线,就需要自定义View,以实现绘制振幅曲线。具体就是将前面计算得到的[-a,a]间的每一分割点的振幅大小显示出来。先把x轴上每一分割点与相应的y坐标一一对应起来,注意,y轴是屏幕由上向下增大的,为方便观看,应当是振幅越大,y坐标值越小。然后调用canvas的drawLine方法连接每个点,得到曲线。
在MainActivity中,自定义一个线程,实现每完成一次迭代计算,更新一次主线程UI显示就能实现迭代过程的振幅分布曲线动态显示。效果如下:
后面还可以通过设置编辑框来改变镜宽和腔长等参量,进一步观察效果,以及绘制坐标值等。