Kernel-phase data analysis tutorial

Table of Contents

1 Introduction

So you want to extract kernel-phase out of your hard earned data? You've heard that kernel-phase can do amazing things: that it outperforms coronagraphs in certain cases, that it leads to high-contrast detections in the super-resolution regime or that it can put an end to global warming? Well, some of these claims are somewhat exagerrated, but I certainly appreciate your enthusiasm.

Let's just say for now that Kernel-phase provides an interesting and useful way to look at your data from a new perspective… that it can lead you to discover new things hidden in your data and that as we keep tinkering with it, it may still lead to powerful new developments.

2 Kernel requirements

In order to be kernel-compatible, your image has to meet certain requirements:

  • it has to be Nyquist-sampled: that is, you need at least two pixels per unit of lambda/D in your image. Some under-sampling can be tolerated but will necessarily translate into a poorer performance.
  • it has to non-saturated. The handling of saturation and/or non linearity is possible but requires a more advanced pre-pocessing that is beyond the scope of this tutorial.
  • it has to be reasonably well corrected, characterized by a Strehl ratio ~60 % or better.
  • images are also assumed to be pre-processed: dark-subtracted, flat-field corrected, bad-pixels accounted for; and the image has been chopped to a square, at least roughly centered on the target of interest in the image.

You also need to know:

  • at what wavelength it was acquired (central wavelength of your filter)
  • what is the plate scale of the image (how many milli-arcseconds per pixels?)

And finally, you need to have access to a reliable description of the pupil of the instrument used to acquire your image. The better the description, the more accurate the kernel-phases that can be extracted from your images will be. From this description of the instrument pupil, you will build a discrete representation of this pupil.

The discrete model is achromatic: positions of virtual sub-apertures and baselines are indeed expressed in meters and not in radians (B/λ) like it is customary in long baseline interferometry. When processing images, the achromatic model however needs to be scaled for the data-set, which is why the information about wavelength and the plate-scale is essential.

The scaling parameter is a variable called m2pix in the code (standing for meter-to-pixel conversion factor). The user rarely has to worry about it as it is handled by the KPO object meyhods, but it may be useful to know that it is defined as follows:

pscale = 16.7   # plate scale of the image (in mas/pixel)
wl     = 1.6e-6 # wavelength of the image  (in meters)
ISZ    = 128    # image size               (128x128)

m2pix  = xara.core.mas2rad(pscale) * ISZ / cwavel

3 The context of the tutorial

This tutorial will rely on simulated images that are fairly representative of an actual instrument. We will assume that we are working with XAO-corrected images produced by SCExAO, currently installed at the Nasmyth-IR focus of the Subaru Telescope.

  • the pupil is at a fixed angle (field de-rotator turned off)
  • the plate scale is 16.7 mas/pixels
  • the central wavelength is 1.6 micron
  • the images are chopped to a 140x140 pixel size, covering a 2.3 x 2.3 arc second field of view

4 Extraction of kernels

import xara
import as pf

# load the image
img = pf.get_data("my_image.fits")

# creation of the KERNEL model
cal = xara.KPO(fname="my_discrete_model.txt")

# image kernel-extraction
pscale = 16.7   # plate scale of the image          (in mas/pixel)
wl     = 1.6e-6 # wavelength the image was acquired (in meters)

cal.extract_KPD_single_frame(img, pscale, wl, target="The Banana Star", recenter=True)

# saving the result as a kernel FITS file

On a somewhat humble chromebook, the creation of the KERNEL model takes ~15 seconds, for this special case (cf output by XARA):

  • 428 sub-apertures
  • 1000 distinct baselines
  • 786 Ker-phases (78.6 % target phase information recovery)
  • 214 Eig-phases (50.0 % wavefront information recovery)

The first time the Fourier-phase information is extracted out of an image (when calling cal.extract_KPD_single_frame(), an auxilliary matrix (called cal.FF) used to the Fourier transform explicitly for the uv coordinates of the discrete is computed. The time this operation takes will depend on the total number of pixels in the image along with the number of baselines. On the same humble chromebook mentioned before, the first extraction of the 786 kernels of the model on a 140x140 image takes less than 5 seconds.

If other images need to be processed by XARA, as long as the size of the images and the wavelength of observation remain the same, the same matrix can be reused again and the extraction of kernels is almost instantaneous.

5 The kernel-phase data structure

The kernels extracted from the image are included to the cal object structure and appended to a kpo class member list called KPDT, and each call to an extract_KPD_...() function call will append an array to cal.KPDT. Depending on the number of images or the number of slices in the data cube provided to the function call, the dimensions the the added array can vary. This possibility is reflected in the structure of the FITS file with multiple KP-DATA tables.

If you want to print or visualize the kernel-phase, you need to keep track of two indices:

  • the index of the data-set
  • the index of one kernel-realization in the chosen data-set

For this simple scenario with only one data set, the indices pointing to the data are both equal to zero. Thus:

ii = 0 # data-set index
jj = 0 # kernel-phase realization index


f1 = plt.figure(figsize=(12,7))
ax1 = f1.add_subplot(111)
ax1.plot(cal.KPDT[ii][jj], label="tutorial data-set")
ax1.set_xlabel("Kernel-phase index")
ax1.set_ylabel("Kernel-phase (radian)")

6 Interpretation of the kernels

At this point, the user has access to a series of (for this special case) 786 kernels, which are linear combinations of Fourier-phases.

Back to the documentation index

Author: Frantz Martinache

Created: 2019-01-09 Wed 18:40