通过改变参数,可以观察到不同的现象。
先从介绍干涉实验原理开始,首先如下图所示:
点光源s1和s2在同一直线上,设为x轴,观察屏在距离它们为D的位置上,观察屏平行于y-z平面,在观察屏上各点光强不同,即存在干涉现象。s1和s2发射球面波,所以在空间任意一点上的光强与距离的平方成反比,而干涉理论公式为:I = I1+I2+sqrt(I1*I2)*cos(phi)。
下面是app的具体实现,下面给出定义的各变量的含义:
private double length=5;//观察范围半宽度5mm private double width=0.2;//两点间距0.2mm private double D = 30;//点光源所在平面到观察屏距离30mm private double wavelength = 600;//波长600nm private double k;//波矢量 private double dlength;//观察屏刻度 // private double dwidth; int ny = 151;//观察屏范围分割数 private double I[][];//记录观察屏上的点的强度 private EditText rectLength;//设置观察范围 private EditText pointWidth;//设置点间距 private EditText editTextWavelength;//设置波长 private Button buttonSet;然后自定义View类用于绘制干涉现象,通过选定屏幕一个区域,将区域分割成一个个的点,作为采样点,在采样点上画小圆点,根据采样点的光强大小,设置颜色深浅以表示光强大小: @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLACK); if (I==null){ I = new double[151][151]; } drawPoint(canvas,I); } private void drawPoint(Canvas canvas,double I[][]){ for (int i = 0; i < I.length; i++) { for (int j = 0; j < I.length; j++) { paint = new Paint(); paint.setARGB(255,0,0, (int) I[i][j]);//改变颜色大小,仅改变蓝色 canvas.drawCircle(startX+i*deltaX,startY+j*deltaY,8,paint); } } }还需要定义一个方法,使得在MainActivity中获得光强值后能更新数值: public void setI(double I[][]){ if (I!=null){ this.I = I; } }这样,我们就可以在MainActivity中根据参数设置进行计算并显示了。由于数值计算过程可能会比较久,因此,自定义一个新线程进行光强值计算: class DataThread extends Thread{//自定义线程,用于计算观察范围内各点强度 public Handler handler; @Override public void run() { Looper.prepare(); handler = new Handler(){ @Override public void handleMessage(Message msg) { if (msg.what==0x123){ k = 2*Math.PI/wavelength*1000000;//k的单位是mm-1 I = new double[ny][ny]; dlength = 2*length/ny;//将观察范围分割 double Imax = 0;//强度最大值 double Imin = 255;//强度最小值 double l1,l2,phi; for (int i = 0; i <ny ; i++) { for (int j = 0; j <ny ; j++) { //l1是右边的点光源到观察屏上各采样点的距离 l1 = Math.sqrt((-length+dlength*j)*(-length+dlength*j)+ (-length+dlength*i)*(-length+dlength*i)+(D-width/2)*(D-width/2)); //l2是左边的点光源到观察屏上各采样点的距离 l2 = Math.sqrt((-length+dlength*j)*(-length+dlength*j)+ (-length+dlength*i)*(-length+dlength*i)+(D+width/2)*(D+width/2)); phi = k*(l2-l1);//相位差 I[i][j] = (1/l1)*(1/l1)+(1/l2)*(1/l2)+2*(1/l1)*(1/l2)*Math.cos(phi);/* 设点光源振幅为1,球面波到空间某点出的光强与距离的平方成反比 即左边点光源光强:I1 = 1/l2^2,右边点光源光强:I2 = 1/l1^2 干涉公式:I = I1+I2+sqrt(I1*I2)*cos(phi) */ if(I[i][j]>Imax) Imax = I[i][j];//取得最大值 if (I[i][j]<Imin) Imin = I[i][j];//取得最小值 } } for (int i=0;i<ny;i++){ for (int j = 0; j < ny; j++) { I[i][j] = (I[i][j]-Imin)/(Imax-Imin)*255;//将强度大小等比放大到0~255范围,好设置颜色深浅 } } imaging.setI(I); imaging.postInvalidate(); } } }; Looper.loop(); } }当我们点击设定按钮时,更新参数值,并且发送消息: buttonSet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String s1 = rectLength.getText().toString(); String s2 = pointWidth.getText().toString(); String s3 = editTextWavelength.getText().toString(); //输入不为空就更新相应的数值 if (s1!=null&&!s1.equals("")){ length = Double.parseDouble(s1); } if (s2!=null&&!s2.equals("")){ width = Double.parseDouble(s2); } if (s3!=null&&!s3.equals("")){ wavelength = Double.parseDouble(s3); } Message msg = new Message(); msg.what = 0x123; dataThread.handler.sendMessage(msg); } });改变参数,效果如下:
附上完整代码:
public class MainActivity extends AppCompatActivity { private double length=5;//观察范围半宽度5mm private double width=0.2;//两点间距0.2mm private double D = 30;//点光源所在平面到观察屏距离30mm private double wavelength = 600;//波长600nm private double k;//波矢量 private double dlength;//观察屏刻度 // private double dwidth; int ny = 151;//观察屏范围分割数 private double I[][];//记录观察屏上的点的强度 private EditText rectLength;//设置观察范围 private EditText pointWidth;//设置点间距 private EditText editTextWavelength;//设置波长 private Button buttonSet; private Imaging imaging; DataThread dataThread; class DataThread extends Thread{//自定义线程,用于计算观察范围内各点强度 public Handler handler; @Override public void run() { Looper.prepare(); handler = new Handler(){ @Override public void handleMessage(Message msg) { if (msg.what==0x123){ k = 2*Math.PI/wavelength*1000000;//k的单位是mm-1 I = new double[ny][ny]; dlength = 2*length/ny;//将观察范围分割 double Imax = 0;//强度最大值 double Imin = 255;//强度最小值 double l1,l2,phi; for (int i = 0; i <ny ; i++) { for (int j = 0; j <ny ; j++) { //l1是右边的点光源到观察屏上各采样点的距离 l1 = Math.sqrt((-length+dlength*j)*(-length+dlength*j)+ (-length+dlength*i)*(-length+dlength*i)+(D-width/2)*(D-width/2)); //l2是左边的点光源到观察屏上各采样点的距离 l2 = Math.sqrt((-length+dlength*j)*(-length+dlength*j)+ (-length+dlength*i)*(-length+dlength*i)+(D+width/2)*(D+width/2)); phi = k*(l2-l1);//相位差 I[i][j] = (1/l1)*(1/l1)+(1/l2)*(1/l2)+2*(1/l1)*(1/l2)*Math.cos(phi);/* 设点光源振幅为1,球面波到空间某点出的光强与距离的平方成反比 即左边点光源光强:I1 = 1/l2^2,右边点光源光强:I2 = 1/l1^2 干涉公式:I = I1+I2+sqrt(I1*I2)*cos(phi) */ if(I[i][j]>Imax) Imax = I[i][j];//取得最大值 if (I[i][j]<Imin) Imin = I[i][j];//取得最小值 } } for (int i=0;i<ny;i++){ for (int j = 0; j < ny; j++) { I[i][j] = (I[i][j]-Imin)/(Imax-Imin)*255;//将强度大小等比放大到0~255范围,好设置颜色深浅 } } imaging.setI(I); imaging.postInvalidate(); } } }; Looper.loop(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rectLength = (EditText) findViewById(R.id.rect_len); pointWidth = (EditText) findViewById(R.id.rect_wid); editTextWavelength = (EditText) findViewById(R.id.wavelength); buttonSet = (Button) findViewById(R.id.bt_set); imaging = (Imaging) findViewById(R.id.show_image); dataThread = new DataThread(); dataThread.start();//线程开启 buttonSet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String s1 = rectLength.getText().toString(); String s2 = pointWidth.getText().toString(); String s3 = editTextWavelength.getText().toString(); //输入不为空就更新相应的数值 if (s1!=null&&!s1.equals("")){ length = Double.parseDouble(s1); } if (s2!=null&&!s2.equals("")){ width = Double.parseDouble(s2); } if (s3!=null&&!s3.equals("")){ wavelength = Double.parseDouble(s3); } Message msg = new Message(); msg.what = 0x123; dataThread.handler.sendMessage(msg); } }); } }Imaging.java:
public class Imaging extends View{ private float startX;//X轴起点 private float startY;//Y轴起点 private float deltaX;//采样点间距 private float deltaY; private Paint paint; private double I[][]; private int ny=151; public Imaging(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); startX = (w-h)/2;//设置X轴起点 startY = 0;//设置Y轴起点 deltaX = deltaY = h/150; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLACK); if (I==null){ I = new double[151][151]; } drawPoint(canvas,I); } private void drawPoint(Canvas canvas,double I[][]){ for (int i = 0; i < I.length; i++) { for (int j = 0; j < I.length; j++) { paint = new Paint(); paint.setARGB(255,0,0, (int) I[i][j]);//改变颜色大小,仅改变蓝色 canvas.drawCircle(startX+i*deltaX,startY+j*deltaY,8,paint); } } } public void setI(double I[][]){ if (I!=null){ this.I = I; } } }
