summaryrefslogtreecommitdiff
path: root/src/phys.py
blob: 4e78fe25b521d4a51d4740091c06064d60dc6cda (plain)
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
import re, sys, traceback
import numpy as np
import scipy.optimize
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

from ui import *

def R(theta):
	return np.array([[np.cos(theta), np.sin(theta)],
			 [-np.sin(theta), np.cos(theta)]])


class Ellipse:
	def __init__(self, state):
		# FIXME: a less brute-force way of doing this
		if state is None:
			self.alpha = np.nan
			self.theta = np.nan
			self.e = np.nan
			self.a = np.nan
			self.b = np.nan
			return

		def x(theta):
			return np.real(np.exp(1j * theta) * state)

		def r(theta):
			return np.linalg.norm(x(theta))

		def angle(x):
			a = np.arctan2(x[1], x[0])
			if a < 0:
				a += 2 * np.pi
			if a > np.pi:
				a -= np.pi
			return a

		opt = scipy.optimize.minimize_scalar(r, bounds=[0, np.pi], \
		                                     method="bounded")
		self.b = r(opt.x)
		opt = scipy.optimize.minimize_scalar(lambda x: -r(x), \
		      bounds=[0, np.pi], method="bounded")
		self.a = r(opt.x)

		self.alpha = angle(x(opt.x))

		self.e = self.b / self.a
		self.theta = np.arctan(self.e)
		if self.alpha > angle(x(opt.x + 0.001)):
			self.theta *= -1

class Polarizer:
	def __init__(self, type, delta=0):
		self.name = "New element" # FIXME
		self.type = type
		self.angle = 0
		self.delta = delta
		self.ref = False
		self.t1 = 1
		self.t2 = 0
		self.enable = True
		self.set_type(type)

	def set_type(self, type):
		if type == "linear":
			self.M = np.array([[1, 0], [0, 0]])
		elif type == "quarterwave":
			self.M = np.exp(-1j / 4 * np.pi) * \
			         np.array([[1, 0], [0, 1j]])
		else:
			raise ValueError("bad Polarizer type: %s" % type)
		self.type = type

	def mul(self, state):
		# unpolarized light
		if state is None:
			if self.type == "linear":
				return np.dot(R(-self.angle - self.delta), \
				              np.array([[1], [0]])) * np.sqrt(self.t1)
			else:
				return None

		if type == "linear":
			A = np.sqrt(np.array([[self.t1, 0], [0, self.t2]]))
		else:
			A = np.sqrt(np.array([[self.t1, 0], [0, self.t1]]))

		M = np.matmul(R(-self.angle - self.delta), \
		    np.matmul(np.matmul(self.M, A), R(self.angle + self.delta)))
		return np.dot(M, state)

class System:
	def __init__(self):
		self.elements = list()
		self.input_intensity = 1

	def recalculate(system):
		system.states = [None] * len(system.elements)
		system.ellipses = list()

		state = None
		for i, pol in enumerate(system.elements):
			if pol.enable:
				new_state = pol.mul(state)
				if state is None and new_state is not None:
					state = new_state * np.sqrt(system.input_intensity)
				else:
					state = new_state
			system.states[i] = state
			system.ellipses.append(Ellipse(state))