Using POPPY, Physical Optics Propagation in Python https://github.com/mperrin/poppy/
The simplest example from the documentation, http://www-int.stsci.edu/~mperrin/software/poppy/examples.html#a-simple-circular-pupil:
osys = poppy.OpticalSystem()
osys.addPupil(function='Circle', radius=3) # pupil radius in meters
osys.addDetector(pixelscale=0.010, fov_arcsec=5.0) # image plane coordinates in arcseconds
psf = osys.calcPSF(2e-6) # wavelength in microns
poppy.display_PSF(psf, title='The Airy Function')
Simply incrasing the plate scale to 0.1"/pixel introduces considerable edge effects from undersampling the input pupil.
osys = poppy.OpticalSystem()
osys.addPupil(function='Circle', radius=3) # pupil radius in meters
osys.addDetector(pixelscale=0.10, fov_arcsec=5.0) # image plane coordinates in arcseconds
psf = osys.calcPSF(2e-6) # wavelength in microns
poppy.display_PSF(psf, title='The Airy Function')
To produce a realistic psf, oversample to 20 rather than the default of 2. This will produce an accurate PSF, which can then be downsampled according to the pixel geometry:
osys = poppy.OpticalSystem()
osys.addPupil(function='Circle', radius=3) # pupil radius in meters
osys.addDetector(pixelscale=0.10, fov_arcsec=5.0,oversample=20) # image plane coordinates in arcseconds
psf = osys.calcPSF(2e-6) # wavelength in microns
poppy.display_PSF(psf, title='The Airy Function')