Closed jonathanabishop closed 4 years ago
What version are you using, 0.17.x?
When I re-wrote the "header" to your code as:
system_wavelength = 500e-9 # meters
system_aperture_diameter = 100e-3 # meters
system_W_pp = 1 # waves, expect a zero at the center of the PSF
system_f_number = 10
prysmWavelength = system_wavelength * 1e6
prysmDiameter = system_aperture_diameter * 1000
prysmDefocus = prysmWavelength * system_W_pp
I'm assuming W_pp is supposed to be a Hopkins coefficient (W020). In the algebra, with the example of unity, this spits out 0.5 for prysmDefocus, which is interpreted as 0.5 nm, since the default z_unit
argument is nm
.
For debugging things like this, the print is likely helpful:
>>> print(prysmPupil)
Fringe Zernike description with:
+0.250 Z4 - Defocus
0.496 PV, 0.144 RMS [nm]
You could change your call that looks like:
prysmPupil = FringeZernike(\
wavelength=prysmWavelength,
dia=prysmDiameter,
samples=50,
Z4=prysmDefocus/2)
to:
prysmPupil = FringeZernike(\
wavelength=prysmWavelength,
dia=prysmDiameter,
samples=50,
Z4=prysmDefocus/2,
z_unit='um') # <- see this line
As an aside, as well, 5,000 samples is very very large and you can get away with far smaller numbers, like the default of 128, unless you have a monstrous amount of OPD, care about things very far away in the spatial/PSF domain, or need the fidelity to be extremely high (back of a napkin, you should get to 1e-13 level with 5,000 samples).
The accuracy will actually turn around eventually due to floating point overflow. I know 10,000x10,000 is too many samples for complex doubles if the signal has a scale much bigger than unity.
As an aside2, "raw" numeric wavelengths in prysm are given in microns; if you are ever unsure about a unit, the docstring (in this case, help(prysm.Pupil)
will tell you, or you can use an astropy quantity, as in:
from prysm import FringeZernike
from astropy import units as u
FringeZernike(wavelength = 500 * u.nm)
Of course this doesn't really matter for the purposes of the issue, since the wavelength just changes the coordinates of the MTF.
Did you look at the user's guide for Zernikes and Pupils? If so, was anything unclear? How about the API documentation (things like help(prysmPupil)
? If anything was unclear, could you please open a PR to improve the docs?
Thank you for the quick reply.
I've found the issue--I had seen that Pupils have default z_units of nm, and missed that the default wavelengths are in um. Everything else was fine.
As an aside, I found samples=129 more pleasing since it then includes a point at the center and gives print(prysmPupil) then gives exactly the expected PV value.
128 vs 129 accuracy just has to do with even vs odd numbers of samples. In the even case, you can have a point at one extreme or the other - so you end up a bit shy on one side. Powers of two should have better performance, but that is very old advise that I've never bothered to test.
I'm attempting to calculate the aberrated MTF using a pupil defined using FringeZernike. In this particular case, it has only first order defocus. I expect the result to match closely with Hopkins' solution (or Shannon's approximation). Plotting the pupil function and printing the output from the Pupil object, I have the expected amount of defocus, but the MTF that's plotted is the classic diffraction-limited MTF. A prysm-specific snippet that plots using the variables I've separately calculated for Shannon's approximation is below.
If I'm missing something in the implementation, I apologize, but it looks after several reviews like the inputs are consistent with what I want and what prysm wants.
Any assistance is appreciated.