Closed KF243 closed 2 years ago
Are you running Python v 3.6 or below? If so can you upgrade to v 3.7 or above and try running again.
Python is upgraded to version 3.9.6, and then the result changes to the following.
min() arg is an empty sequence
This appears to be happening because data from the JV scan to determine the inital Vmpp can not be read. Can you verify that when you run the program a voc.csv
and jv.csv
file are created before the MPP starts. Is there data in those files?
If you need to get the experiment up and running you can skip the automated Voc and JV scans by using the MPP_Tracking
procedure, and supplying the initial Vmpp.
voc.csv and jv.csv files are created at "C:\Users\kf\data\" when the last error message was shown as follows,
File "C:\Users\kf\AppData\Local\Programs\Python\Python39\lib\site-packages\easy_biologic\base_programs.py", line 1700, in <dictcomp>
ch: min( data, key = lambda d: d.power ) # power of interest is negative
ValueError: min() arg is an empty sequence
Is the "data" folder created at the correct path?
Yes, that is the correct path. Is there data written into the jv.csv
file?
I re-installed easy-biologic on the anaconda python and could create jv.csv voc.csv and mpp.csv files in data folder at the top directory. I also confirmed the contents in these files. So I think the problem might be caused by the wrong installing of easy-biologic in my python PC. At the next step, I will code to show the results as the graphs with matplotlib and change the details of method.
I can only find brief comments for methods in your Project description. Could you open the more detail explanation for them?
I re-installed easy-biologic on the anaconda python and could create jv.csv voc.csv and mpp.csv files in data folder at the top directory. I also confirmed the contents in these files. So I think the problem might be caused by the wrong installing of easy-biologic in my python PC. At the next step, I will code to show the results as the graphs with matplotlib and change the details of method.
Great to hear :)
I can only find brief comments for methods in your Project description. Could you open the more detail explanation for them?
Is there a more specific question you have that I can help you with? I am happy to include more examples in the documentation, but that will take me some time.
MPP may serve us Vmpp by OCV and JV scan if the cell wires are connected with no cell. However, an ocv.csv file with correct data, a jv.csv file without data and no mpp.csv file are created with the following messages, when the cell wires were connected with DC3 dummy cell (in standard 3 electrode connection and this connection was successfully operated with EC-Lab).
(biologicSP300) C:\Users\kfush>python C:\Users\kfush\data\try.py
Traceback (most recent call last):
File "C:\Users\kfush\data\try.py", line 19, in <module>
mpp.run( 'C:/Users/kfush/data' )
File "C:\Users\kfush\anaconda3\envs\biologicSP300\lib\site-packages\easy_biologic\base_programs.py", line 1580, in run
self.v_mpp = self._run_jv( self.voc, jv_loc, by_channel = by_channel, jv_params = jv_params ) # jv
File "C:\Users\kfush\anaconda3\envs\biologicSP300\lib\site-packages\easy_biologic\base_programs.py", line 1699, in _run_jv
mpp = {
File "C:\Users\kfush\anaconda3\envs\biologicSP300\lib\site-packages\easy_biologic\base_programs.py", line 1700, in <dictcomp>
ch: min( data, key = lambda d: d.power ) # power of interest is negative
ValueError: min() arg is an empty sequence
Which kind of problem is causing in my JV scan?
The issue is that for some reason the JV_Scan
program that is built into the MPP
program isn't collecting any data. Can you please try running a JV_Scan
program on it's own, and see if that works.
The problem depends on the cell and not on the program. Isn't it caused by using Ultra Low Current booster (https://www.biologic.net/products/ultra-low-current-down-to-aa-resolution/)?
Ah, I understand. What happens if you run a CV scan from EC Lab directly?
There are two boards named 1ch and 2ch in EC Lab (0 and 1 in example.py), which are connected via each booster with a dummy cell or no cell. In EC lab, 1ch showed an Ohmic slope during CV but 2ch gave current over load and failed CV. In the same connection, try30.py (line 15: channels = [0] ) created jv.csv (very small current and no ohmic slope) for 1ch and try31.py (line 16: channels = [1] ) created jv.csv (no data) for 2ch try3.zip .
For channel 2 the failure is expected. The current overload will prevent the measurement from proceeding and the JV_Scan
should fail by design. If the technique won't run using EC Lab it appears the issue is with your dummy cell, and not the easy_biologic
program.
Sorry. It was not "current overload" but "Control amplifier overloaded on channel 2" using EC-Lab. It is because of no dummy cell. Using easy-biologic, no dummy cell connection gathered very small current and created jv.cvs file. The problem is occurred when try30.py is used for the connection with a dummy cell. In all cases, Ultra Low Current booster is used because our SP-300 has no general cables.
Alternately, I am trying the using JV_Scan directly as cbj.py. It seems to run. But I do not know how the data is correctly measured. How the data can be saved in csv file ?
Ah, I understand. I am unsure as to why the measurement is failing. My suggestion would be to just run an MPP_Tracking
program then. That way you can bypass teh JV_Scan
which is giving you problems. Is that a viable solution for you?
You can save data using the BiologicProgram#save_data method. e.g. jv.save_data( 'path/to/file.csv', by_channel = False ).
Many thanks. Now, jv_scan data file is successfully created independent of cell connection.
For the next ca measurement, in which ch0 and ch1 are independently polarized at different voltages, eg. 0.1 and 0.2 V, respectively, how do I code it? Using the attached py, both chs seems to be polarized at 0.1 V. try5.zip .
To specify different parameters for each channel you can use a dictionary keyed by channel with values of the specific parameters. e.g.
params = {
1: { 'start': 0, 'end': 1, 'step': 0.01 },
2: { 'start': -1, 'end': 0, 'step': 0.05 }
}
According your example, I modified for JV_Scan as follows but it does not work.
jv = blp.JV_Scan(device =
bl,
params = {
'1': { 'start': 0, 'end': 1, 'step': 0.01 },
'2': { 'start': -1, 'end': 0, 'step': 0.05 }
},
channels = [0, 1]
)
Does not need the dictionary 'quote' for a key? For two chs (0 and 1), how does the params relate to channels? Is the params of CA {'voltages', 'durations', etc} instead of { 'start', 'end', 'step', etc} ?
When specifiying channel specific parameters you leave out the channels
argument. e.g.
jv = blp.JV_Scan(
device = bl,
params = {
1: { 'start': 0, 'end': 1, 'step': 0.01 },
2: { 'start': -1, 'end': 0, 'step': 0.05 }
}
)
ca = blp.CA(
device = bl,
params = {
1: { 'time_interval': 0.01, 'voltages': [ 0.1, 0.2, 0.3 ], durations: [ 1, 1, 1 ] },
2: { 'time_interval': 0.1, 'voltages': [ 0.4, 0.5, 0.6 ], durations: [ 10, 5, 10 ] }
}
)
int
s.Thanks. Now both ch0 and ch1 are polarized potentiostatically using the zipped cbj3.py.
For two channel connection, we need to use floating mode instead of ground mode. How can I switch the mode? During the CA running, how can I display measured values such as current?
Glad to hear we're making progress :)
I don't currently have the ability to change the ground mode programmed. I would be happy to implement it, but it may be a week or two until I get around to it. I also don't have an SP300, so won't be able to test it on my own hardware before hand. I suggest creating this as a seperate issue if you would like me to implement it.
To read the current measurement data you can register a callback function using the BiologicProgram#on_data
method. Because the program writes its data to file as soon as it is processed, you can also create a separate program that just reads the file. If you will be collecting data over a long period of time, I would also suggest setting the BiologicProgram.data_window
attrribute to release memory.
e.g. Using #on_data
def my_logging_function( segment, program ):
data = segment.data
print( data )
ca = CA( ... )
ca.on_data( my_logging_function )
Thanks every time. Ground/floating mode switching was separated as other issue.
cbj32.py using ca = blp.CA(...) does not show the current data. But ca = CA(...) seems to be not accepted on Spyder that shows "CA is undefined name" during the coding. What should be fixed?
ca = CA( ... )
throws an error because you have not imported the class directly, e.g. from easy_biologic.base_programs import CA
. Instead you have only import the base_programs
module with import easy_biologic.base_programs as blp
, so must always access the classes with in with the namespace, i.e. ca = blp.CA( ... )
.
In the provided file you have registered the callback function incorrectly., and it doesn't appear you've started the program any where. I also noticed you've provided the bin_file
and xlx_file
parameters to bl.connect()
which you shouldn't have to do.
import easy_biologic as ebl
import easy_biologic.base_programs as blp
bl = ebl.BiologicDevice( ... )
bl.connect()
def my_logging_function( segment, program ):
data = segment.data
print( data )
ca = blp.CA( ... )
ca.on_data( my_logging_function )
ca.run()
OK. cbj4.py gives us data, the number of which is a inverse of 'time_interval', with a 1-second interval for 'duration'. 1) How can I change the interval of 1 s? 2) During this interval, how can I run an other program (eg. printing some messages depending on measured data)?
I'm a bit confused by your question.
cbj4.py
it appears you have changed the time_interval
parameter for channel 0
. Are you talking about a different interval?BiologicProgram#ondata
method as shown before. If you would like to run something while waiting you can reimplement the BiologicProgram#_run
or BiologicProgram#_retrieve_data
methods. Sorry for the confusing.
Okay, I understand a bit better now. I'm not familiar with SECM, but form what I understand you position the electrode spatially, then run a scan, then move the elctrode to a new position and run another scan, continuing the process for each position. If this is the case it seems the best approach would be something like:
# NOTE: This is pseudo-code
import numpy as np
from easy_biologic.base_programs import CA
x = [ 1, 2, 3 ] y = [ 1, 2, 3 ] xx, yy = np.meshgrid( x, y ) coordinates = np.c_[ xx.ravel(), yy.ravel() ]
electrode = MyElectrodeController() # for example purposes
ca = CA( ... )
for coord in coordinates:
electrode.move_to( coord )
datapath = f'x{coord[ 0 ]}-y_{coord[1]}' ca.run( data_path )
I will check tomorrow morning whether the "for coord in coordinates:" disturbs the potentiostatic polarization or not. With the latest code, I will also check if I can get the data for a short period smaller than 1 s (eg. 100 ms) after each electrode scan.
cbj5.py results in showing the intermittent polarization like pulse polarization. As you know, just after the polarization a double layer charging takes place and then Faradaic reaction proceeds. Because of the initial charging, several hundreds milli-seconds are needed and the detection of Faradaic reaction is disturbed. For the fine imaging, once started, the polarization does not stop. Can we freeze the polarization status with some functions?
This is possible, although it does start to get a bit complicated. I've attached here an example of a program we use where we perform MPP tracking in combination with a light source. We keep the light on for a specified amount of time and perform MPP tracking, when the light turns off we hold each channel at a different voltage for a given amount of time, then we turn the light source back on and resume MPP tracking.
This should act as a good template for your customization. You will need to subclass either BiologicProgram
or CA
to add in this functionality, as we have done in the MPP_Tracking_w_Lamp
in the attached file. Note that I have removed many details from this file to make it more readable, so if you try to run it there will be errors.
Certainly, your template seems to be useful for my target. But it makes errors which is difficult for me to understand. For example, I have no idea what Lamp() provides at line 219 because of no information of bcu and dp. What are defined at the dictionary (**jv_params) at line 245? Do you have more simple examples for MPP_Tracking?
As I mentioned, I removed much of the code to make it a bit more readable, so errors were going to occur. Unfortunately without a better understanding of the specifics of your project it is hard for me to give much input.
The main idea though, is that you can subclass either the BiologicProgram
or CA
classes and add your control code in the _run
method. I have included the full example code below for your reference.
Please find the attachment which is the specifics of my project. During the XY stepping motions, current data (now, it is dummy) are collected to image. Initially potentiostatic polarization for 0ch and 1ch needs to be started. Current data of either ch at each XY step needs to be measured to image without disturbing polarization.
Using "segment" provides instantaneous data. Is it possible for my target to collect current data in a csv file and to combine with scanning program? Nevertheless, how to control the providing number of instantaneous data is unclear. In the attached case, time=interval:0.1, durations:10 for 2ch writes a couple of lines 10 times. How do I increase the line number in the same durations.
I'm not sure I completely understand your questions, but I will do my best to answer them.
Yes, you can write the data out to a file as you wish. I suggest looking at the BiologicProgram.save_data
method for an example. Be aware that in the DataSegment
there is both processd and unprocessed data. For the data to make sense you must access the .data
attribute of the segement.
You can not control the amount of data coming from the BioLogic device. Essentially it will take a measurement whenever it surpasses one of the thresholds set up in the program parameters. This data is stored in a buffer. When Biologic._retrieve_data
is called it pulls all the data out of this buffer.
Attached is some pseudocode that may be useful for you. I have not tested it, and there are likely errors, but hopefully it gives you an idea of ho I would approach the program from what I understand of it. secm.zip
I am overwhelmingly lacking in reference information. How I can find BiologicProgram.save_data and Biologic._retrieve_data ?
Thanks. Compared with mpp_lamp_track.py, certainly, secm.py may be useful for me. But it is still difficult for me to understand. Only for SECM( blp.CA) operation (without PositionController() operation), how are voltages and params set? secm1.py results in the followings.
C:\Users\kfush>python C:\Users\kfush\data\secm1.py
Traceback (most recent call last):
File "C:\Users\kfush\data\secm1.py", line 184, in
The documentation for both BiologicProgram.save_data
and Biologic._retrieve_data
is included in their docstrings which you can see in the program
file.
You can update a program's parameters using the BiologicDevice.update_parameters
method. An example of how to use this is seen in the CA.update_voltages
method.
The reason your error is occurring is becasue of the way params
are being passed in. If params
is a dictionary keyed by the channels, you can not pass the channels
parameter as well. Only use the channels
parameter if all the channels use the same parameters, in which case the parameters should be a dictionary of the parameters only, not including the channels.
e.g.
# all channels with same parameters
secm = SECM(
bl,
coordinates,
position_controller,
params = { 'time_interval': 0.1, 'voltages': [ 0.1 ], 'durations': [ 10 ] },
channels = [ 0, 1 ]
)
# or
# parameters specified by channel
secm = SECM(
bl,
coordinates,
position_controller,
params = {
0: { 'time_interval': 0.1, 'voltages': [ 0.1 ], 'durations': [ 10 ] },
1: { 'time_interval': 0.1, 'voltages': [ 0.2 ], 'durations': [ 10 ] }
}
)
line184: what is the role of argument 'data' for secm.run()? SECM12.py can run because voltage of -0.2V for 10s at 1ch is detected actually but go somewhere without error message. How do I check the status of the program? How do I show the measured current?
'data' was put here accidentally. It should be removed.
You can retrieve the measured current either from the BiologicProgram.data
attritute, or you could read it in from the file it is being saved to.
What sort of status do you want from the program?
Line 184 in secm12.py was just corrected. But it still show nothing and does not stop. I want to know the "status" or situation, in which the program is running. Specially, I want to know which line is running or which line is wrong.
To retrieve the measured current using BiologicProgram.data attribute or reading from the file, do I need to define a new "class" like PositionController or SECM?
To track which line is running you should use an IDE that allows you to insert break points. I believe VSCode, PyCharm, and DataSpell allow this functionality, and there may be others. You can also place print or logging statements in the function to output what part of the program is currently running.
You don't need to create a new class to retrieve the data. If you are within the program you can use self.data
, or from outside you can do something like secm = SECM(); data = secm.data
.
How do I modify to attribute 'channel' for update_voltages? Is it OK secm.run() is in line 186?
Ah, apologies for this. This seems to be an issue with the CA
program, try using the CALimit
program instead.
i.e.
class SECM( blp.CALimit ):
...
Or you can download and install commit 118bf5, which chould resolve this issue.
Line 55 was modified to 'class SECM( blp.CALimit ):', but the error message does not change.
Exception has occurred: TypeError
an integer is required (got type NoneType)
File "C:\Users\kfush\data\secm13.py", line 156, in _run
self.update_voltages( voltages, channels )
File "C:\Users\kfush\data\secm13.py", line 186, in <module>
secm.run()
In fact, this is a different error. In your code the line occurs on the line self.update_voltages( voltages, channels )
. First, channels
should have probably been self.channels
. But more importantly update_voltages()
does not take channels as a parameter. Please be sure to look at the documentation of the function for its correct use.
Modified secm13.py shows the following error messages.
Exception has occurred: TypeError
float() argument must be a string or a number, not 'dict'
File "C:\Users\kfush\data\secm13.py", line 158, in _run
self.update_voltages( voltages )
File "C:\Users\kfush\data\secm13.py", line 188, in
The documentation may be from line 560 in base_programs.py. But which is the documentation for self.channels?
try1.zip
On the vanilla Python environment, my example.py results in showing this error message. Please suggest how this problem is fixed.