|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +Generating speckle patterns with (finite) lateral memory effect. |
| 4 | +From a point source, take a look at the speckle pattern at a given distance |
| 5 | +from the scattering layer when the source moves laterally. |
| 6 | +
|
| 7 | +Also implementation for ~infinite memory effect (illuminating the scattering |
| 8 | +layer with plane waves with different tilts). In this case you can see the |
| 9 | +'warping' arround the borders (cirular behaviour) clearly |
| 10 | +
|
| 11 | +@author: Fernando |
| 12 | +""" |
| 13 | +#%% Import stuff |
| 14 | +import numpy as np |
| 15 | +import optsim as ops |
| 16 | + |
| 17 | +#%% Define physical parameters |
| 18 | +wvl = 532e-9 #wavelength |
| 19 | +aperture_size = 50e-6 #physical size of the aperture |
| 20 | +pxnum = 128 #number of pixels |
| 21 | +pxsize = aperture_size / pxnum #pixel size |
| 22 | +scat_sensor_distance = 300e-6 #distance between scattering layer and detector |
| 23 | + |
| 24 | +#%% Generate source positions |
| 25 | + |
| 26 | +xpos = np.squeeze(np.linspace(-20,20,20))*1e-6 #x positions |
| 27 | +ypos = np.array((0,)) #y position |
| 28 | +zpos = np.array((20e-6,)) #distance between source and scattering layer |
| 29 | + |
| 30 | +# define total number of positions (object space) |
| 31 | +num_pos = xpos.size*ypos.size*zpos.size |
| 32 | +# Calculate array of 3D positions for the source |
| 33 | +source_pos = np.zeros((num_pos,3)) #preallocating |
| 34 | +if num_pos == 1: |
| 35 | + source_pos[0] = (xpos,ypos,zpos) |
| 36 | +else: |
| 37 | + temp = 0 |
| 38 | + for xidx in range(xpos.size): |
| 39 | + for yidx in range(ypos.size): |
| 40 | + for zidx in range(zpos.size): |
| 41 | + source_pos[temp,:] = (xpos[xidx],ypos[yidx],zpos[zidx]) |
| 42 | + temp += 1 |
| 43 | + pass |
| 44 | + pass |
| 45 | + pass |
| 46 | + pass |
| 47 | + |
| 48 | +#%% Generate fields from point sources, propagate to the scattering layer, |
| 49 | +#and to the sensor plane |
| 50 | + |
| 51 | +#Generate sources |
| 52 | +print('generating sources...') |
| 53 | +source = [] |
| 54 | +for idx in range(num_pos): |
| 55 | + source.append(ops.build_point(xpos = source_pos[idx,0], |
| 56 | + ypos = source_pos[idx,1], |
| 57 | + pxsize = pxnum, |
| 58 | + delta = pxsize)) |
| 59 | + pass |
| 60 | +print('done') |
| 61 | +source = np.asarray(source) |
| 62 | + |
| 63 | +#propagate to scattering layer |
| 64 | +print('propagating to scattering layer...') |
| 65 | +field_before = [] |
| 66 | +for idx in range(num_pos): |
| 67 | + field_before.append(ops.rs_ang_spec_prop(Uin = source[idx,:,:], wvl = wvl, |
| 68 | + delta = pxsize, z = zpos[0], padsize = 128)) |
| 69 | + pass |
| 70 | +print('done') |
| 71 | +field_before = np.asarray(field_before) |
| 72 | + |
| 73 | +#Generate a thin scattering medium |
| 74 | +scat = ops.thin_scatter(size = field_before.shape[1]*pxsize, pxnum = field_before.shape[1], |
| 75 | + corr_width = 2*pxsize, strength = 2) |
| 76 | + |
| 77 | +# Mask it (place a circular pupil) |
| 78 | +mask, _, _ = ops.circAp(totalSize = field_before.shape[1], radius = 0.85) |
| 79 | +scat_layer = scat.thin_scat * mask |
| 80 | +#Show random phase mask (scattering medium) |
| 81 | +ops.show_field(scat_layer, mode = 'dark') |
| 82 | + |
| 83 | +#Calculate field after scattering layer |
| 84 | +field_after = field_before * scat_layer |
| 85 | + |
| 86 | +#Propagate to sensor |
| 87 | +print('propagating to sensor plane...') |
| 88 | +field_sensor = [] |
| 89 | +for idx in range(num_pos): |
| 90 | + field_sensor.append(ops.rs_ang_spec_prop(Uin = field_after[idx,:,:], |
| 91 | + wvl = wvl, delta = pxsize, |
| 92 | + z = scat_sensor_distance, padsize = 512)) |
| 93 | + pass |
| 94 | +print('done') |
| 95 | +field_sensor = np.asarray(field_sensor) |
| 96 | +field_sensor = np.moveaxis(field_sensor,0,2) |
| 97 | + |
| 98 | +#show results at thesensor plane |
| 99 | +anim1 = ops.show_vid(np.abs(field_sensor)**2,rate = 500, loop = True) |
| 100 | + |
| 101 | +#%% Illuminate a scattering layer with plane waves with different tilts, |
| 102 | +#look at the far field speckles |
| 103 | +#Generate illuminations |
| 104 | +print('generating illumination plane waves...') |
| 105 | +illus = [] |
| 106 | +for idx in range(num_pos): |
| 107 | + #define ramp orientation |
| 108 | + ramp_angle = np.deg2rad(0) |
| 109 | + #define ramp strength (how many 2pi jumps in total) |
| 110 | + ramp_strength = 0.5*idx |
| 111 | + #build ramp image |
| 112 | + x = np.linspace(-1, 1, pxnum) #axes |
| 113 | + x,y = np.meshgrid(x,-x) #axes |
| 114 | + ramp = x*np.cos(ramp_angle) + y*np.sin(ramp_angle) #ramp profile |
| 115 | + #build complex mask |
| 116 | + ramp_mask = np.exp(1j*2*np.pi*ramp*ramp_strength) |
| 117 | + illus.append(ramp_mask) |
| 118 | +print('done') |
| 119 | +illus = np.asarray(illus) |
| 120 | + |
| 121 | +#Generate a thin scattering medium |
| 122 | +scat = ops.thin_scatter(size = pxnum*pxsize, pxnum = pxnum, |
| 123 | + corr_width = 2.5*pxsize, strength = 2) |
| 124 | + |
| 125 | +# Mask it (place a circular pupil) |
| 126 | +mask, _, _ = ops.circAp(totalSize = pxnum, radius = 0.85) |
| 127 | +scat_layer = scat.thin_scat * mask |
| 128 | +#Show random phase mask (scattering medium) |
| 129 | +ops.show_field(scat_layer, mode = 'dark') |
| 130 | + |
| 131 | +#Calculate field after scattering layer |
| 132 | +field_after_plane = illus * scat_layer |
| 133 | + |
| 134 | +#Propagate to sensor |
| 135 | +print('propagating to sensor plane...') |
| 136 | +field_sensor_plane = [] |
| 137 | +for idx in range(num_pos): |
| 138 | + field_sensor_plane.append(ops.rs_ang_spec_prop(Uin = field_after_plane[idx,:,:], |
| 139 | + wvl = wvl, delta = pxsize, |
| 140 | + z = 300e-6, padsize = 256)) |
| 141 | + pass |
| 142 | +print('done') |
| 143 | +field_sensor_plane = np.asarray(field_sensor_plane) |
| 144 | +field_sensor_plane = np.moveaxis(field_sensor_plane,0,2) |
| 145 | + |
| 146 | +#show results at thesensor plane |
| 147 | +anim2 = ops.show_vid(np.abs(field_sensor_plane)**2,rate = 500, loop = True) |
0 commit comments