{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Interferograms\n", "\n", "Prysm offers rich features for analysis of interferometric data. Interferogram objects are conceptually similar to [Pupils](./Pupils.ipynb) and both inherit from the same base class, as they both have to do with optical phase. The construction of an `Interferogram` requires only a few parameters:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from prysm import Interferogram\n", "x = y = np.arange(129)\n", "z = np.random.uniform((128,128))\n", "interf = Interferogram(phase=z, intensity=None, x=x, y=y, scale='mm', phase_unit='nm', meta={'wavelength': 632.8e-9})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notable are the scale, and phase unit, which define the x, y, and z units. Any SI unit is accepted as well as angstroms. Imperial units not accepted. meta is a dictionary to store metadata. For several interferogram methods to work, the wavelength must be present in meters. This departure from `prysm`’s convention of preferred units is used to maintain compatability with Zygo dat files. Interferograms are usually created from such files:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from prysm import sample_files\n", "\n", "interf = Interferogram.from_zygo_dat(sample_files('dat'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and both the dat and datx format from Zygo are supported. Dat carries no dependencies, while datx requries the installation of `h5py`. In addition to properties inherited from the OpticalPhase class (`pv`, `rms`, `Sa`, `std`), Interferograms have a `PVr` property, for C. Evan's Robust PV metric, and `dropout_percentage` property, which gives the percentage of NaN values within the phase array. These NaNs may be filled," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.fill(_with=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "with 0 as a default value; only constants are supported. The modification is done in-place and the method returns self. Piston, tip-tilt, and power may be removed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.remove_piston().remove_tiptilt().remove_power()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "again done in-place and returning self, so methods can be chained. You should remove these terms (or, indeed do anything with Zernikes) before filling NaNs. One line convenience wrappers exist:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.remove_piston_tiptilt()\n", "interf.remove_piston_tiptilt_power()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "spikes may also be clipped," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.spike_clip(nsigma=3) # default is 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "setting points with a value more than nsigma standard deviations from the mean to NaN.\n", "\n", "If the data did not have a lateral calibration baked into it, you can provide one in `prysm`," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# this is not going to do what you want if your data is already calibrated.\n", "interf.latcal(plate_scale=0.1, unit='mm')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Masks may be applied:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "your_mask = np.ones(interf.phase.shape)\n", "interf.mask(your_mask)\n", "interf.mask('circle', diameter=4) # 4 diameter circle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The truecircle mask should not be used on interferometric data. the phase is deleted (replaced with NaN) wherever the mask is equal to zero.\n", "\n", "Interferograms may be cropped, deleting empty (NaN) regions around a measurment;" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.crop()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Convenience properties are provided for data size," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.shape, interf.size, interf.diameter_x, interf.diameter_y, interf.diameter, interf.semidiameter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`shape` and `size` mirrors the underlying `interf.phase` ndarray. The x and y diameters are in units of `interf.spatial_unit` and `diameter` is the greater of the two.\n", "\n", "The two dimensional Power Spectral Density (PSD) may be computed. The data may not contain NaNs, and piston tip and tilt should be removed prior. A 2D Welch window is used for circular data and a 2D Hanning window for rectangular data, so there is no need for concern about zero values creating a discontinuity at the edge of circular or other nonrectangular apertures." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.crop().remove_piston_tiptilt_power().fill()\n", "ux, uy, psd = interf.psd()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "several slices are also available," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "psd_dict = interf.psd_slices(x=True, y=True, azavg=True, azmin=True, azmax=True)\n", "ux, psd_x = psd_dict['x']\n", "uy, psd_y = psd_dict['y']\n", "ur, psd_r = psd_dict['azavg']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and the PSD may be plotted," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.plot_psd2d(axlim=1, interp_method='lanczos', fig=None, ax=None)\n", "interf.plot_psd_slices(xlim=(1e0,1e3), ylim=(1e-7,1e2), fig=None, ax=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the slices plot, a Lorentzian or power law model may be plotted alongside the data for e.g. visual verification of a requirement:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.plot_psd_slices(a=1,b=2,c=3)\n", "interf.plot_psd_slices(a=1,b=1.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A bandlimited RMS value derived from the 2D PSD may also be evaluated," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.bandlimited_rms(wllow=1, wlhigh=10, flow=1, fhigh=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "only one of wavelength (wl; spatial period) or frequency (f) should be provided. f will clobber wavelength." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interf.plot2d()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.2" } }, "nbformat": 4, "nbformat_minor": 2 }