def test_hex_aperture(): """ Ensure the hex aperture used for Zernikes is consistent with the regular poppy HexagonAperture """ npix_to_try = [10, 11, 12, 13, 100, 101, 512, 513] for npix in npix_to_try: assert np.all(optics.HexagonAperture(side=1).sample(npix=npix) - zernike.hex_aperture( npix=npix) == 0), "hex_aperture and HexagonAperture outputs differ for npix={}".format(npix)
def __init__(self, nhex=15, narr=200, extrasupportindex=None): """ Input: nzern: number of Noll Zernikes to use in the fit Input: narr: the live pupil array size you want to use Sets up list of poly's and grids & support grids Makes coordinate grid for rho and phi and circular support mask Calculates 'overlap integrals' (covariance matrix) of the Zernike polynomials on your grid and array size Calculates the inverse of this matrix, so it's 'ready to fit' your incoming array """ self.narr = narr self.nhex = nhex # tbd - allowed numbers from Pascal's Triangle sum(n) starting from n=1, viz. n(n+1)/2 self.grid = (N.indices((self.narr, self.narr), dtype=N.float) - self.narr // 2) / (float(self.narr) * 0.5) self.grid_rho = (self.grid**2.0).sum(0)**0.5 self.grid_phi = N.arctan2(self.grid[0], self.grid[1]) self.grid_mask = self.grid_rho <= 1 self.grid_outside = self.grid_rho > 1 if extrasupportindex is not None: self.grid_mask[extrasupportindex] = 0 self.grid_outside[extrasupportindex] = 1 # Compute list of explicit Zernike polynomials and keep them around for fitting self.hex_list = z.hexike_basis(nterms=self.nhex, npix=self.narr) self.hex_list = z.hexike_basis(nterms=self.nhex, npix=self.narr) # Force hexikes to be unit standard deviation over hex mask for h, hfunc in enumerate(self.hex_list): if h > 0: self.hex_list[h] = ( hfunc / hfunc[self.grid_mask].std()) * self.grid_mask else: self.hex_list[0] = hfunc * self.grid_mask #### Write out a cube of the hexikes in here if 0: self.stack = N.zeros((self.nhex, self.narr, self.narr)) for ii in range(len(self.hex_list)): self.stack[ii, :, :] = self.hex_list[ii] # Calculate covariance between all Zernike polynomials self.cov_mat = N.array([[N.sum(hexi * hexj) for hexi in self.hex_list] for hexj in self.hex_list]) self.grid_mask = z.hex_aperture(npix=self.narr) == 1 self.grid_outside = self.grid_mask == False # Invert covariance matrix using SVD self.cov_mat_in = N.linalg.pinv(self.cov_mat)
def zern_seg(self, segment, vmax=150, unit='nm'): """ Show the Zernike terms applied to a given segment""" # the actual wavefront is always in units of microns. if unit == 'nm': scalefact = 1000. elif unit =='micron': scalefact = 1.0 else: raise ValueError("unknown unit keyword") nzerns = 11 title = "Zernike components for "+segment zerns = np.zeros((nzerns)) if segment+"-decenter" in self.state.keys(): zerns += self._move(segment, type='decenter', vector=self.state[segment+"-decenter"], return_zernikes=True) title += ", displacement=[%.2e, %.2e, %.2e] um" % tuple(self.state[segment+"-decenter"]) if segment+"-tilt" in self.state.keys(): zerns += self._move(segment, type='tilt', vector=self.state[segment+"-tilt"], return_zernikes=True) title += ", tilts =[%.5f, %.5f, %.5f] urad" % tuple(self.state[segment+"-tilt"]) _log.info("Zerns: "+str(zerns)) fig = plt.gcf() fig.clf() npix=200 hexap = zernike.hex_aperture(npix) hexap[np.where(hexap == 0)] = np.nan cmap = matplotlib.cm.jet cmap.set_bad('0.5', alpha=0.0) for j in np.arange(nzerns)+1: ax = fig.add_subplot(3, 4, j, frameon=False, xticks=[], yticks=[]) # n, m = zernike.noll_indices(j) Z = zernike.zernike1(j, npix=npix) ax.imshow(Z * zerns[j-1] * hexap*scalefact, vmin=-1*vmax, vmax=vmax, cmap=cmap) ax.text(npix*0.95, npix*0.8, "$Z%d$" % (j), fontsize=20, horizontalalignment='right') ax.text(npix*0.95, npix*0.1, "%.2e" % (zerns[j-1]), fontsize=15, horizontalalignment='right') fig.text(0.5, 0.95, title, horizontalalignment='center', fontsize=15) fig.text(0.95, 0.15, 'Segment RMS WFE = %.2f %s ' % (self.rms(segment)*(scalefact/1000), unit), fontsize=10, horizontalalignment='right') #fig.text(0.95, 0.05, 'OPDs scaled from %.2e - %.2e um' % (-vmax, vmax), horizontalalignment='right', fontsize=10) fig.text(0.95, 0.05, 'OPDs scaled from %.2f - %.2f %s' % (-vmax, vmax, unit), horizontalalignment='right', fontsize=10) plt.draw()