Saffman Lab experiment controller. Written by Martin Lichtman
It is highly recommended that you use a pip-compatible environment manager to handle your dependency installation. Our recommendation is virtualenv with either virtualenvwrapper or virtualenvwrapper-win depending on your OS.
Almost everything can be installed with:
$ pip install -r requirements.txt
This gives us most of our python dependencies. Some additional dependencies may exist on a per-experiment basis if hardware that your experiment uses requires dlls or other external code. One additional requirement we all need but unfortunately cannot pip install is PyQT4. Instead, you can find a windows wheel for PyQt4 at the below link. The filename of the wheel you want is most likely PyQt4‑4.11.4‑cp27‑cp27m‑win_amd64.whl. Download the wheel and pip install it in your virtual environment.
Some parameters need to be specified before the controller is started, sich as DLL paths and python modules not installed globally. Additionally there are experiment specific parameters that rarely or never change. These are all good candidates for entries in a config file. Basically if you ever thought hey I wish X experiment would stop overwriting my Y whenever they makes changes, Y should be moved to the config file.
To prevent everyone form just overwriting each others config files perpetuating the cycle, everyone makes their own config file with a descriptive name such as config_FNODE.cfg
or config_AQUA.cfg
.
You then, on your Windows machine, run cmd.exe as administrator, navigate to the config folder for the controller and run the following code:
mklink config.cfg config_<EXPERIMENT TAG>.cfg
which makes a symbolic (soft) link to your actual config_<EXPERIMENT TAG>.cfg
file whenever the experiment looks for config.cfg
and no one has to yell at anyone else anymore.
On a linux machine run:
ln -s config_<EXPERIMENT TAG>.cfg config.cfg
The configuration file is stored in the settings and data files as a JSON string. In the event that the configuration file differs from the saved JSON configuration in the settings, the user will be prompted at startup to choose which version they want to use.
Threaded analyses are now built into the CsPyController, but analyses are not threaded by default since I do not have the ability to test everyone's analyses.
In order to enable threading for your analysis you need to add some code to the __init__
class method for your analysis.
To see how this works let's say we have two analyses Analysis1
and Analysis2
, and Analysis2
depends on the results of Analysis1
.
Analysis1
only depends on instrument data, and no other analysis.
The contents of the __init__
method for Analysis1
would look like this:
def __init__(self, experiment, desc=None):
super(Analysis1, self).__init__('Analysis1', experiment, 'description of Analysis1')
# initialize Analysis1 here
self.queueAfterMeasurement = True # enable threading for analysis
Analysis2
is then:
def __init__(self, experiment, desc=None):
super(Analysis2, self).__init__('Analysis2', experiment, 'description of Analysis2')
# initialize Analysis2 here
self.queueAfterMeasurement = True # enable threading for analysis
self.measurementDependencies += [self.experiment.Analysis1Obj]
Note that self.experiment.Analysis1Obj
refers to the instantiation of the Analysis1
class named Analysis1Obj
in the main aqua.py
file.
The high-speed digital I/O (NI PXIe-6545) instrument can be set up via the python controller entirely.
On the computer running the labview server:
On the computer running the python controller:
The functional waveforms module may throw an error ("Exception in HSDIO: index 2 is out of bounds for axis 0 with size 2") if there is a channel in the HSDIO or Analog Out waveforms that has one or fewer defined intervals. This may also appear as an exception in functional_waveforms_graph.draw_digital(). As a workaround, I've added the following to the init function in our functional waveforms file (it adds a 100 microsecond 'off' period to the beginning of the sequence to ensure that all channels have at least two defined values):
def initAll(t=0):
for chan in range(NUM_HSDIO_CHANNELS):
HSDIO(0, chan, False)
HSDIO(0.1, chan, False)
for chan in range(NUM_ANALOG_CHANNELS):
AO_Set(0, chan, 0)
AO_Set(0.1, chan, 0)
t += 0.1
For interfacing with the origin data server.
You can specify Origin behavior by modifying the below lines in your config file. As of the time of writing, all of the experiments use the same Origin configurations. If you need different behavior, simply make new Origin config files for yourself and adjust your experiment config file to match.
[ORIGIN]
OriginTest = False ; if true communciate with a local origin server
OriginCfgPath = config/origin_config
The module works by automagically generating a list of per-measurement and per-iteration datasets after and experiment has been run. You should not attempt to populate datasets you want to log, instead first run an experiment where the variable or measurement you want to record is setup to be saved to the hdf5 file. The origin interface palette should then be populated with all the datasets you can track. You may need to close and reopen the palette to shows changes.
Once you have populated the lists of variables, then fill in the "namespace" for your experiment. The namespace will keep you from overwritting someone elses data, the namespace should be short and I suggest a format of the form:
FNODE_, RB_, AQUA_, etc.
You will not be able to record data without a namespace or a stream name and any stream you enable will be automatically disabled in the palette when running an experiment, if you fail to comply.
Now find the variable you want to record in the list of variables, give it a name (remember the namespace will be prepended to the stream name). Verify that the data type is correct (numpy datatypes are used), the most common time it wont be is if an integer is detected but the value will sometimes be a float. If this is the case change the int32 to a float32, or whatever is appropriate from the numpy datatypes. Finally, click the stream checkbox and verify that the enable box is checked at the top. If you are testing with a local server, make sure the test box is checked (and you have the local origin server running).
When you run the experiment, data will now be logged on a per-iteration or per-measurement basis based on the type of data you are logging.
If you run into an issue try removing the offending variables from the list with the remove button. Re-running the experiment will repopulate the list.