slmsuite.hardware.slms.slm.SLM#
- class SLM(resolution, bitdepth=8, name='SLM', wav_um=1, wav_design_um=None, pitch_um=(8, 8), settle_time_s=0.3)[source]#
Bases:
_PicklableAbstract class for SLMs.
- name#
Name of the SLM.
- Type:
str
- shape#
Stores
(height, width)of the SLM in pixels, the same convention asnumpy.ndarray.shape.- Type:
(int, int)
- bitdepth#
Depth of SLM pixel well in bits. This is useful for converting the floats which the user provides to the
bitdepth-bit ints that the SLM reads (see the private method_phase2gray()).- Type:
int
- bitresolution#
Stores
2 ** bitdepth.- Type:
int
- settle_time_s#
Delay in seconds to allow the SLM to settle. This is mostly useful for applications requiring high precision. This delay is applied if the user flags
settleinset_phase(). Defaults to .3 sec for precision.- Type:
float
- pitch_um#
Pixel pitch in microns.
- Type:
(float, float)
- pitch#
Pixel pitch normalized to wavelengths
pitch_um / wav_um. This value is more useful thanpitch_umwhen considering conversions to \(k\)-space.- Type:
float
- wav_um#
Operating wavelength targeted by the SLM in microns. Defaults to 780 nm.
- Type:
float
- wav_design_um#
Design wavelength for which the maximum settable value corresponds to a \(2\pi\) phase shift. Defaults to
wav_umif passedNone.Tip
wav_design_umis useful for using, for instance, an SLM designed at 1064 nm for an application at 780 nm by using only a fraction (780/1064) of the full dynamic range. It is especially useful for SLMs which do not have builtin capability to change their voltage lookup tables (e.g. Thorlabs). Even so, the max lookup wavelength (wav_design_um) could be set larger thanwav_umshould the user want to have a phase range larger than \(2\pi\), for SLMs with lookup table capability.- Type:
float
- phase_scaling#
Wavelength normalized to the phase range of the SLM. See
wav_design_um. Determined byphase_scaling = wav_um / wav_design_um.- Type:
float
- grid#
\(x\) and \(y\) coordinates of the SLM’s pixels in wavelengths (see
wav_um,pitch_um) measured from the center of the SLM. Of sizeshape. Produced bynumpy.meshgrid().- Type:
(numpy.ndarray<float> (height, width), numpy.ndarray<float> (height, width))
- source#
Stores data describing measured, simulated, or estimated properties of the source, such as amplitude and phase. Typical keys include:
"amplitude"numpy.ndarraySource amplitude (with the dimensions of
shape) measured on the SLM viawavefront_calibrate(). Also seeset_source_analytic()to set without wavefront calibration."phase"numpy.ndarraySource phase (with the dimensions of
shape) measured on the SLM viawavefront_calibrate(). Also seeset_source_analytic()to set without wavefront calibration.
For a
SimulatedSLM(),"amplitude_sim"and"phase_sim"keywords store the true source properties (defined by the user) used to simulate the SLM’s far-field.When
fit_source_amplitude()is called,- Type:
dict
- phase#
Displayed data in units of phase (radians).
- Type:
numpy.ndarray
- display#
Displayed data in SLM units (integers).
- Type:
numpy.ndarray
Methods
Abstract method to close the SLM and delete related objects.
Extracts various
sourceparameters from the source for use in analytic functions.Fourier transforms the wavefront calibration's measured amplitude to find the expected diffraction-limited performance of the system in
"knm"space.Extracts the scaling for
zernike_aperture()from the scalars computed infit_source_amplitude().Extracts the source radius in normalized units for functions like
laguerre_gaussian()from the scalars computed infit_source_amplitude().Extracts the scaling for
zernike_aperture()from the scalars computed infit_source_amplitude().Approximates the expected standard deviation radius of farfield spots in the
"kxy"basis based on the near-field amplitude distribution stored insource.Abstract method to load display information.
Loads
displayfrom a file and writes to the SLM.Loads vendor-provided phase correction from file, setting
source["phase"].Returns a dictionary containing selected attributes of this class.
Plots the provided phase.
Plots measured or simulated amplitude and phase distribution of the SLM illumination.
Saves the dictionary returned from
pickle()to a file like"path/name_id.h5".Checks, cleans, and adds to data, then sends the data to the SLM and potentially waits for settle.
In the absence of a proper wavefront calibration, sets
sourceamplitude and phase using a fit_function fromfitfunctions.Backwards-compatibility alias for
set_phase().- __init__(resolution, bitdepth=8, name='SLM', wav_um=1, wav_design_um=None, pitch_um=(8, 8), settle_time_s=0.3)[source]#
Initialize SLM.
- Parameters:
resolution –
The width and height of the camera in
(width, height)form.Important
This is the opposite of the numpy
(height, width)convention stored inshape.bitdepth – See
bitdepth. Defaults to 8.name – See
name.wav_um – See
wav_um.wav_design_um – See
wav_design_um.pitch_um – See
pitch_um. Defaults to 8 micron square pixels.settle_time_s – See
settle_time_s.
- static info(verbose=True)[source]#
Abstract method to load display information.
- Parameters:
verbose (bool) – Whether or not to print display information.
- Returns:
An empty list.
- Return type:
list
- load_vendor_phase_correction(file_path)[source]#
Loads vendor-provided phase correction from file, setting
source["phase"]. By default, this is interpreted as an image file and is padded or unpadded to the shape of the SLM. Subclasses should implement vendor-specific routines for loading and interpreting the file (e.g.Santecloads a .csv).- Parameters:
file_path (str) – File path for the vendor-provided phase correction.
- Returns:
source["phase"], the vendor-provided phase correction.- Return type:
numpy.ndarray
- plot(phase=None, limits=None, title='Phase', ax=None, cbar=True)[source]#
Plots the provided phase.
- Parameters:
phase (ndarray OR None) – Phase to be plotted. If
None, grabs the last writtenphasefrom the SLM.limits (None OR float OR [[float, float], [float, float]]) – Scales the limits by a given factor or uses the passed limits directly.
title (str) – Title the axis.
ax (matplotlib.pyplot.axis OR None) – Axis to plot upon.
cbar (bool) – Also plot a colorbar.
- Returns:
Axis of the plotted phase.
- Return type:
matplotlib.pyplot.axis
- write(phase, phase_correct=True, settle=False)[source]#
Backwards-compatibility alias for
set_phase().
- set_phase(phase, phase_correct=True, settle=False)[source]#
Checks, cleans, and adds to data, then sends the data to the SLM and potentially waits for settle. This method calls the SLM-specific private method
_set_phase_hw()which transfers the data to the SLM.Warning
Subclasses implementing vendor-specific software should not overwrite this method. Subclasses should overwrite
_set_phase_hw()instead.Caution
The sign on
phaseis flipped before converting to integer data. This is to convert between the ‘increasing value ==> increasing voltage (= decreasing phase delay)’ convention in most SLMs andslmsuite’s ‘increasing value ==> increasing phase delay’ convention. As a result, zero phase will appear entirely white (255 for an 8-bit SLM), and increasing phase will darken the displayed pattern. If integer data is passed, this data is displayed directly and the sign is not flipped.Important
The user does not need to wrap (e.g.
numpy.mod(data, 2*numpy.pi)) the passed phase data, unless they are pre-caching data for speed (see below).set_phase()uses optimized routines to wrap the phase (see the private method_phase2gray()). Which routine is used depends onphase_scaling:phase_scalingis one.Fast bitwise integer modulo is used. Much faster than the other routines which depend on
numpy.mod().
phase_scalingis less than one.In this case, the SLM has more phase tuning range than necessary. If the data is within the SLM range
[0, 2*pi/phase_scaling], then the data is passed directly. Otherwise, the data is wrapped by \(2\pi\) using the very slownumpy.mod(). Try to avoid this in applications where speed is important.
phase_scalingis more than one.In this case, the SLM has less phase tuning range than necessary. Processed the same way as the
phase_scalingis less than one case, with the important exception that phases (after wrapping) between2*pi/phase_scalingand2*piare set to zero. For instance, a sawtooth blaze would be truncated at the tips.
Caution
After scale conversion, data is
floor()ed to integers withnp.copyto, rather than rounded to the nearest integer (np.rint()equivalent). While this is irrelevant for the average user, it may be significant in some cases. If this behavior is undesired consider either:set_phase()integer data directly or modifying the behavior of the private method_phase2gray()in a pull request. We have not been able to find an example ofnp.copytoproducing undesired behavior, but will change this if such behavior is found.- Parameters:
phase (numpy.ndarray OR slmsuite.holography.algorithms.Hologram OR None) –
Phase data to display in units of \(2\pi\), unless the passed data is of integer type and the data is applied directly.
If
Noneis passed toset_phase(), data is zeroed.If a
Hologramis passed, the phase is grabbed fromget_phase().If the array has a larger shape than the SLM shape, then the data is cropped to size in a centered manner (
unpad).If integer data is passed with the same type as
display(np.uint8for <=8-bit SLMs,np.uint16otherwise), then this data is directly passed to the SLM, without going through the “phase delay to grayscale” conversion defined in the private method_phase2gray(). In this situation,phase_correctis ignored. This is error-checked such that bits with greater significance than the bitdepth of the SLM are zero (e.g. the final 6 bits of 16 bit data for a 10-bit SLM). Integer data with type different fromdisplayleads to a TypeError.
Usually, an exact stored copy of the data passed by the user under
phaseis stored in the attributephase. However, in cases wherephase_scalingnot one, this copy is modified to include how the data was wrapped. If the data was cropped, then the cropped data is stored, etc. If integer data was passed, the equivalent floating point phase is computed and stored in the attributephase.phase_correct (bool) – Whether or not to add
source```["phase"]`tophase.settle (bool) – Whether to sleep for
settle_time_s.
- Returns:
display, the integer data sent to the SLM.- Return type:
numpy.ndarray
- Raises:
TypeError – If integer data is incompatible with the bitdepth or if the passed phase is otherwise incompatible (not a 2D array or smaller than the SLM shape, etc).
- save_phase(path='.', name=None)[source]#
Saves
phaseanddisplayto a file like"path/name_id.h5".- Parameters:
path (str) – Path to directory to save in. Default is current directory.
name (str OR None) – Name of the save file. If
None, will usename+'-phase'.
- Returns:
The file path that the phase was saved to.
- Return type:
str
- load_phase(file_path=None, settle=False)[source]#
Loads
displayfrom a file and writes to the SLM.- Parameters:
file_path (str OR None) – Full path to the phase file. If
None, will search the current directory for a file with a name likename+'-phase'.settle (bool) – Whether to sleep for
settle_time_s.
- Returns:
The file path that the phase was loaded from.
- Return type:
str
- Raises:
FileNotFoundError – If a file is not found.
Warning – Warns the user if the stored
phasedoes not agree with the displayed value.
- set_source_analytic(fit_function='gaussian2d', units='norm', phase_offset=0, sim=False, **kwargs)[source]#
In the absence of a proper wavefront calibration, sets
sourceamplitude and phase using a fit_function fromfitfunctions.Note
FourierSLMincludes capabilities for wavefront calibration viawavefront_calibrate(). This process also measures the amplitude of the source on the SLM and stores this insource.sourcekeywords are also used for better refinement of holograms during numerical optimization. If unable to runwavefront_calibrate(), this method allows the user to set an approximation of the complex source.- Parameters:
fit_function (str OR lambda) – Function name from
fitfunctionsused to set the source profile. The function can also be passed directly. Defaults to"gaussian2d".units (str in {"norm", "frac", "nm", "um", "mm", "m"}) – Units for the \((x,y)\) grid passed to
fit_function. This essentially determines the scaling on the normalized grid stored in the SLM which is passed to thefit_function.sim (bool) – Sets the simulated source distribution if
Trueor the approximate experimental source distribution (in absence of wavefront calibration) ifFalse.phase_offset (float OR numpy.ndarray) – Additional phase (of shape
shape) added tosource.**kwargs – Arguments passed to
fit_functionin addition to the SLM grid in the requestedunits. If thefit_functionis"gaussian2d"and no keyword arguments have been passed, the radius defaults to 1/2 of the smaller of the two SLM dimensions.
- Returns:
- Return type:
dict
- fit_source_amplitude(method='moments', extent_threshold=0.1, force=True)[source]#
Extracts various
sourceparameters from the source for use in analytic functions. This is done by analyzing thesource["amplitude"]distribution with"moments"or least squares"fit". These parameters include the following keys:"amplitude_center_pix": (float, float)Pixel corresponding to the center of the source. The grid is also changed to be centered on this pixel.
"amplitude_radius": floatThe radial standard deviation of the amplitude distribution in normalized units. For a Gaussian source, this is the \(1/e\) amplitude radius (\(1/e^2\) power radius). This is scalar and averages the \(x\) and \(y\) distributions. This is used to set the source radius for
laguerre_gaussian()and similar."amplitude_extent": (float, float)The box radii of the smallest rectangle which covers all amplitude larger than
extent_threshold, where the maximum of the distribution is normalized to one."amplitude_extent_radius": floatSmallest scalar radius about the center of the that covers all amplitude larger than
extent_threshold, where the maximum of the distribution is normalized to one. This is used to determine the scaling forzernike_aperture(): Too small of a scaling is not good because amplitude would overlap outside where Zernike is defined, with divergent phase for higher order Zernike polynomials. Too large of a scaling is not good because one needs to use high order Zernike to attain sufficient spatial resolution at the center of the distribution.
Important
If
source["amplitude"]is not set, then the parameters are guessed as fractions of the grid:"amplitude_center_pix"Unchanged from current center."amplitude_radius"Guessed as 1/4 of the smallest extent."amplitude_extent"Guessed as the the rectangle that circumscribes the SLM field."amplitude_extent_radius"Guessed as the the radius that circumscribes the SLM field.
Important
The
gridis recentered upon the detected center of the source. Thisgridis used to generated phase functions likelens()orlaguerre_gaussian(). Such generation works best when centered upon the source; alens()focuses coaxially and alaguerre_gaussian()appears symmetric.- Parameters:
method (str {"fit", "moments"}) – Whether to use moment calculations
"moments"or a least squares"fit"to determine"amplitude_center_pix"and"amplitude_radius"."moments"is faster but"fit"is more accurate.extent_threshold (float) – Fraction of the maximal amplitude to use as the full extent of the amplitude distribution.
force (bool) – If
False, does not calculate if these quantities already exist.Trueforces recomputation.
- get_source_radius()[source]#
Extracts the source radius in normalized units for functions like
laguerre_gaussian()from the scalars computed infit_source_amplitude().
- get_source_zernike_scaling()[source]#
Extracts the scaling for
zernike_aperture()from the scalars computed infit_source_amplitude().
- get_source_center()[source]#
Extracts the scaling for
zernike_aperture()from the scalars computed infit_source_amplitude().
- pickle(attributes=True, metadata=True)[source]#
Returns a dictionary containing selected attributes of this class.
- Parameters:
attributes (bool OR list of str) – If
False, pickles only baseline attributes, usually single floats. IfTrue, also pickles ‘heavy’ attributes such as large images and calibrations. Iflist of str, pickles the keys in the given list. By default, the chosen attributes should be things that can be written to .h5 files: scalars and lists of scalars.metadata (bool) – If
True, package the dictionary as the"__meta__"value of a superdictionary which also contains:"__version__", the current slmsuite version,"__time__", the time formatted as a date string, and"__timestamp__", the time formatting as a floating point timestamp. This information is used as standard metadata for calibrations and saving.
- plot_source(sim=False, power=False)[source]#
Plots measured or simulated amplitude and phase distribution of the SLM illumination. Also plots the rsquared goodness of fit value if available.
- Parameters:
sim (bool) – Plots the simulated source distribution if
Trueor the measured source distribution ifFalse.power (bool) – If
True, plot the power (amplitude squared) instead of the amplitude.
- Returns:
Axis handles for the generated plot.
- Return type:
matplotlib.pyplot.axis
- save(path='.', name=None, **kwargs)[source]#
Saves the dictionary returned from
pickle()to a file like"path/name_id.h5".- Parameters:
- Returns:
The file path that the pickled data was saved to.
- Return type:
str
- get_point_spread_function_knm(padded_shape=None)[source]#
Fourier transforms the wavefront calibration’s measured amplitude to find the expected diffraction-limited performance of the system in
"knm"space.- Parameters:
padded_shape ((int, int) OR None) – The point spread function changes in resolution depending on the padding. Use this variable to provide this padding. If
None, do not pad.- Returns:
The point spread function of shape
padded_shape.- Return type:
numpy.ndarray
- get_spot_radius_kxy()[source]#
Approximates the expected standard deviation radius of farfield spots in the
"kxy"basis based on the near-field amplitude distribution stored insource. For a Gaussian source, this is the \(1/e\) amplitude radius (\(1/e^2\) power radius).- Returns:
Radius of the farfield spot.
- Return type:
float