Ethan-Tseng / Neural_Nano-Optics

Repository for "Neural Nano-Optics for High-quality Thin Lens Imaging"
Boost Software License 1.0
72 stars 30 forks source link

Some questions about make_propagator in solver.py #4

Open longzw001116 opened 1 year ago

longzw001116 commented 1 year ago

I'm new to the field of Fourier Optics. I couldn't understand this function since I can't match it to any kind of diffraction. Can anyone have some formulas here to explain it ?

def make_propagator(params):

  batchSize = params['batchSize']
  pixelsX = params['pixelsX']
  pixelsY = params['pixelsY']
  upsample = params['upsample']

  # Propagator definition.
  k = 2 * np.pi / params['lam0'][:, 0, 0]
  k = k[:, np.newaxis, np.newaxis]
  samp = params['upsample'] * pixelsX
  k = tf.tile(k, multiples = (1, 2 * samp - 1, 2 * samp - 1))
  k = tf.cast(k, dtype = tf.complex64)  
  k_xlist_pos = 2 * np.pi * np.linspace(0, 1 / (2 *  params['Lx'] / params['upsample']), samp)  
  front = k_xlist_pos[-(samp - 1):]
  front = -front[::-1]
  k_xlist = np.hstack((front, k_xlist_pos))
  k_x = np.kron(k_xlist, np.ones((2 * samp - 1, 1)))
  k_x = k_x[np.newaxis, :, :]
  k_y = np.transpose(k_x, axes = [0, 2, 1])
  k_x = tf.convert_to_tensor(k_x, dtype = tf.complex64)
  k_x = tf.tile(k_x, multiples = (batchSize, 1, 1))
  k_y = tf.convert_to_tensor(k_y, dtype = tf.complex64)
  k_y = tf.tile(k_y, multiples = (batchSize, 1, 1))
  k_z_arg = tf.square(k) - (tf.square(k_x) + tf.square(k_y))
  k_z = tf.sqrt(k_z_arg)

  # Find shift amount
  theta = params['theta'][:, 0, 0]
  theta = theta[:, np.newaxis, np.newaxis]
  y0 = np.tan(theta) * params['f']
  y0 = tf.tile(y0, multiples = (1, 2 * samp - 1, 2 * samp - 1))
  y0 = tf.cast(y0, dtype = tf.complex64)

  phi = params['phi'][:, 0, 0]
  phi = phi[:, np.newaxis, np.newaxis]
  x0 = np.tan(phi) * params['f']
  x0 = tf.tile(x0, multiples = (1, 2 * samp - 1, 2 * samp - 1))
  x0 = tf.cast(x0, dtype = tf.complex64)

  propagator_arg = 1j * (k_z * params['f'] + k_x * x0 + k_y * y0)
  propagator = tf.exp(propagator_arg)

  return propagator
Ethan-Tseng commented 1 year ago

Welcome to Fourier Optics! This function implements the Angular Spectrum Method (ASM). It is one of many different wave propagation simulation methods. This function specifically generates the ASM transfer function which is used later in the code to simulate the optical response of the metasurface.

For more information on different types of propagation functions please refer to our other works. Specifically, refer to Section 3 of Learned Hardware-in-the-loop Phase Retrieval for Holographic Near-Eye Displays and our SIGGRAPH course notes.

Let us know if you have any further questions!

longzw001116 commented 1 year ago

Thank you for answering my question.

I have new questions as follows:

In this make_propagator function: propagator_arg = 1j * (k_z * params['f'] + k_x * x0 + k_y * y0) while x0 = np.tan(phi) * params['f'] and y0 = np.tan(theta) * params['f'].

  1. k_z * params['f'] represents the ASM, so what does k_x * x0 + k_y * y0 mean? Does it account for the shift of image in the focal plane due to the oblique incident light?
  2. Since θ and φ are field angles alone x- and y-axis, I think there is a mistake in x0 and y0.
    In other words: x0 = np.tan(theta) * params['f'] and y0 = np.tan(phi) * params['f']
longzw001116 commented 1 year ago

Welcome to Fourier Optics! This function implements the Angular Spectrum Method (ASM). It is one of many different wave propagation simulation methods. This function specifically generates the ASM transfer function which is used later in the code to simulate the optical response of the metasurface.

For more information on different types of propagation functions please refer to our other works. Specifically, refer to Section 3 of Learned Hardware-in-the-loop Phase Retrieval for Holographic Near-Eye Displays and our SIGGRAPH course notes.

Let us know if you have any further questions!

Ethan-Tseng commented 1 year ago

Thank you for answering my question.

I have new questions as follows:

In this make_propagator function: propagator_arg = 1j * (k_z * params['f'] + k_x * x0 + k_y * y0) while x0 = np.tan(phi) * params['f'] and y0 = np.tan(theta) * params['f'].

  1. k_z * params['f'] represents the ASM, so what does k_x * x0 + k_y * y0 mean? Does it account for the shift of image in the focal plane due to the oblique incident light?
  2. Since θ and φ are field angles alone x- and y-axis, I think there is a mistake in x0 and y0. In other words: x0 = np.tan(theta) * params['f'] and y0 = np.tan(phi) * params['f']
  1. You are correct. The extra terms describe lateral shifts on the sensor plane as a result of the tilted wavefront.
  2. Thanks for debugging our code! We assumed rotational symmetry of the metalens and so we ended up only using theta and hence this mistake did not affect the final results.