Wasatch.PY
Python application driver for Wasatch Photonics spectrometers
Loading...
Searching...
No Matches
wasatch.WasatchDevice.WasatchDevice Class Reference

A WasatchDevice encapsulates and wraps a Wasatch spectrometer in a blocking interface. More...

Inheritance diagram for wasatch.WasatchDevice.WasatchDevice:
wasatch.InterfaceDevice.InterfaceDevice

Public Member Functions

 __init__ (self, DeviceID device_id, Queue message_queue=None)
 
 acquire_data (self)
 
 acquire_spectrum (self)
 Generate one Reading from the spectrometer, including one optionally-averaged spectrum, device temperatures and other hardware status.
 
 acquire_spectrum_auto_raman (self)
 
 acquire_spectrum_standard (self)
 
 balance_acquisition (self, device=None, mode=None, intensity=45000, threshold=2500, pixel=None, max_integration_time_ms=5000, max_tries=20)
 
 change_setting (self, str setting, Any value, bool allow_immediate=True)
 Processes an incoming (setting, value) pair.
 
 connect (self)
 Attempt low level connection to the specified DeviceID.
 
 connect_feature_identification (self)
 Given a specified universal identifier, attempt to connect to the device using FID protocol.
 
 disconnect (self)
 
 handle_requests (self, list[SpectrometerRequest] requests)
 
 initialize_settings (self)
 
 monitor_memory (self)
 
 perform_optional_throwaways (self)
 It's unclear how many throwaways are really needed for a stable Raman spectrum, and whether they're really based on number of integrations (sensor stabilization) or time (laser warmup); I suspect both.
 
 process_commands (self)
 Process every entry on the incoming command (settings) queue, writing each to the device.
 
 take_one_averaged_reading (self, label=None)
 

Public Attributes

 auto_raman
 
 command_queue
 
 connected
 
 device_id
 
 hardware
 
 immediate_mode
 
 last_battery_percentage
 
 last_complete_acquisition
 
 last_memory_check
 
 lock
 
 message_queue
 
 process_f
 
 process_id
 
 session_reading_count
 
 settings
 
 sum_count
 Aggregate scan averaging.
 
 summed_spectra
 
 take_one_request
 
- Public Attributes inherited from wasatch.InterfaceDevice.InterfaceDevice
 process_f
 
 remaining_throwaways
 

Protected Member Functions

 _init_process_funcs (self)
 

Detailed Description

A WasatchDevice encapsulates and wraps a Wasatch spectrometer in a blocking interface.

It will normally wrap one of the following:

ENLIGHTEN does not instantiate WasatchDevices directly, but instead uses a WasatchDeviceWrapper to access a single WasatchDevice in a dedicated child thread. Other users of Wasatch.PY may of course instantiate a WasatchDevice directly.

Constructor & Destructor Documentation

◆ __init__()

wasatch.WasatchDevice.WasatchDevice.__init__ ( self,
DeviceID device_id,
Queue message_queue = None )
Parameters
device_ida DeviceID instance OR string label thereof
message_queueif provided, used to send status back to caller

Reimplemented from wasatch.InterfaceDevice.InterfaceDevice.

Member Function Documentation

◆ _init_process_funcs()

wasatch.WasatchDevice.WasatchDevice._init_process_funcs ( self)
protected

◆ acquire_data()

wasatch.WasatchDevice.WasatchDevice.acquire_data ( self)
Process all enqueued settings, then read actual data (spectrum and
temperatures) from the device.

ENLIGHTEN calls this function via WrapperWorker.run().

@see Controller.acquire_reading

◆ acquire_spectrum()

wasatch.WasatchDevice.WasatchDevice.acquire_spectrum ( self)

Generate one Reading from the spectrometer, including one optionally-averaged spectrum, device temperatures and other hardware status.

This is normally called by self.acquire_data when that function decides it is time to perform an acquisition.

Scan Averaging

IF the driver is in free-running mode, AND performing scan averaging, THEN scan averaging is NOT encapsulated within a single call to this function. Instead, we let ths spectrometer run in free-running mode, collecting individual spectra as per normal, and returning each "partial" readings while "building up" to the final averaged measurement.

That is to say, if scan averaging is set to 10, then this function will get called 10 times, as ticked by the regular free-running timers, before the fully averaged spectrum is returned. A total of 10 (not 11) spectra will be generated and sent upstream: the first 9 "partial" (unaveraged) reads, and the final 10th spectrum which will contain the average of all 10 measurements.

This gives the user-facing GUI an opportunity to update the "collected X-of-Y" readout on-screen, and potentially even graph the traces of in-process partial readings.

HOWEVER, this doesn't make as much sense if we're not in free-running mode, i.e. the subprocess has been slaved to explicit control by the Controller (likely a feature object like BatchCollection), and is collecting exactly those measurements we're being commanded, as they're commanded.

THEREFORE, if the driver IS NOT in free-running mode, then we ONLY return the final averaged spectrum as one atomic operation.

In this case, if scan averaging is set to 10, then A SINGLE CALL to this function will "block" while the full 10 measurements are made, and then a single, fully-averaged spectrum will be returned upstream.

Returns
a Reading wrapped in a SpectrometerResponse

◆ acquire_spectrum_auto_raman()

wasatch.WasatchDevice.WasatchDevice.acquire_spectrum_auto_raman ( self)
@returns a Reading wrapped in a SpectrometerResponse
@todo fold-in a lot of the post-reading sensor measurements 
      (temperature, interlock etc) provided by acquire_spectrum_standard

◆ acquire_spectrum_standard()

wasatch.WasatchDevice.WasatchDevice.acquire_spectrum_standard ( self)

◆ balance_acquisition()

wasatch.WasatchDevice.WasatchDevice.balance_acquisition ( self,
device = None,
mode = None,
intensity = 45000,
threshold = 2500,
pixel = None,
max_integration_time_ms = 5000,
max_tries = 20 )

◆ change_setting()

wasatch.WasatchDevice.WasatchDevice.change_setting ( self,
str setting,
Any value,
bool allow_immediate = True )

Processes an incoming (setting, value) pair.

Some settings are processed internally within this function, if the functionality they are controlling is implemented by WasatchDevice. This includes scan averaging, and anything related to scan averaging (such as "take one" behavior).

Most tuples are queued to be sent downstream to the connected hardware (usually FeatureIdentificationDevice) at the start of the next acquisition.

Some hardware settings (those involving triggering or the laser) are sent downstream immediately, rather than waiting for the next "scheduled" settings update.

ENLIGHTEN commands to WasatchDeviceWrapper are sent here by WasatchDeviceWrapper.continuous_poll.

Parameters
setting(Input) which setting to change
value(Input) the new value of the setting (required, but can be None or "anything" for commands like "acquire" which don't use the argument).
allow_immediate

◆ connect()

wasatch.WasatchDevice.WasatchDevice.connect ( self)

Attempt low level connection to the specified DeviceID.

◆ connect_feature_identification()

wasatch.WasatchDevice.WasatchDevice.connect_feature_identification ( self)

Given a specified universal identifier, attempt to connect to the device using FID protocol.

Todo
merge with the hardcoded list in DeviceFinderUSB

◆ disconnect()

wasatch.WasatchDevice.WasatchDevice.disconnect ( self)

◆ handle_requests()

wasatch.WasatchDevice.WasatchDevice.handle_requests ( self,
list[SpectrometerRequest] requests )

◆ initialize_settings()

wasatch.WasatchDevice.WasatchDevice.initialize_settings ( self)

◆ monitor_memory()

wasatch.WasatchDevice.WasatchDevice.monitor_memory ( self)

◆ perform_optional_throwaways()

wasatch.WasatchDevice.WasatchDevice.perform_optional_throwaways ( self)

It's unclear how many throwaways are really needed for a stable Raman spectrum, and whether they're really based on number of integrations (sensor stabilization) or time (laser warmup); I suspect both.

Also note the potential need for sensor warm-up, but I think that's handled inside FW.

Optimal would probably be something like "As many integrations as it takes to span 2sec, but not fewer than two."

These are NOT the same throwaways added to smooth spectra over changes to integration time and gain. These are separate throwaways potentially required when waking the sensor from sleep. However, I'm using the same mechanism for tracking (self.remaining_throwaways) for commonality.

Todo
This shouldn't be required at all if we're in free-running mode, or if it's been less than a second since the last acquisition.
Returns
SpectrometerResponse IFF error occurred (normally None)

◆ process_commands()

wasatch.WasatchDevice.WasatchDevice.process_commands ( self)

Process every entry on the incoming command (settings) queue, writing each to the device.

Essentially this iterates through all the (setting, value) pairs we've received through change_setting() which have not yet been processed, and <– MZ: incomplete sentence

Note that WrapperWorker.run "de-dupes" commands on receipt from ENLIGHTEN, so the command stream arising from that source should already be optimized and minimal. Commands injected manually by calling WasatchDevice.change_setting() do not receive this treatment.

In the normal multithreaded (ENLIGHTEN) workflow, this function is called at the beginning of acquire_data, itself ticked regularly by WrapperWorker.run.

◆ take_one_averaged_reading()

wasatch.WasatchDevice.WasatchDevice.take_one_averaged_reading ( self,
label = None )
Okay, let's talk about averaging.  We only perform averaging as a 
blocking call in Wasatch.PY when given a TakeOneRequest with non-zero 
scans_to_average, typically from ENLIGHTEN's TakeOneFeature (perhaps via
VCRControls.step, possibly with AutoRaman, or BatchCollection).

Otherwise, normally this thread (the background thread owned by a 
WasatchDeviceWrapper object and running WrapperWorker.run) is in "free-
running" mode, taking spectra just as fast as it can in an endless loop,
feeding them back to the consumer (ENLIGHTEN) over a queue. To keep that 
pipeline "moving," generally we don't do heavy blocking operations down 
here in the background thread.

The new AutoRaman feature makes increased using of scan averaging,
and again kind of wants to be encapsulated down here. And by implication,
all TakeOneRequests should really support encapsulated, atomic averaging.
So the current design is that ATOMIC scans_to_average comes from 
TakeOneRequest, ENLIGHTEN-based averaging in SpectrometerState.

@returns Reading on success, true or false on "stop processing" conditions

Member Data Documentation

◆ auto_raman

wasatch.WasatchDevice.WasatchDevice.auto_raman

◆ command_queue

wasatch.WasatchDevice.WasatchDevice.command_queue

◆ connected

wasatch.WasatchDevice.WasatchDevice.connected

◆ device_id

wasatch.WasatchDevice.WasatchDevice.device_id

◆ hardware

wasatch.WasatchDevice.WasatchDevice.hardware

◆ immediate_mode

wasatch.WasatchDevice.WasatchDevice.immediate_mode

◆ last_battery_percentage

wasatch.WasatchDevice.WasatchDevice.last_battery_percentage

◆ last_complete_acquisition

wasatch.WasatchDevice.WasatchDevice.last_complete_acquisition

◆ last_memory_check

wasatch.WasatchDevice.WasatchDevice.last_memory_check

◆ lock

wasatch.WasatchDevice.WasatchDevice.lock

◆ message_queue

wasatch.WasatchDevice.WasatchDevice.message_queue

◆ process_f

wasatch.WasatchDevice.WasatchDevice.process_f

◆ process_id

wasatch.WasatchDevice.WasatchDevice.process_id

◆ session_reading_count

wasatch.WasatchDevice.WasatchDevice.session_reading_count

◆ settings

wasatch.WasatchDevice.WasatchDevice.settings

◆ sum_count

wasatch.WasatchDevice.WasatchDevice.sum_count

Aggregate scan averaging.

◆ summed_spectra

wasatch.WasatchDevice.WasatchDevice.summed_spectra

◆ take_one_request

wasatch.WasatchDevice.WasatchDevice.take_one_request

The documentation for this class was generated from the following file: