-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsimulation_corr.py
316 lines (266 loc) · 16.4 KB
/
simulation_corr.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import math
import numpy as np
# Our axis is:
# [0, 0, 0] = origin = center of mirror_G
# [1, 0, 0] = x-direction = mirror_G to mirror_M2
# [0, 1, 0] = y-direction = mirror_G to mirror_M1
# [0, 0, 1] = z-direction, obeying verter product rule
spec_wavelengths = np.arange(380, 781, 5)
class MichelsonSimulation:
# We have a list of point-source, each with its position and wavelength information.
# We give central mirror(G), position-changing mirror(M1), direction-changing mirror(M2)
# information respectively, including its central point and direction.
# All of the above information should be 'np.array' type.
# We give a term to control interference type, and the initialize of screen is related to it.
def __init__(self):
self.source_list = []
self.mirror_G = []
self.mirror_M1 = []
self.mirror_M2 = []
self.islocalInterference = False
self.screen = []
# insert a list of source information, including its spatialCorrelation, position, wavelength and intensity
# if local correlation is necessary, change islocalCorrelate=True
def insertSource(self, source_position, wavelength, islocalCorrelate=False, source_intensity=1):
position = np.array(source_position)
self.source_list.append([islocalCorrelate, position, wavelength, source_intensity])
# include a light source of compound light
# if local correlation is necessary, change islocalCorrelate=True
def insertSpecSource(self, source_position, spec, islocalCorrelate=False):
position = np.array(source_position)
for wavelength, source_intensity in zip(spec_wavelengths, spec):
self.source_list.append([islocalCorrelate, position, wavelength, source_intensity])
# clear all the point sources
def clearSource(self):
self.source_list.clear()
def getSourceList(self):
return self.source_list
# initialize information of central mirror —— G, input '[...], [...]'
def initialMirrorG(self, mirror_G_position, mirror_G_direction):
position = np.array(mirror_G_position)
direction = np.array(mirror_G_direction)
self.mirror_G.append(position)
self.mirror_G.append(direction)
# initialize information of mirror M1 (the type is [np.array, np.array])
def initialMirrorM1(self, mirror_M1_position, mirror_M1_direction):
position = np.array(mirror_M1_position)
direction = np.array(mirror_M1_direction)
self.mirror_M1.append(position)
self.mirror_M1.append(direction)
# initialize information of mirror M2 (the type is [np.array, np.array])
def initialMirrorM2(self, mirror_M2_position, mirror_M2_direction):
position = np.array(mirror_M2_position)
direction = np.array(mirror_M2_direction)
self.mirror_M2.append(position)
self.mirror_M2.append(direction)
# set M1 mirror(i.e. set its central point)
def setMirrorM1(self, loc):
locVector = np.array(loc)
self.mirror_M1[0] = locVector
# set M2 mirror(i.e. set its direction)
def setMirrorM2(self, direction):
directionVector = np.array(direction)
self.mirror_M2[1] = directionVector
# move M1 mirror(i.e. move its central point)
def moveMirrorM1(self, movement):
movementVector = np.array(movement)
self.mirror_M1[0] += movementVector
# move M2 mirror(i.e. change its direction)
def moveMirrorM2(self, directionChange): #TODO: experimentally we measure angle, not direction vector, need a converter
directionVector = np.array(directionChange)
self.mirror_M2[1] += directionVector
def getMirror(self):
G, M1, M2 = self.mirror_G, self.mirror_M1, self.mirror_M2
return 'G', G, 'M1', M1, 'M2', M2
# change to non-local interference mode, together with finite-distance-screen
# we set distance from mirror_G to screen is 30cm
def changeToNonlocal(self):
self.islocalInterference = False
screen = [] # here initialize screen, 100*100 points, 5cm*5cm
center = np.array([0, -30, 0])
for i in range(-50, 50):
for j in range(-50, 50):
point = center + np.array([5 * i / 100, 0, 5 * j /100])
screen.append(point)
self.screen = screen
# change to local interference mode, together with infinite-distance-screen
# we only consider the relative position between screen and lens(i.e. our eyes)
# thus we set lens as [0, 0, 0], the relative distance is 2cm
def changeToLocal(self):
self.islocalInterference = True
screen = [] # here initialize screen, 100*100 points, 2cm*2cm
center = np.array([0, -2, 0])
for i in range(-50, 50):
for j in range(-50, 50):
point = center + np.array([2 * i / 100, 0, 2 * j /100])
screen.append(point)
self.screen = screen
def getInterferenceMode(self):
mode = self.islocalInterference
if mode:
return 'local interference'
else:
return 'non-local interference'
def getScreen(self):
return self.screen
# This is the mirror symmetry operation acting on a point source.
# mirror = [np.array(central position), np.array(direction)]
# source = [np.array(position), wavelength], here we just use the former
def mirrorOperation(self, source_position, mirror):
const = np.inner(mirror[1], -1 * mirror[0]) # change a(x-x0)+b(y-y0)+c(z-z0) to ax+by+cz+d
coe = -2 * (np.inner(mirror[1], source_position) + const) \
/ np.inner(mirror[1], mirror[1]) # compute the coeffient for image_coordinate calculation
image_coordinate = source_position + coe * mirror[1]
return image_coordinate
# This is the projection from a vector to a given axis, both input and output are np.array
def projection(self, vector, axis):
coe = np.inner(vector, axis) / np.inner(axis, axis)
projectVector = coe * axis
return projectVector
# Output an image source list, corresponding to source S,
# the term is like '[np.array(position of S1), np.array(position of S2), wavelength]'
# Detailly speaking, S-mirrorG-mirrorM1-S1, S-mirrorM2-mirrorG-S2
def getImageSourceList(self):
source_list = self.source_list
image_list = []
for source in source_list:
islocalCorrelate, position_S, wavelength, source_intensity = source
# for non-correlate source (ordinary source)
if not islocalCorrelate:
# get position of S1
position_S1 = self.mirrorOperation(self.mirrorOperation(position_S, self.mirror_G), self.mirror_M1)
# get position of S2
position_S2 = self.mirrorOperation(self.mirrorOperation(position_S, self.mirror_M2), self.mirror_G)
# generate coherent light source unit
image_list.append([islocalCorrelate, position_S1, position_S2, wavelength, source_intensity])
# for correlate source (i.e. with 4 correlated subsource around)
else:
# get position of 4 subsource
position_left = position_S - np.array([0, 0.5, 0])
position_right = position_S + np.array([0, 0.5, 0])
position_up = position_S + np.array([0, 0, 0.5])
position_down = position_S - np.array([0, 0, 0.5])
subsourcePositionList = [position_left, position_right, position_up, position_down]
# get image source information
imageSource = [islocalCorrelate, wavelength]
# central source
position_S1 = self.mirrorOperation(self.mirrorOperation(position_S, self.mirror_G), self.mirror_M1)
position_S2 = self.mirrorOperation(self.mirrorOperation(position_S, self.mirror_M2), self.mirror_G)
imageSource.append([position_S1, source_intensity])
imageSource.append([position_S2, source_intensity])
# subsource
for subsourcePosition in subsourcePositionList:
sub1 = self.mirrorOperation(self.mirrorOperation(subsourcePosition, self.mirror_G), self.mirror_M1)
sub2 = self.mirrorOperation(self.mirrorOperation(subsourcePosition, self.mirror_M2), self.mirror_G)
imageSource.append([sub1, 0.1 * source_intensity])
imageSource.append([sub2, 0.1 * source_intensity])
# generate coherent light source unit, first gives islocalCorrelate & wavelength,
# then gives all related image source by '[position, intensity]'.
image_list.append(imageSource)
return image_list
# get interval between two vector, supporting both type(list) and type(np.ndarray)
def getInterval(self, vec1, vec2):
if type(vec1) is not np.ndarray:
vec1 = np.array(vec1)
if type(vec2) is not np.ndarray:
vec2 = np.array(vec2)
return np.linalg.norm(vec1 - vec2)
# This is the interference pattern calculation for non-local interference.
# The output is a list, and the term is like '[position on screen, wavelength, intensity]'
# Since no interference between different source, we give an output for
# each source-screenPoint combination, we can get final pattern by simply adding their intensity.
def nonlocalInterference(self):
enhance_factor = 1e3
if not self.islocalInterference:
image_list = self.getImageSourceList() # get imformation of image-source-pair
screen = self.screen # get point list of screen
pattern = []
positionList = image_list.copy()
for point in screen:
for coherentSource in positionList: # calculate for each source-screenPoint combination
islocalCorrelate = coherentSource[0]
# for non-correlate source (ordinary source)
if not islocalCorrelate:
islocalCorrelate, point1, point2, wavelength, source_intensity = coherentSource
# calculate interval between source and screen straightly, using them to derive phase difference
interval1 = self.getInterval(point1, point)
interval2 = self.getInterval(point2, point)
delta = (10 ** 7) * 2 * math.pi * (interval1 - interval2) \
/ wavelength # derive phase differnce, wavelength is in nm=10^{-7}cm
intensity1 = 1/(interval1 ** 2)
intensity2 = 1/(interval2 ** 2)
intensity = intensity1 + intensity2 + \
2 * math.sqrt(intensity1 * intensity2) * math.cos(delta)
# forming one term, not interfere with others
pattern.append([point, wavelength, intensity*source_intensity*enhance_factor])
# for correlate source (i.e. with 4 correlated subsource around)
else:
wavelength = coherentSource[1]
# calculate sum of amplitude, use 2-element array
correlatelist = coherentSource[2:]
point1, source_intensity1 = correlatelist[0]
interval1 = self.getInterval(point1, point)
amplitude = np.array([0.0, 0.0])
for imagesource in correlatelist:
point2, source_intensity2 = imagesource
source_amplitude = math.sqrt(source_intensity2)
interval2 = self.getInterval(point2, point)
delta = (10 ** 7) * 2 * math.pi * (interval1 - interval2) \
/ wavelength # derive phase differnce, wavelength is in nm=10^{-7}cm
amplitude += np.array([source_amplitude * math.cos(delta), source_amplitude * math.sin(delta)])
# calculate intensity
intensity = np.linalg.norm(amplitude) ** 2
# forming one term, not interfere with others
pattern.append([point, wavelength, intensity*source_intensity1*enhance_factor])
return pattern
else:
raise Exception('Mode is local interference now, please change mode')
# This is the interference pattern calculation for local interference.
# The output is a list, and the term is like '[position on screen, wavelength, intensity]'
def localInterference(self):
if self.islocalInterference:
image_list = self.getImageSourceList() # get imformation of image-source-pair
screen = self.screen # get point list of screen
pattern = []
positionList = image_list.copy()
for point in screen:
for coherentSource in positionList: # calculate for each source-screenPoint combination
islocalCorrelate = coherentSource[0]
# for non-correlate source (ordinary source)
if not islocalCorrelate:
islocalCorrelate, point1, point2, wavelength, source_intensity = coherentSource
intervalVector = point1 - point2 # derive vector from one coherent image source to the other
# since specified screenPoint gives a pair of parallel light,
# we follow screenPoint-lightDirection-phaseDifference calculation,
# type(point) == np.ndarray, and the term denotes relative distance.
direction = np.array(point)
delta = (10 ** 7) * 2 * math.pi * np.inner(intervalVector, direction) / np.linalg.norm(direction) \
/ wavelength # derive phase differnce, wavelength is in nm=10^{-7}cm
intensity = 2 + 2 * math.cos(delta)
# forming one term, not interfere with others
pattern.append([point, wavelength, intensity*source_intensity])
# for correlate source (i.e. with 4 correlated subsource around)
else:
wavelength = coherentSource[1]
# calculate sum of amplitude, use 2-element array
correlatelist = coherentSource[2:]
point1, source_intensity1 = correlatelist[0]
amplitude = np.array([0.0, 0.0])
for correlate in correlatelist:
point2, source_intensity2 = correlate
source_amplitude = math.sqrt(source_intensity2)
intervalVector = point1 - point2 # derive vector from one coherent image source to the other
# since specified screenPoint gives a pair of parallel light,
# we follow screenPoint-lightDirection-phaseDifference calculation,
# type(point) == np.ndarray, and the term denotes relative distance.
direction = np.array(point)
delta = (10 ** 7) * 2 * math.pi * np.inner(intervalVector, direction) / np.linalg.norm(direction) \
/ wavelength # derive phase differnce, wavelength is in nm=10^{-7}cm
amplitude += np.array([source_amplitude * math.cos(delta), source_amplitude * math.sin(delta)])
# calculate intensity
intensity = np.linalg.norm(amplitude) ** 2
# forming one term, not interfere with others
pattern.append([point, wavelength, intensity*source_intensity1])
return pattern
else:
raise Exception('Mode is nonlocal interference now, please change mode')