基于Android用数值迭代法得到条形平面腔的自再现模

上学期做过激光平行平面腔的自再现模研究,基于Matlab,采用Fox-Li数值迭代法得到条形平面腔的稳定输出模式。得到振幅分布曲线如下:

但由于对Matlab图片动画显示并不熟悉,最近便想能否用安卓来实现,通过不断重新加载UI,使分布曲线随着迭代次数动态改变。本来以为应该是对公式进行简单输入就能实现,做起来才发现还是有不少麻烦的,不过还好,最终还是把效果做出来了。

先介绍自再现模的迭代公式:

u(x)就是要求的稳定模式,先把u(x)设为1,然后代入公式求出新的u(x),继续不断回代,进行数值迭代,当u(x)的整体分布不再改变时,就得到了自再现模。其中a为腔镜半宽度,L为腔长,k是波矢量。具体迭代操作就是,将-a到a的积分区间分割,初始u(x)=1,要求新的u(x),就是对[-a,a]上每一分割点都基于公式,将积分转换为累加计算得到,对得到的u(x)回代又能得到新的u(x),设置迭代100次,基本就能得到稳定的分布。

下面介绍在android上该迭代过程的具体操作。先定义要用到的各个变量。发现,这里的数据都是复数型的,而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;
    }
}
复数有了,我们就需要定义数组u以存放每次迭代的数据结果,由于数组只能用于基本类型,没办法,我们只能采用 ArrayList了,定义完还需全部置1,即:使u(x)初始为1。接着,做着做着就发现,Math里面的exp方法在这里是用不了的,因为是对复数进行操作的,那只能自己定义了。想了一下,可以基于欧拉公式: exp(a+bi)=exp(a)*(cosb+isinb)。代码如下:

 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;
    }
做着做着又发现,公式中还有对复数进行开根号的运算,同样Math里面的sqrt又不能用,还是得自己定义。又是新的麻烦,好在回想起以前是怎么对复数开根: 要求sqrt(a+bi),可先令(m+ni)*(m+ni)=a+bi,得到a=m2-n2,b=2mn,顺着求解得到m和n用a和b表达的公式就行了。代码如下:

 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,以实现绘制振幅曲线。具体就是将前面计算得到的[-a,a]间的每一分割点的振幅大小显示出来。先把x轴上每一分割点与相应的y坐标一一对应起来,注意,y轴是屏幕由上向下增大的,为方便观看,应当是振幅越大,y坐标值越小。然后调用canvas的drawLine方法连接每个点,得到曲线。

在MainActivity中,自定义一个线程,实现每完成一次迭代计算,更新一次主线程UI显示就能实现迭代过程的振幅分布曲线动态显示。效果如下:

后面还可以通过设置编辑框来改变镜宽和腔长等参量,进一步观察效果,以及绘制坐标值等。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值