MasterScan  Lab_Matlab_control Master Branch
List of all members | Properties and Events | Protected Properties | Methods | Protected Methods | Static Methods
dotsReadable Class Reference

Overview

Superclass for objects that read data.

The dotsReadable superclass provides a uniform way to read data, such as data from a gamepad or eyetracker. It imposes a format for data and provides utilities for previewing data and for defining, detecting and enqueing events of interest.

dotsReadable itself is not a usable class. Rather, it provides a uniform interface and core functionality for subclasses. Subclasses must redefine the following methods in order to read actual data:

startRecording()

openComponents()

These methods are invoked internally. They encapsulate the details of how to read from any particular device. See the documentation for each of these methods for more information about how subclasses should redefine them.

Users should expect to call public methods like initialize(), preview(), and read(), which are the same for all subclasses.

dotsReadable() assumes that each input source or device has one or more components. Each component must be assigned a small, positive, unique, integer ID. This ID is used in many methods and properties to identify the component. A component might be an individual button on a game pad, or a data channel from an eye tracker.

For most properties and methods, data are formatted as matrix rows. Each row represents one measurement. Each row has three columns: [ID, value, time]. The ID is the ID of a device component. The value is any observed value. The time is a timestamp associated with the value.

Several properties use component ID as indexes. For example, the state property has one row for each component. If for some reason component IDs are non-sequential, the state property may have gaps between useful rows. This is expected. Using IDs as indices takes advantage of Matlab's array facility to provide quick, concise assignment and lookup of data.

dotsReadable provides utilities for defining, detecting, and enqueueing events of interest. Each component may define one event of interest at a time. An event can be defined for one of four possibilities:

Once defined, events are detected automatically during read() and can be read out sequentially from getNextEvent(). Event dectection relies heavily on the dotsReadable data format and ID indexes.

Inheritance diagram for dotsReadable:
Inheritance graph
[legend]

Properties and Events

Property isAvailable = false
 

whether or not the object is ready to read() from


 
Property components
 

struct array with details about each component


 
Property state
 

matrix of ID, latest value, and latest time indexed by ID


 
Property history
 

matrix of component ID, value, and time from previous read()


 
Property isAutoRead = true
 

whether or not to to invoke read() during getValue(), etc.


 
Property eventDefinitions
 

struct array defining events of interest, indexed by ID


 
Property initialEventQueueSize = 100
 

initial size of queue for events of interest


 
Property clockFunction
 

any function that returns the current time as a number


 
Property filename
 

name of the data file for devices that store their own data


 
Property filepath
 

where the file is


 
Property recordDuringCalibration = true
 

controls whether or not to stop recording during calibration


 
Property useGUI = false
 Flag to use GUI for feedback, etc.
 
Property useExistingCalibration = false
 Flag to skip calibration routine.
 
Property calibrationUI
 Possibly use a keyboard or other UI to help with calibration.
 
Property deactivateEventsAtStartTrial =false
 Flag to deactivate all events at the beginning of each trial.
 

Protected Properties

Property eventQueue
 

array of queued events (row indices into history)


 
Property queueNext
 

queue index of the next event to be dequeued


 
Property queueLast =0
 

queue index of the last event enqueued


 
Property isRecording =false
 

keep track of whether device is currenly writing to a data file


 
Property didCalibrate = true
 Keep track of whether calibration occurs.
 
Property defaultEventPrefix = 'event'
 Default prefix for event names: <prefix>_<componentName>
 
Property eventSets
 Strutures with different named event definitions, in case we want to quickly swap between them.
 

Methods

self dotsReadable ()
 

Constructor takes no arguments.


 
 initialize (self)
 

Locate, acquire, configure, etc. device and component resources.


 
 calibrate (self, varargin)
 

Calibrate the device

More...
 
 record (self, onFlag, filename)
 

Open/close data file associated with the device Arguments: onFlag ...

More...
 
 reset (self, varargin)
 reset device More...
 
 close (self)
 

Release any resources acquired by initialize().


 
 delete (self)
 

Automatically close when Matlab is done with this object.


 
 read (self)
 

Add incoming data to history and detect events of interest.

More...
 
 flushData (self, waitForNoEvents)
 

Delete historical data and reset the current state.

More...
 
 logData (self)
 

Record current and historical data in topsDataLog.

More...
 
stateAtTime getState (self, time)
 

Get the state of device components as of the given time.

More...
 
value data getValue (self, ID)
 

Get the latest value for the given component.

More...
 
event defineEvent (self, name, varargin)
 

Define the event of interest for one of the input components.

More...
 
 defineEventsFromComponents (self, names, varargin)
 defineEventsFromComponents More...
 
 defineEventsFromStruct (self, eventStruct, setName, keepExisting, inactivate)
 defineEventsFromStruct More...
 
 showActiveEvents (self)
 Mostly for debugging.
 
 activateEventSet (self, name)
 Swap in a set of events.
 
 activateEvents (self)
 Activate all events. More...
 
 deactivateEvents (self)
 Deactivate all events. More...
 
activeFlags getActiveFlags (self)
 Get all active flags.
 
 setActiveFlags (self, activeFlags)
 Set all active flags from array.
 
 setEventsActiveFlag (self, activateList, deactivateList)
 Set/unset activeFlag. More...
 
name data getNextEvent (self, isPeek, acceptedEvents)
 

Get the next event that was detected in read().

More...
 
lastName lastID names IDs getHappeningEvent (self, time)
 

Get events that are happening at the current time.

More...
 
name waitTime data waitForEvents (self, eventNames, maxWait)
 Wait for event(s)
 
nEvents getNumberOfEvents (self)
 

Get the number of events in eventQueue.

More...
 
IDs getComponentIDs (self)
 

Get an array of unique integer component IDs.

More...
 
ID getComponentID (self, nameOrID)
 

Get ID of component by name or ID


 
name getComponentName (self, nameOrID)
 

Get name of component by name or ID


 
indices getComponentIndicesByID (self, IDs)
 

Get array of indices for the given component IDs


 
indices getComponentIndicesByName (self, names)
 

Get array of indices for the given component names


 
time getDeviceTime (self)
 

Get the current time from clockFunction.


 
 setDeviceTime (self, val)
 

Set the device time


 
 startTrial (self, varargin)
 

startTrial()

More...
 
 finishTrial (self, varargin)
 

finishTrial()

More...
 
 plotData (self)
 

Open a figure with continuously read device data.

More...
 
 startTrialDevice (self, varargin)
 Overloaded methods.
 

Protected Methods

isOpen openDevice (self)
 

Locate and acquire input device resources (for subclasses).

More...
 
 closeDevice (self)
 

Release input device resources (for subclasses).

More...
 
 resetDevice (self, varargin)
 Reset the device.
 
status calibrateDevice (self, varargin)
 

Calibrate the device (for subclasses).

More...
 
isRecording startRecording (self)
 

Turn on data recording from the device (for subclasses).


 
isRecording stopRecording (self)
 

Turn off data recording from the device (for subclasses).


 
components openComponents (self)
 

Locate and acquire device components (for subclasses).

More...
 
 closeComponents (self)
 

Release device components (for subclasses).

More...
 
newData readNewData (self)
 

Read and format incoming data (for subclasses).

More...
 
isEvent detectEvents (self, data)
 

Use new data to look up events of interest (used internally).

More...
 
newSize resizeEventQueue (self, minSize, doClear)
 

Resize and optionally clear the event queue (used internally).

More...
 
nEvents enqueueEvents (self, eventValues)
 

Add events of interest to the event queue (used internally).

More...
 
eventValue nEvents dequeueEvent (self, isPeek)
 

Remove the next queued event of interest (used internally).

More...
 

Static Methods

static isHappening data readable isEventHappening (readables, eventName)
 

Is the named event happening now?

More...
 
static didHappen waitTime data readable name waitForEvent (readables, eventName, maxWait)
 

Wait for the named event to happen.

More...
 
static data loadDataFile (filename, varargin)
 Load data from file. More...
 

Methods

◆ calibrate()

calibrate ( self  ,
varargin   
)

Calibrate the device

calibrateDevice is device specific and should return 0 if successful, otherwise an error

◆ record()

record ( self  ,
onFlag  ,
filename   
)

Open/close data file associated with the device Arguments: onFlag ...

true to turn on (default), false to turn off filename ... string name of the file

◆ reset()

reset ( self  ,
varargin   
)

reset device

subclass-specific methods

◆ read()

read ( self  )

Add incoming data to history and detect events of interest.

read() updates device resources and components as defined by subclasses in readNewData(). It uses any new data to detect events of interest and enqueues any events in eventQueue. It appends any new data to history and updates the component summary in state.

read() should be called in order to get the latest device data. It may make sense to call read() periodically, or to call read() immediately before accessing history or state, or invoking getState(), getValue(), or getNextEvent().

◆ flushData()

flushData ( self  ,
waitForNoEvents   
)

Delete historical data and reset the current state.

flushData() flush data deletes any data previously read. This includes the object's state, history, and eventQueue.

◆ logData()

logData ( self  )

Record current and historical data in topsDataLog.

logData() saves all properties of a dotsReadable object as a struct in topsDataLog, using the class's name as the data group name.

◆ getState()

stateAtTime getState ( self  ,
time   
)

Get the state of device components as of the given time.

Parameters
timea time in the past to consider instead of the current time

getState() summarizes the latest data for each device component. getState() returns a nx3 matrix where each row has the form [ID, value, time]. Each ID identifies a device component. Rows of the matrix are indexed by ID values. Each value is the latest value that was read at each component. Each time is the time when the corresponding value was read.

By default, getState() returns the latest data. If time is provided, components are summarized as of the given time and data read after the given time are ignored.

If isAutoRead is set to true, invokes read() to update component data before summarizing.

◆ getValue()

value data getValue ( self  ,
ID   
)

Get the latest value for the given component.

Parameters
IDone of the integer IDs in components

Returns the latest value that was read for the component identified by ID. Also returns as a second argument a data row of the form [ID, value, time], where the time is the time associated with the latest value.

If isAutoRead is set to true, invokes read() to update component data before accessing values.

◆ defineEvent()

event defineEvent ( self  ,
name  ,
varargin   
)

Define the event of interest for one of the input components.

Required input:

name ... string name for an event of interest

Optional property/value pairs:

'component' ... string name or one of the integer IDs in components 'isActive' ... whether event is current active 'isInverted' ... whether to invert event detection logic 'lowValue' ... the lower bound on the event of interest 'highValue' ... the upper bound on the event of interest 'isRelease' ... event on release of component

defineEvent() sets parameters for detecting events of interest as the value of a component changes. ID specifies which component. Each component may define only one event of interest at a time, so repeated calls to defineEvent() with the same ID will replace previous event definitions.

name is an arbitrary string identifying the event of interest. lowValue and highValue define the boundaries of the event of interest. When the value of the component falls between lowValue and highValue, an event of interest occurs. If isInverted is provided and equal to true, the definition of the event will be inverted. The event will occur when the value of the component moves outside of lowValue and highValue.

Events of interest are detected during read(), as new data arrive. When events of interest are detected they are added to eventQueue. Events can be read out one at a time later, with getNextEvent().

Event does not use any timing information, so techniques like edge detection are not possible. As a consequence, the number of events that occur may depend on the sampling frequency or noisiness of input sources. To avoid redundant event detection, readNewData() may be implemented so as to smooth data, or the report data only when the value of a component changes.

Can be overloaded in subclasses

◆ defineEventsFromComponents()

defineEventsFromComponents ( self  ,
names  ,
varargin   
)

defineEventsFromComponents

Automatically define default events associated with all of the components (or from the list of names) Arguments: names ... optional cell array of string names of components to use varargin ... optional property/value pairs sent to defineEvent

◆ defineEventsFromStruct()

defineEventsFromStruct ( self  ,
eventStruct  ,
setName  ,
keepExisting  ,
inactivate   
)

defineEventsFromStruct

Takes a structure with information about events and calls defineEvent for each event. Arguments: eventStruct ... array of structs, one per event, with fields corresponding to properties defined in defineEvents (which may be overridden in subclasses). The only required field is 'name' (first argument to defineEvent), all others are optional paired arguments. setName ... string name to use to save this set of event definitions keepExisting ... string to keep existing definitions (default false) startInactive ... flag for initial isActive flag (default false)

◆ activateEvents()

activateEvents ( self  )

Activate all events.

To do this separately for each event, call defineEvent and set isActive flag to true

◆ deactivateEvents()

deactivateEvents ( self  )

Deactivate all events.

To do this separately for each event, call defineEvent and set isActive flag to true

◆ setEventsActiveFlag()

setEventsActiveFlag ( self  ,
activateList  ,
deactivateList   
)

Set/unset activeFlag.

NOTE: if anything changes here, be careful to update activateEvents and deactivateEvents, above, as appropriate Input lists are either string name of event, or cell array of string names of events

◆ getNextEvent()

name data getNextEvent ( self  ,
isPeek  ,
acceptedEvents   
)

Get the next event that was detected in read().

Parameters
isPeekwhether to leave the next event in the queue

getNextEvent() returns the name of the the next queued event of interest. The name corresponds to one of the name values in eventDefinitions. Also returns as second output the data which caused the event of interest. The data corresponds to one of the rows of history. Thus, the data has the form [ID, value, time].

Additional information about the event can be found in eventDefinitions(ID). Additional information about the component which caused the event can be found in components.

By default, the next event is read out of the queue and removed. If isPeek is provided and true, the event is read out but left in the queue to be read again.

If isAutoRead is set to true, invokes read() to update component data before getting the next event. jig added cell array of strings acceptedEvents to list names of events that can be used

◆ getHappeningEvent()

lastName lastID names IDs getHappeningEvent ( self  ,
time   
)

Get events that are happening at the current time.

Parameters
timea time in the past to consider instead of the current time.

getHappeningEvent() summarizes events that are still happening, at the given time. If time is omitted, defaults to the current time. This contrasts with getNextEvent(), which recalls events that happened in the past. getHappeningEvent() does not affect the behavior of getNextEvent() or the values in eventQueue.

If no events are happening at the given time, returns ''. If one or more events is happening, returns the name of the last event that happened. Also returns as a second output the component ID for the last event.

Also returns as a third output a cell array of names of all the events that are happening. Also returns as a fourth output an array of component IDs for all the events that are happening.

◆ getNumberOfEvents()

nEvents getNumberOfEvents ( self  )

Get the number of events in eventQueue.

Returns the number of events which are currently enqueued in eventQueue.

◆ getComponentIDs()

IDs getComponentIDs ( self  )

Get an array of unique integer component IDs.

Returns an array of component IDs, which are unique, small, positive integers which identify device components.

◆ startTrial()

startTrial ( self  ,
varargin   
)

startTrial()

In case you need to turn on/off recording at the beginning of each trial (e.g., dotsReadableEyeEOG, using the PMD1208FS device)

◆ finishTrial()

finishTrial ( self  ,
varargin   
)

finishTrial()

In case you need to turn on/off recording at the beginning of each trial (e.g., dotsReadableEyeEOG, using the PMD1208FS device)

◆ plotData()

plotData ( self  )

Open a figure with continuously read device data.

Opens a new figure and plots component and event data. Continuously invokes read() and updates the plot as long as the figure is open.

◆ openDevice()

isOpen openDevice ( self  )
protected

Locate and acquire input device resources (for subclasses).

Subclasses must redefine openDevice(). They should expect openDevice() to be called during initialize() and when an object is constructed. openDevice() should locate, acquire, configure, etc. major device resources required for reading data. Specific resources relating to device components, like individual buttons of a gamepad, should be handled in openComponents().

openDevice() should return true if resources were successfully acquired and individual components are ready to be opened. Otherwise, openDevice() should return false.

◆ closeDevice()

closeDevice ( self  )
protected

Release input device resources (for subclasses).

Subclasses must redefine closedevice(). Any resources that were acquired by openDevice() should be released. It should be safe to call closeDevice() multiple times in a row.

◆ calibrateDevice()

status calibrateDevice ( self  ,
varargin   
)
protected

Calibrate the device (for subclasses).

Subclasses must redefine calibrateDevice(). It should be safe to call calibrateDevice() multiple times in a row.

◆ openComponents()

components openComponents ( self  )
protected

Locate and acquire device components (for subclasses).

Subclasses must redefine openComponents(). They should expect openComponents() to be called immediately after a successful call to openDevice(). Assuming the device was opened successfully, openComponents() should identify, acquire, configure, etc. specific components of interest, such as individual buttons on a gamepad.

openComponents() must assign a name and a unique ID to each component. Each name should be a short, human-readable string. Each ID should be a unique, small, greater-than-0 integer.

openComponents() must return names and IDs as a struct array with fields ID and name. The struct array should have one element per component. Subclasses may add additional fields to the components struct array, but ID and name are mandatory.

◆ closeComponents()

closeComponents ( self  )
protected

Release device components (for subclasses).

Subclasses must redefine closeComponents(). Any resources that were acquired by openComponents() should be released. It should be safe to call closeComponentes() multiple times in a row.

◆ readNewData()

newData readNewData ( self  )
protected

Read and format incoming data (for subclasses).

Subclasses must redefine readNewData() to update input devices, read from device components, and put data in the expected format.

readNewData() must return an nx3 matrix of data with rows of the form [ID, value, time]. Each ID must match one of the values in components.ID. Each value should be a new value that was read from the component. Each time should be a timestamp asociated with that value. Only new data, which has not yet been read, should be returned from readNewData().

◆ detectEvents()

isEvent detectEvents ( self  ,
data   
)
protected

Use new data to look up events of interest (used internally).

Parameters
datanx3 matrix of component data

Expects rows of data to have the form [ID, value, time]. Uses ID values to look up parameters in eventDefinitions, and performs logical comparisons to determine which rows of data qualify as events of interest.

Returns a logical array with one element per row of data. Where the array is true, the corresponding row of data qualifies as an event of interest. If data is empty, returns [].

◆ resizeEventQueue()

newSize resizeEventQueue ( self  ,
minSize  ,
doClear   
)
protected

Resize and optionally clear the event queue (used internally).

Parameters
minSizethe new minimum size for eventQueue
doClearwhether or not to delete previously queued events

Changes the size of eventQueue to agree with the given minSize. If minSize is smaller than the number of events currently in eventQueue, the size of the queue remains unchanged.

If doClear is true, deletes any previously queued events. This is a way to initialize eventQueue. If doClear is false, packs any queued events into the beginning of eventQueue. Events are re-packed regardless of minSize.

Returns the new size of eventQueue, which is at least minSize.

◆ enqueueEvents()

nEvents enqueueEvents ( self  ,
eventValues   
)
protected

Add events of interest to the event queue (used internally).

Parameters
eventValuesarray of values to add to eventQueue

Adds one or more new eventValues to eventQueue and does queue accounting. Returns the new total number of events in eventQueue.

◆ dequeueEvent()

eventValue nEvents dequeueEvent ( self  ,
isPeek   
)
protected

Remove the next queued event of interest (used internally).

Parameters
isPeekwhether to leave the next event in the queue

Gets the next event from eventQueue and does queue accounting. If isPeek is provided and equal to true, leaves the event in the queue to be read again. Otherwise, removes the event.

Returns the next value queued in eventQueue. If there are no queued values, returns []. Returns as a second argument the new total number og events in eventQueue.

◆ isEventHappening()

static isHappening data readable isEventHappening ( readables  ,
eventName   
)
static

Is the named event happening now?

Parameters
readablesarray or cell array of dotsReadable objects
eventNamename of an event defined by readables

Checks whether any of the given readables currently has an event happening with the given eventName. Does not invoke read() for any readable.

Returns true if any of given readables has eventName happening. Returns as a second output the data associated with the event. The data has the form [ID, value, time]. Returns as a third output the readable which has eventName happening. If more than one of the given readables has eventName happening, only returns the first readable.

◆ waitForEvent()

static didHappen waitTime data readable name waitForEvent ( readables  ,
eventName  ,
maxWait   
)
static

Wait for the named event to happen.

Parameters
readablesarray or cell array of dotsReadable objects
eventNamename of an event defined by readables
maxWaitmaximum time to wait for eventName

Waits for one of of the given readables to report that the given eventName happened. maxWait specifies how long to wait before giving up. Uses getDeviceTime() of the first readable to keep track of time. Invokes read() and checks each readable for events at least once, even if maxWait is zero or negative.

Returns true if any of given readables reports that eventName happened before maxWait. Returns as a second output the amount of time waited. Returns as a third output the data associated with the event. The data has the form [ID, value, time]. Returns as a fourth output the readable which reported eventName. If more than one of the given readables reports eventName, only returns the first readable.

◆ loadDataFile()

static data loadDataFile ( filename  ,
varargin   
)
static

Load data from file.

Arguments: filename ... string name varargin ... (optional) flag to check for synch/calibration data in dataLog


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