Basic Demos ========================= Our examples will showcase how easy it is to use a VPixx device with our package. .. Tip:: We will be using an object-oriented approach to use VPixx devices. If you are more comfortable programming using a more imperative/functional way but you still want to use Python, you can use the :doc:`libdpx` module, which is a simple wrapper for our ANSI C SDK. Example 1 - Setting up a device in High-bit depth grey-scale mode. ------------------------------------------------------------------------------------------------------------------------------ You must first consider which device you have. In this example we will use a VIEWPixx3D. .. code-block:: python :linenos: from pypixxlib.viewpixx import VIEWPixx3D # viewpixx and VIEWPixx3D would need to be replaced by the appropriate devices. my_device = VIEWPixx3D() # Opens and initiates the device my_device.setVideoMode('M16') # Set the right video mode my_device.updateRegisterCache() # Update the device Example 2 - Setting up a PROPixx to display in 480 Hz. ----------------------------------------------------------------------------------------------------------------------------- This example is only meant for the PROPixx as it is the only device able to display stimuli at 480 Hz. To do so, we limit our resolution to 1/4 of the screen to display 4 times faster. Indeed, your stimulus needs to be created as follow: +-------------------+-------------------+ | Quadrant 1 | Quadrant 2 | +-------------------+-------------------+ | Quadrant 3 | Quadrant 4 | +-------------------+-------------------+ One frame at 120 Hz will represent 4 frames at 480 Hz on the PROPixx, and each of those 4 frames must be put in order in the quadrants 1, 2, 3 and 4. .. code-block:: python :linenos: from pypixxlib.propixx import PROPixx my_device = PROPixx() my_device.setDlpSequencerProgram('QUAD4X') my_device.updateRegisterCache() # You can now send you stimulus at 120 Hz to be displayed at 480 Hz! Example 3 - Setting up a PROPixx to display in 1440 Hz. --------------------------------------------------------------------------------------------------------------------------- 1440 Hz is very similar to 480 Hz in the set-up process. To get 1440 Hz, we use the fact that every quadrants defined above has three channels of information (RGB). Quadrant 1's red information will define the first frame we display at 1440 Hz, Quadrant 2's red will be the 2nd, and after red we use green information, then blue. In other words: Q1R, Q2R, Q3R, Q4R, Q1G, Q2G, Q3G, Q4G, Q1B, Q2B, Q3B, Q4B. This allows us to have 12 high speed frames every normal speed frame, giving 1440 Hz. .. code-block:: python :linenos: from pypixxlib.propixx import PROPixx my_device = PROPixx() my_device.setDlpSequencerProgram('QUAD12X') my_device.updateRegisterCache() # You can now send you stimulus at 120 Hz to be displayed at 1440 Hz! Example 4 - Setting up a PROPixx for a 3D experiment. ------------------------------------------------------------------------------------------------------------------------------------------------------------------ In this example, we will set up the PROPixx for rear projection, ceiling mode and use of a polariser. We will also set the PROPixx so that it keeps this configuration after a power down. We will also have the PROPixx Controller send out audio stimuli. There exists four ways to set up the polariser, depending on what you wish to achieve. 1. If the video source is set to ``SWTP3D``: ``my_device.setVideoSource('SWTP3D')`` 2. If you are using Blue Lines to sync your 3D stimulus: ``my_device.setVideoBlueLine(True)`` 3. If you are using the red and blue 3D sequencer mode: ``my_device.setDlpSequencerProgram('RB3D')`` 4. You can manually activate the polariser,(this is called VESA Free Run mode): ``my_device.setVesaFreeRun(True)`` .. code-block:: python :linenos: from pypixxlib.propixx import PROPixx, PROPixxCTRL from pypixxlib._libdpx import DPxSelectDevice my_device = PROPixx() my_device_controller = PROPixxCTRL() my_device.setRearProjectionMode(True)# Sets the projector to read-projection mode. my_device.setCeilingMountMode(True) # Sets the projector to ceiling-mount mode. my_device.setVesaFreeRun(True) # Sets the VESA port to work with the polariser. my_device.updateRegisterCache() # Update the new modes to the device. my_device.setCustomStartupConfig() # The projector will remember this configuration. # The audio is done on the controller, so the next functions use the controller object. my_device_controller.audio.initializeCodec() # Configures initial CODEC state. my_device_controller.audio.setLeftRightMode('mono') # Set which mode the audio will be output. my_device_controller.audio.setAudioBuffer(0, 64) # Set the audio to start at address 0, and size 64. # Now we must create the audio stimulus. # This is done by simply filling a list with a sound wave. audio_stim = [] import math for i in range(32): audio_stim.append(int(32767 * math.sin(2.0 * math.pi * i / 32.0))) my_device_controller.writeRam(0, audio_stim) # Write the audio stimulus in the ram. my_device_controller.audio.setVolume(0.25) my_device_controller.updateRegisterCache() # Send everything to the device. # We must at this point create the audio schedule # The first parameter is the schedule onset, which we set to 0, # meaning that the first schedule tick will occur immediately once the schedule starts. # The second and third parameters indicate that the audio samples will be played at 40 kHz. # The forth parameter is a schedule counter, indicating the number of ticks # that the schedule should run before stopping. # We'll run it for 16000 samples, which will take 16000/40000 = 400 ms. my_device_controller.audio.setAudioSchedule(0, 40000, 'hz', 16000) my_device_controller.audio.startScheduleLeft() my_device_controller.updateRegisterCache() # Close the devices my_device.close() my_device_controller.close() Example 5 - Changing the back-light intensity on a VIEWPixx -------------------------------------------------------------------------------------------------------------------------- Our VIEWPixx offer a customizable back-light level, should you wish to work with specific luminance values. .. code-block:: python :linenos: from pypixxlib.viewpixx import VIEWPixxEEG my_device = VIEWPixxEEG() # Create an instance of your device. my_device.setBacklightIntensity(35) # Value between 0-255 for the intensity. my_device.updateRegisterCache() # Send the value to the device. my_device.getBacklightIntensity() # Double check our value was sent and applied 35 Example 6 - Recording changes in digital-in ---------------------------------------------------------------------------------------------------------------------------- If you are running an experiment that sends triggers over a DB-25 cable, it is possible to record those changes with a DATAPixx. .. code-block:: python :linenos: from pypixxlib.datapixx import DATAPixx my_device = DATAPixx() din_state = my_device.din.getValue() # Start your experiment experiement_is_running = True while experiement_is_running: old_state = din_state my_device.updateRegisterCache() din_state = my_device.din.getValue() if old_state is not din_state: # Something triggered. # Now we want to check, for example, if pin 6 triggered. if (old_state & 2**6) is not (din_state & 2**6): print 'Pin 6 triggered!' experiement_is_running = False else: print 'Pin 6 is in the same state as before' # Finish your experiment Example 7 - How to verify the chromacity and luminance of the colors of your device using i1Device ------------------------------------------------------------------------------------------------------------------------------------ Most of our devices come calibrated as D65, but if you want to verify the calibration or get a specific value for a colour/brightness, you can use the i1Display and i1Pro modules. .. code-block:: python :linenos: from pypixxlib.i1 import I1Display # We will use an i1Display here # Initialize the device. my_device = I1Display() my_device.setCurrentCalibration('RGB LED') # We will be using a device with RGB LEDs print 'Current calibration is: ', my_device.getCurrentCalibration() # Verify we have the right calibration # Set the color/intensity you wish to measure my_device.runMeasurement() print 'next acquisition' # Change to the next color/intensity my_device.runMeasurement() print 'next acquisition' # Change to the next color/intensity my_device.runMeasurement() results = my_device.getAllMeasurement() # Get a list of all measurements for i in range(len(results)): print results[i] # Print the different measurements my_device.printLatestMeasurement() # If you want to print your latest measurement my_device.close() # Close the device. Example 8 - How to read button presses from a RESPONSEPixx ------------------------------------------------------------------------------------------------------------------------------------ Pypixxlib supports two ways of interacting with VPixx hardware. First, you can create device objects and call their functions in an object-oriented style, as the previous demos have shown. You can also use the libdpx wrapper to program sequentially as you would in other programs like MATLAB. Example 8 shows how the two methods can be used to read and report button presses using the RESPONSEPixx and the digital input log. First, here is the object-oriented approach: .. code-block:: python :linenos: from pypixxlib.datapixx import DATAPixx3 from psychopy import core #connect to VPixx device device = DATAPixx3() #First, let's make a dictionary of codes that correspond to our buttons. This is in decimal. #Note 1: these codes ARE NOT UNIVERSAL. You can check what your own button codes are using the PyPixx Digital I/O demo #Note 2: these codes are for single button presses only. If two buttons are pressed at the same time this will generate a unique code, which we will ignore buttonCodes = {65527:'blue', 65533:'yellow', 65534:'red', 65531:'green', 65519:'white', 65535:'button release'} exitButton = 'white' myLog = device.din.setDinLog(12e6, 1000) device.din.startDinLog() device.updateRegisterCache() startTime = device.getTime() finished = False #let's create a loop which checks the schedule at 0.25 s intervals for button presses. #Any time a button press is found, we print the timestamp and button pressed. #If a designated exit button is pressed, we disconnect. while finished == False: #read device status device.updateRegisterCache() device.din.getDinLogStatus(myLog) newEvents = myLog["newLogFrames"] if newEvents > 0: eventList = device.din.readDinLog(myLog, newEvents) for x in eventList: if x[1] in buttonCodes: #look up the name of the button buttonID = buttonCodes[x[1]] #get the time of the press, since we started logging time = round(x[0] - startTime, 2) printStr = 'Button pressed! Button code: ' + str(x[1]) + ', Button ID: ' + buttonID + ', Time:' + str(time) print(printStr) if buttonID == exitButton: finished = True core.wait(0.25) #Stop logging device.din.stopDinLog() device.updateRegisterCache() And second, the libdpx version: .. code-block:: python :linenos: from pypixxlib._libdpx import DPxOpen, DPxClose, DPxWriteRegCache, DPxUpdateRegCache, DPxGetTime, DPxStopDinLog from pypixxlib._libdpx import DPxSetDinLog, DPxStartDinLog, DPxGetDinStatus, DPxReadDinLog, DPxEnableDinDebounce from psychopy import core #Connect to VPixx device DPxOpen() #First, let's make a dictionary of codes that correspond to our buttons. This is in decimal (base 10). #Note 1: these codes ARE NOT UNIVERSAL. You can check your own button codes by modifying this script to print all event codes, and testing each button #Note 2: these codes are for single button presses only. If two buttons are pressed at the same time this will generate a unique code, which we will ignore buttonCodes = {65527:'blue', 65533:'yellow', 65534:'red', 65531:'green', 65519:'white', 65535:'button release'} #Let's enable a digital input log on our device, at buffer address 12e6, with size 1000 #This log ONLY marks rising and falling voltages on the digital input, and when they occur. #This means it will give us both button press and button release times. logStatus = DPxSetDinLog(0,1000) #Let's also enable debounce to avoid noise DPxEnableDinDebounce() #This is our start command, but it won't take effect until it is passed to the device register DPxStartDinLog() #Let's push these commands to the device register, and record the time this occurred DPxUpdateRegCache() startTime = DPxGetTime() #Let's create a loop which checks the log for button presses every 0.25 seconds. #Any time a button press or release is logged, we print the timestamp and details. #If our designated exit button is pressed, we stop logging. exitButton = 'white' finished = False; while finished == False: #read device status DPxUpdateRegCache() #check log status and see if there are new log frames since previous read DPxGetDinStatus(logStatus) newData = logStatus['newLogFrames'] #if new log entries if newData > 0: #read all new events in log. The log is an m x 2 array of timetags and event codes log = DPxReadDinLog(logStatus, int(newData)) #check new events to see if they are our button presses/release for x in log: if x[1] in buttonCodes: #look up the name of the button buttonID = buttonCodes.get(x[1]) #get the time of the press, since we started logging time = round(x[0] - startTime, 2) #print a message to the display printStr = 'Button pressed! Button code: ' + str(x[1]) + ', Button ID: ' + buttonID + ', Time:' + str(time) print(printStr) #check if we should stop logging if buttonID == exitButton: finished = True #wait 0.25 seconds before next read of log core.wait(0.25) DPxStopDinLog() #disconnect from device print('All done! Shutting down') DPxClose() These basic demos should help you use your VPixx device. All possible functions are documented, and every module defines what it has access to. If you have any question or run into any problems, please do not hesitate to contact us.