diff options
-rw-r--r-- | src/phys.py | 24 | ||||
-rw-r--r-- | src/ui.py | 38 | ||||
-rw-r--r-- | src/ui_table.py | 56 |
3 files changed, 81 insertions, 37 deletions
diff --git a/src/phys.py b/src/phys.py index 4e78fe2..c47a497 100644 --- a/src/phys.py +++ b/src/phys.py @@ -7,6 +7,16 @@ from PyQt5.QtCore import * from ui import * + + +def jones_to_stokes(E): + I = np.abs(E[0] ** 2) + np.abs(E[1] ** 2) + Q = np.abs(E[0] ** 2) - np.abs(E[1] ** 2) + U = 2 * np.real(E[0] * np.conjugate(E[1])) + V = 2 * np.imag(E[0] * np.conjugate(E[1])) + return np.array([I, Q, U, V]) + + def R(theta): return np.array([[np.cos(theta), np.sin(theta)], [-np.sin(theta), np.cos(theta)]]) @@ -14,7 +24,6 @@ def R(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 @@ -44,12 +53,14 @@ class Ellipse: bounds=[0, np.pi], method="bounded") self.a = r(opt.x) - self.alpha = angle(x(opt.x)) + V = jones_to_stokes(state) + + self.alpha = np.arctan2(V[2], V[1]) / 2 + if self.alpha < 0: + self.alpha += np.pi - self.e = self.b / self.a - self.theta = np.arctan(self.e) - if self.alpha > angle(x(opt.x + 0.001)): - self.theta *= -1 + R = np.sqrt(V[1] ** 2 + V[2] ** 2 + V[3] ** 2) + self.theta = np.arcsin(V[3] / R) / 2 class Polarizer: def __init__(self, type, delta=0): @@ -98,6 +109,7 @@ class System: def recalculate(system): system.states = [None] * len(system.elements) + system.Vs = [None] * len(system.elements) system.ellipses = list() state = None @@ -32,38 +32,42 @@ def update(): for i, pol in enumerate(system.elements): row = GUI.table.rows[i] - # update all the diagrams row.ellipse.state = system.states[i] row.ellipse.ellipse = system.ellipses[i] row.ellipse.is_used = system.elements[i].enable row.ellipse.repaint() - - text = "%s at %f°" \ - % (pol.type, (pol.angle + pol.delta) * 180 / np.pi) - row.info_angle.setText(text) state = system.states[i] + V = system.Vs[i] ellipse = system.ellipses[i] if state is None: - I = 1 - row.info_jones.setText("Unpolarized") + I = system.input_intensity + + for label in row.jones: + label.setText("-") + row.stokes[0].setText("%g" % I) + for label in row.stokes[1:]: + label.setText("0") else: I = np.abs(state[0] * state[0].conjugate() \ + state[1] * state[1].conjugate()) if state is None: continue - - A, B = state - text = "I = %f\n" % I - text += "%f ∠ %+f°\n%f ∠ %+f°\n" % \ - (np.abs(A), 180 / np.pi * np.angle(A), \ - np.abs(B), 180 / np.pi * np.angle(B)) - text += "α = %f°\nφ = %+f°" % \ - (180 / np.pi * ellipse.alpha, 180 / np.pi * ellipse.theta) - text = text.replace("-", "- ").replace("+", "+ ") - row.info_jones.setText(text) + + polar = [(np.abs(z), np.angle(z) * 180 / np.pi) for z in state] + for i, (a, b) in enumerate(polar): + row.jones[2 * i].setText("%g" % a) + row.jones[2 * i + 1].setText("%g°" % b) + + delta = polar[1][1] - polar[0][1] + row.jones[4].setText("%g°" % delta) + + for i, x in enumerate(phys.jones_to_stokes(state)): + row.stokes[i].setText("%g" % x) + row.stokes[4].setText("%g°" % (ellipse.alpha * 180 / np.pi)) + row.stokes[5].setText("%g°" % (ellipse.theta * 180 / np.pi)) GUI.widok.intensity = I GUI.widok.repaint() diff --git a/src/ui_table.py b/src/ui_table.py index 8286f5e..52a4171 100644 --- a/src/ui_table.py +++ b/src/ui_table.py @@ -147,7 +147,7 @@ class OptBox(QVBoxLayout): def change_enable(self): self.row.pol.enable = self.enable.isChecked() - update() + GUI.do_update() @@ -161,22 +161,49 @@ class SystemTableRow: self.delta = pol.delta self.ref = pol.ref + # Option box (column 1) self.optbox = OptBox(self, pol) parent.setCellWidget(row_number, 0, LayoutWrapper(self.optbox)) + # Ellipse diagram (column 2) self.ellipse = EllipseWidget(pol) parent.setCellWidget(row_number, 1, self.ellipse) - self.info = QVBoxLayout() - self.info_angle = MeinLabel() - self.info_angle.setAlignment(Qt.AlignLeft) - self.info.addWidget(self.info_angle) - self.info.addWidget(QLabel("Polarization state")) - self.info_jones = MeinLabel() - self.info_jones.setAlignment(Qt.AlignLeft) - self.info.addWidget(self.info_jones) - self.info.addItem(ExpandingSpacer()) - parent.setCellWidget(row_number, 2, LayoutWrapper(self.info)) + # Jones vector (column 3) + box = QVBoxLayout() + parent.setCellWidget(row_number, 2, LayoutWrapper(box)) + + grid = QGridLayout() + grid.setColumnStretch(2, 10) + box.addLayout(grid) + box.addItem(ExpandingSpacer()) + + for i, label in enumerate(["|Ex|", "arg Ex", "|Ey|", "arg Ey", "δ"]): + grid.addWidget(QLabel(label), 1 + i, 1) + + self.jones = list() + for i in range(5): + label = MeinLabel("-") + grid.addWidget(label, 1 + i, 2) + self.jones.append(label) + + # Stokes parameters (column 4) + box = QVBoxLayout() + parent.setCellWidget(row_number, 3, LayoutWrapper(box)) + + grid = QGridLayout() + grid.setColumnStretch(2, 10) + box.addLayout(grid) + box.addItem(ExpandingSpacer()) + + for i, label in enumerate(["I", "Q", "U", "V", "α", "θ"]): + grid.addWidget(QLabel(label), 1 + i, 1) + + self.stokes = list() + for i in range(6): + label = MeinLabel("-") + grid.addWidget(label, 1 + i, 2) + self.stokes.append(label) def angle_change(self): self.angle = self.optbox.angle.angle / 180 * np.pi @@ -190,14 +217,15 @@ class SystemTable(QTableWidget): super().__init__() self.rows = list() - self.setColumnCount(3) # this won't change + self.setColumnCount(4) # this won't change self.hh = self.horizontalHeader() self.hh.setSectionResizeMode(0, QHeaderView.ResizeToContents) - self.hh.resizeSection(1, 170) + self.hh.resizeSection(1, 150) + self.hh.resizeSection(2, 150) self.hh.setStretchLastSection(True) self.setHorizontalHeaderLabels([ - "Settings", "Ellipse", "State" + "Settings", "Diagram", "State", "Stokes" ]) self.vh = self.verticalHeader() |