finish blazed grating design algorithm
authorAndrew Lorimer <andrew@lorimer.id.au>
Thu, 16 Jan 2025 11:06:51 +0000 (22:06 +1100)
committerAndrew Lorimer <andrew@lorimer.id.au>
Thu, 16 Jan 2025 11:06:51 +0000 (22:06 +1100)
write_path/write_blazed.py
index 9771c7a9b60247c4ad55abf2d433d8b14af00d2c..13c665f552ef0574ee05e993f43a009106750f29 100644 (file)
@@ -12,10 +12,10 @@ import cv2
 import numpy as np
 import sys
 import matplotlib.pyplot as plt
-import write_path
-from pipython import datarectools, pitools
-import nidaqmx
-import pipython
+#import write_path
+#from pipython import datarectools, pitools
+#import nidaqmx
+#import pipython
 import time
 
 def calculate_offset_vertices(outer_vertices, offset_distance):
@@ -111,13 +111,14 @@ if __name__ == "__main__":
     #task, pidevice = write_path.setup()
 
     # Input parameters
-    grating_height = 1  # h, nm
-    grating_pitch = 5   # Lambda, nm
-    blaze_angle = 15    # theta_b, degrees
-    n_blazes = 2      # number of steps ("teeth")
-    beam_dia = 0.1     # diameter of laser beam, nm
-
-    # Calculate turning points of a single step ("tooth")
+    grating_height = 1000  # h, nm
+    grating_pitch = 5000   # Lambda, nm
+    blaze_angle = None # theta_b, degrees
+    n_blazes = 10      # number of steps ("teeth")
+    beam_dia = 500     # diameter of laser beam, nm
+    base_height = 500  # nm
+
+    # Calculate vertices of a single step ("tooth")
     if blaze_angle is None:
         d1 = grating_pitch # axial length of upwards section of sawtooth
         d2 = 0 # axial length of downwards section of sawtooth
@@ -127,22 +128,29 @@ if __name__ == "__main__":
         d2 = grating_pitch - d1 # axial length of downwards section of sawtooth
         back_angle = np.arctan(d2 / grating_height) / np.pi * 180 # angle between grating normal and downwards section of sawtooth, degrees
     
+    # Put these vertices into an array as coordinates [ [x1, y1], [x2, y2], [x3, y3] ]
     pts = [
         [0,             0               ],
         [d1,            grating_height  ],
         [grating_pitch, 0               ]
     ]
 
+    # Calculate vertices of the inner triangles to fill in the middle
+    n_passes = 1
     while True:
         try:
             pts_inner = calculate_offset_vertices(np.array(pts[-3:]), -beam_dia)
         except ValueError:
+            # Not possible to fit any smaller triangles in the middle with given beam diameter
             break
+        # Add inner triangles to the list of vertices
         for pt_inner in pts_inner:
             pts.append(pt_inner)
+        n_passes += 1
 
     lines = []
 
+    # Generate lines between each set of three consecutive vertices
     for i in range(len(pts) // 3):
         lines.append((pts[i*3+0], pts[i*3+1]))
         lines.append((pts[i*3+1], pts[i*3+2]))
@@ -152,32 +160,34 @@ if __name__ == "__main__":
     # Remove a bit of the line in the corner to prevent overwriting
     lines[2,1,0] += beam_dia
 
-    blazes_addition_x = np.repeat(np.arange(n_blazes) * grating_pitch, 3)
-    blazes_addition_y = np.zeros(n_blazes * 3)
-    blazes_addition = np.column_stack((blazes_addition_x, blazes_addition_y))
-    pts = np.tile(pts, n_blazes) + blazes_addition
-    
 
-    #points = np.tile(np.tile(single_blaze_points, (n_blazes, 1)) + blazes_addition, (n_passes, 1)) + passes_addition
-    # points = np.tile(single_blaze_points, (n_passes, 1)) + passes_addition
-    #points = np.tile(single_blaze_points, (n_blazes, 1)) + blazes_addition
-    # print(points)
-    
+    # Duplicate this set of triangles a number of times along the axis of the grating (defined by n_blazes)
+    blazes_addition_x = np.tile(np.repeat(np.arange(n_blazes) * grating_pitch, 3*n_passes), (2, 1)).T
+    blazes_addition_y = np.zeros((n_blazes * 3 * n_passes, 2))
+    blazes_addition = np.stack((blazes_addition_x, blazes_addition_y), axis=-1)
+    lines = np.tile(lines, (n_blazes, 1, 1)) + blazes_addition
 
-    # points_x = []
-    # points_y = []
-    # for k in range(n_passes):
-    #     for i in range(n_blazes):
-    #         points_x_this_blaze = single_blaze_points[0] + i*grating_pitch + k*passes_transformation[0]
-    #         points_y_this_blaze = single_blaze_points[1] + k*passes_transformation[1]
-    #         for j in range(len(single_blaze_points[0])):
-    #             points_x.append(points_x_this_blaze[j])
-    #             points_y.append(points_y_this_blaze[j])
-    # print(points_x)
-    # print(points_y)
-        
+    # Calculate a set of y values for lines to make up the solid rectangular base
+    base_y_vals = np.arange(-base_height, 0, beam_dia)
+
+    # Calculate alternating x values for a zig-zag raster scan
+    base_x_vals_single = np.array([0, grating_pitch*n_blazes])
+    base_x_vals_duplicated = np.array((base_x_vals_single, np.flip(base_x_vals_single)))
+    base_x_vals = np.tile(base_x_vals_duplicated, (int(len(base_y_vals)//2), 1))
+    # Deal with odd number of lines
+    if len(base_y_vals) % 2 != 0:
+        base_x_vals = np.vstack((base_x_vals, base_x_vals_single))
+
+    # Put x and y values into a list of pairs of points
+    base_y_vals = np.tile(base_y_vals, (2, 1)).T
+    base_lines = np.stack((base_x_vals, base_y_vals), axis=2)
+
+    # Add these lines to the overall array
+    lines = np.concatenate((lines, base_lines))
+
+    # Plot
     fig, ax = plt.subplots()
     ax.set_aspect("equal")
     for pair in lines:
         ax.plot(pair[:,0], pair[:,1], '-', color='black')  
-    plt.show()
\ No newline at end of file
+    plt.show()