I wrote some python code to control a number of USB (electrical relays and temperature sensors) and RS232 (vacuum gauges) devices. From within this main script (e.g., myscript.py), I would like to import a module (e.g., exp_protocols.py) where I define different experimental protocols, i.e. a series of instructions to open or close relays, read temperature and pressure values, with some simple flow control thrown in (e.g. "wait until temperature exceeds 200 degrees C").
My initial attempt looked like this:
switch_A = Relay('A')
switch_B = Relay('B')
gauge_1 = Gauge('1')
global switch_A
global switch_B
global gauge_1
from exp_protocols import my_protocol
my_protocol()
with exp_protocols.py looking like this:
def my_protocol():
print 'Pressure is %.3f mbar.' % gauge_1.value
switch_A.close()
switch_B.open()
This outputs a global variable error, because exp_protocols.my_protocol cannot access the objects defined in myscript.py.
It seems, from reading the answers to earlier questions here, that I could (should?) create all my Relay and Gauge variable in another module, e.g., myconfig.py, and then import myconfig both in myscript.py and exp_protocols? But if I do that, won't my Relay and Gauge objects be created twice (thus trying to open serial ports already active, etc.)?
What would be the best (most Pythonic) way to achieve this kind of inter-module communication?
Thanks in advance.
No matter how many times you import myconfig, python only imports the module once. After the first import, future import statements just grab another reference to the module.
Globals should only be used if these are static bits of data. Your function would be more generic if it took the variables as parameters:
def my_protocol(switch_A, switch_B, gauge_1):
print 'Pressure is %.3f mbar.' % gauge_1.value
switch_A.close()
switch_B.open()
modules could use it with many combinations of data. Suppose you have blocks of switches in a list (and I'm just making this up because I have no idea how you configure your data...), you could process them all with the same function:
import exp_protocols
switch_blocks = [
[Relay('1-A'), Relay('1-B'), Gauge('1-1')],
[Relay('2-A'), Relay('2-B'), Gauge('2-1')],
]
for switch1, switch2, gauge in switch_blocks:
exp_protocols.my_protocol(switch1, switch2, gauge)
Related
I am creating several experiments in python and have various functions which will be common across these experiments. I thus wanted to create a script only containing these functions which I could import at the beginning of the experimental script to avoid half of the script being taken up with 'generic setup lines'.
So far, I have created the functions and the script and can import them and use them. For example, in the following, I have a function which shows a blank screen which takes the duration I want (e.g., 4 seconds) and displays it on the window defined in the experimental script.
import functions
win = visual.Window([1440,900], color=[-1,-1,-1], fullscr=True)
dur = 4
functions.blank_screen(duration=dur)
This all works fine but in the script containing the functions, there are several 'errors' the function uses the variable 'win' which is not defined in the function:
def blank_screen(duration):
blank = TextStim(win, text='')
blank.draw()
win.flip()
But when I run the experimental script, as it is defined in the script, it all works. How can I get around this? I have this problem with several functions as a large majority uses variables which are defined in the experimental script and not in the functions. As I say, it all works but just annoys me that the script is covered in 'errors'!
I'd be greatly appreciative of any help, thank you!
You can pass on the win you want blanked out as an argument to the blank_screen function:
import functions
win = visual.Window([1440,900], color=[-1,-1,-1], fullscr=True)
dur = 4
functions.blank_screen(duration=dur, win=win)
and
def blank_screen(duration, win):
blank = TextStim(win, text='')
blank.draw()
win.flip()
I am struggling with properly organising Python code. My struggle stems from namespaces in Python. More specifically, as I understand, every module has its own specific namespace and if not stated specifically, elements from one namespace will not be available in another namespace.
To give an example what I mean, consider the function subfile1.py:
def foo();
print(a)
Now if I want the foo() function to print a from the namespace of another module/script, I will have to set it explicitly for that subfile1 module; e.g. like in main.py:
import subfile1
a = 4
subfile1.a = 4
subfile1.foo()
When I code (in R), it’s generally to provide data analytics reports. So I have to import data, clean data and perform analyses on this data. My coding projects (to be re-run every couple of months) are then organised as follows: I have a main script from which I run other sub-scripts. I find this very handy I have separate sub-scripts for:
Setting paths
Loading data
Data cleaning
Specific analyses
Simply looking at the names of the sub-scripts listed in the main script gives me then a good overview of what is being done and where I need to add additional sub-scripts if needed.
With Python I don’t find this an easy way of working because of the namespaces. If I would like to keep this way of working in Python, it seems to me that I would have to import all sub-scripts as modules and set the necessary variables for each module explicitly (either in the module or in the main script as in the example above).
So I thought that maybe my way of working is simply not optimal, at least in a Python setting. Could anyone tell me how best to organise the project I have in mind? Or put differently, what is a good way of organising code if the same data/variables has to be used at various places in the code?
Update:
After reading the comments, I made another example. Now with classes. Any comments on whether this is an appropriate way of structuring code or not would be very welcome. My main aim is to split the code in bits and pieces so a third party can quickly gauge what is going on and make changes to the code where necessary.
I have a master_file.py in which I run the code:
from sub_file_1 import DoSomething
from sub_file_2 import DoSomethingElse
from sub_file_3 import CombineTheStuff
x1 = DoSomething.c #could e.g. be import from a data source and transform the data
x2 = DoSomethingElse.d #could e.g. be import from another data source and transform the data taking into its particularities
y = CombineTheStuff(x1, x2) # e.g. with the data imported and cleaned (x1 and x2) I can now estimate a particular model
print(x1)
print(x2)
print(y.fin_result())
sub_file_1.py contains (in reality these sub_files are very lengthy)
from param_file import GeneralPar
class DoSomething():
c = GeneralPar.a + GeneralPar.b
sub_file_2.py contains
from param_file import GeneralPar
class DoSomethingElse():
d = GeneralPar.a * 4
sub_file_3.py contains
class CombineTheStuff():
def __init__(self, input1, input2):
self.input1 = input1
self.input2 = input2
def fin_result(self):
k = self.input1 * self.input2 - 0.01
return(k)
I am trying to write a program in PyDAQmx that counts digital edges and outputs a TTL signal every nth edge. I am having trouble setting the Acquisition Mode in PyDAQmx to be "1 Sample (On Demand)" which is what I set while using LabVIEW. I am using a NI USB6210 DAQ Device.
This is my first time coding with NIDAQ/PyDAQMX/etc so I based this on an example on the PyDAQmx page that shows how to translate a C program into Python, the relevant piece of code looks like this:
read = int32()
data = numpy.zeros((1000,), dtype=numpy.uint32)
try:
DAQmxCreateTask("",byref(taskHandle))
DAQmxCreateCICountEdgesChan(taskHandle,"Dev6/ctr0","",DAQmx_Val_Rising,0,DAQmx_Val_CountUp)
#Somehow set acquisition mode here
DAQmxStartTask(taskHandle)
while True:
DAQmxReadCounterScalarU32 (taskHandle, 1000, None, read)
print "Acquired %d samples"%read.value
print "result is %s " %result
My expectation is that this is the default timing mode for counter input tasks, and you can confirm that by asking the driver via the DAQmx C API's Sample Timing Type parameter:
DAQmxCreateTask("",byref(taskHandle))
DAQmxCreateCICountEdgesChan(taskHandle,"Dev6/ctr0","",DAQmx_Val_Rising,0,DAQmx_Val_CountUp)
timingType = int32()
DAQmxGetSampTimingType(taskHandle, byref(timingType))
print(timingType)
If timingType has the value 10390, then you have on-demand sampling.
In general, if there isn't a function that does what you want (in this case, there isn't a DAQmxCfgOnDemandTiming() function), you can assume that is the default configuration. In addition, the DAQmx functions don't expose all of the device's settings, however, and so for very specialized behavior, you must get and set the properties you require explicitly.
When I look at the output of the function
Phonon.BackendCapabilities.availableAudioEffects()
I get this as one of the options:
>>> speed_effect = Phonon.BackendCapabilities.availableAudioEffects()[3]
>>> speed_effect.name()
PyQt4.QtCore.QString(u'speed')
>>> speed_effect.__doc__
'Phonon.EffectDescription()\nPhonon.EffectDescription(int, dict-of-QByteArray-QVariant)\nPhonon.EffectDescription(Phonon.EffectDescription)'
I understand that I need to insert this effect into a path connecting to my audio source file, and that implementation won't be difficult. What I don't understand is how to access options or what the functionality of this 'speed' effect is. How do I access it through the Python interface? Can I specify a playback rate (like 2x, 4x, etc., for doubling or quadrupling the speed) as an option to this?
Well, not too many people were looking at this so I kept going and finally figured it out. Note that all of this is specific to my particular backend media player, gstreamer, for Phonon. If you have a different backend, you'll need to do some tinkering to see what effects you need to play around with.
The way this works is that you can see names and descriptions of your Phonon.Effect() options by calling the function
from PyQt4 import QtGui, QtCore
from PyQt4.phonon import Phonon
list_of_backend_audio_effects = Phonon.BackendCapabilities.availableAudioEffects()
After this, I figured out which of the available effects was the gstreamer option 'speed', by doing this:
list_of_effect_names = [str(elem.name()) for elem in list_of_backend_audio_effects]
for iter in range(len(list_of_effect_names)):
if list_of_effect_names[iter] == 'speed':
effect_index = iter
break
Finally, you need to actually edit the parameters, which has to be done by going through a data type called a QVariant. To double the speed of the audio, here's what I called:
speed_effect = Phonon.Effect(list_of_backend_audio_effects[effect_index])
speed_effect.setParameterValue(speed_effect.parameters()[0],QtCore.QVariant(str(2)))
In the first line, I create a new Phonon.Effect() which takes the effect description as an input (the things returned by the call the availableAudioEffects()). Then I set the parameter of this effect object (the first argument) to take the QVariant value '2' (the second argument). On my system, the default speed is '1', the min is '0.1' and the max is '40', which represents ranges of speeds between one-tenth and 40 times as fast as the regular audio file encodes.
I hope this helps some Python folks with gstreamer change speeds of audio.
Alright, so a couple days ago I decided to try and write a primitive wrapper for the PARI library. Ever since then I've been playing with ctypes library in loading the dll and accessing the functions contained using code similar to the following:
from ctypes import *
libcyg=CDLL("<path/cygwin1.dll") #It needs cygwin to be loaded. Not sure why.
pari=CDLL("<path>/libpari-gmp-2.4.dll")
print pari.fibo #fibonacci function
#prints something like "<_FuncPtr object at 0x00BA5828>"
So the functions are there and they can potentially be accessed, but I always receive an access violation no matter what I try. For example:
pari.fibo(5) #access violation
pari.fibo(c_int(5)) #access violation
pari.fibo.argtypes = [c_long] #setting arguments manually
pari.fibo.restype = long #set the return type
pari.fibo(byref(c_int(5))) #access violation reading 0x04 consistently
and any variation on that, including setting argtypes to receive pointers.
The Pari .dll is written in C and the fibonacci function's syntax within the library is GEN fibo(long x).
Could it be the return type that's causing these errors, as it is not a standard int or long but a GEN type, which is unique to the PARI library? Any help would be appreciated. If anyone is able to successfully load the library and use ANY function from within python, please tell; I've been at this for hours now.
EDIT: Seems as though I was simply forgetting to initialize the library. After a quick pari.pari_init(4000000,500000) it stopped erroring. Now my problem lies in the in the fact that it returns a GEN object; which is fine, but whenever I try to reference the address to which it points, it's always 33554435, which I presume is still an address. I'm trying further commands and I'll update if I succeed in getting the correct value of something.
You have two problems here, one give fibo the correct return type and two convert the GEN return type to the value you are looking for.
Poking around the source code a bit, you'll find that GEN is defined as a pointer to a long. Also, at looks like the library provides some converting/printing GENs. I focused in on GENtostr since it would probably be safer for all the pari functions.
import cytpes
pari = ctypes.CDLL("./libpari.so.2.3.5") #I did this under linux
pari.fibo.restype = ctypes.POINTER(ctypes.c_long)
pari.GENtostr.restype = ctypes.POINTER(ctypes.c_char)
pari.pari_init(4000000,500000)
x = pari.fibo(100)
y = pari.GENtostr(x)
ctypes.string_at(y)
Results in:
'354224848179261915075'