bicarlsen / easy-biologic

Python library for communicating with Biologic devices.
GNU General Public License v3.0
18 stars 11 forks source link

Maximum data length #6

Closed chemyibinjiang closed 2 years ago

chemyibinjiang commented 2 years ago

Hello, I was trying to use CALimit to control the voltage of the potentiostat but found that the maximum length of the collected data is limited to 190. For example, when I ran the following code

Initialization

import easy_biologic
import sys
import logging
import time 
from matplotlib import pyplot as plt
bl_potentiostat = easy_biologic.BiologicDevice('USB0')
print('Potentiostat device connected.')
bl_potentiostat.connect(bin_file="C:\\Users\group\Documents\GitHub\easy-biologic\easy_biologic\techniques-6.01\kernel.bin", xlx_file="C:\\Users\group\Documents\GitHub\easy-biologic\easy_biologic\techniques-6.01\Vmp_ii_0437_a6.xlx")

CA Limit

ca = easy_biologic.base_programs.CALimit(device=bl_potentiostat,
                                    params={'voltages':[0.4,0.5,0.6,0.7,0.8],
                                            'durations':[0.1,0.1,0.1,0.1,0.1],
                                            'vs_initial':False,
                                            'time_interval':0.001,
                                            'current_interval': 0.001},
                                         channels=[0])

Get data size

print(len(ca.data[0])) # 190

The length of the gathered data is 190. But since I have applied the control for 0.5 seconds with a time_interval of 0.001s, the total data length can be 500. I would really appreciate it if you could give me some information! Thanks!

bicarlsen commented 2 years ago

The first thing I notice is that you are loading a bin_file and xlx_file when connecting. I think you shouldn't have to do this. I'm not sure if it's related to the data issue or not.

For the data, have you tried running wiht a longer time_interval or longer durations? Can you try running the same program from EC-Lab?

chemyibinjiang commented 2 years ago

Hello, Thanks for your reply. It is not necessary to clarify the bin_file and xlx_file so we changed the connection command to bl_potentiostat.connect(). To further test where the problem can be from, we did several tests:

  1. We ran the same program from EC-lab and it works.
  2. We tried running with a longer time_interval, and as long as it increases so that the number of the overall collection points is smaller than 190, it works fine.
  3. With longer duration, the collected points increased. e.g, if we ran these two programs respectively:
    
    ca1 = easy_biologic.base_programs.CA(device=bl_potentiostat,
                                    params={'voltages':[0.5],
                                            'durations':[1],
                                            'vs_initial':False,
                                            'time_interval':0.001,
                                            'current_interval': 0.001},
                                         channels=[0])

ca2 = easy_biologic.base_programs.CA(device=bl_potentiostat, params={'voltages':[0.5], 'durations':[10], 'vs_initial':False, 'time_interval':0.001, 'current_interval': 0.001}, channels=[0])

ca1 gives the collection of 190 points, while ca2 gives the collection of 1900 points. ca1 collects the points until 0.19 s, while ca2 collects the points until 1.9 s. 

Furthermore, if we increased the time interval to 0.01 s, it works fine. The following program gives the right read-out, even though 1000 points are collected. 

ca = easy_biologic.base_programs.CA(device=bl_potentiostat, params={'voltages':[0.5], 'durations':[10], 'vs_initial':False, 'time_interval':0.01, 'current_interval': 0.001}, channels=[0])


Thanks again for your reply :) 
bicarlsen commented 2 years ago

This may be a data read error. Is it possible for you to connect via ethernet?

Does the program run the entire time it should? If not, it could be a memory issue and you can speed up how often a data is read from the Biologic. e.g.

from easy_biologic.base_programs import CA 
class FastCA( CA ):
  def run( self, data_interval = 1 ):
     params = {}
        for ch, ch_params in self.params.items():
            steps = len( ch_params[ 'voltages' ] )

            params[ ch ] = {
                'Voltage_step':      ch_params[ 'voltages' ],
                'vs_initial':        [ ch_params[ 'vs_initial' ] ]* steps,
                'Duration_step':     ch_params[ 'durations' ],
                'Step_number':       steps - 1,
                'Record_every_dT':   ch_params[ 'time_interval' ],
                'Record_every_dI':   ch_params[ 'current_interval' ],
                'N_Cycles':          0,
                'I_Range':           ch_params[ 'current_range' ].value
            }

        # run technique
        data = self._run( 'ca', params, interval = data_interval )

fca = FastCA(device=bl_potentiostat,
                                    params={'voltages':[0.5],
                                            'durations':[10],
                                            'vs_initial':False,
                                            'time_interval':0.01,
                                            'current_interval': 0.001},
                                         channels=[0])

fca.run( interval = 0.01 )

Another option would be to register a custom call back when data is received to check if everything is at least running as it should be. If you look at the BiologicProgram class you can register a callback when the program receives data using the #on_data method. Perhaps printing out a message each time. e.g.

from time import time
ca = easy_biologic.base_programs.CA(device=bl_potentiostat,
                                    params={'voltages':[0.5],
                                            'durations':[10],
                                            'vs_initial':False,
                                            'time_interval':0.01,
                                            'current_interval': 0.001},
                                         channels=[0])

start = time()
ca.on_data( lambda seg, prg ): print( time() - start ) )

ca.run()
chemyibinjiang commented 2 years ago

Hello, Thanks for your comments. Putting an interval in _run() function solves the problem perfectly. Also maybe fca.run( interval = 0.01 ) should be fca.run( data_interval = 0.01 ) to make the argument consistent.

I'm just wondering why adding the interval solves the problem, and should I set the interval to a small value globally when using the package to avoid the efficient collection of data?

bicarlsen commented 2 years ago

Ah, wonderful :) Glad to hear.

My guess as to why the measurement fails if the interval is too long is because the BioLogic's internal buffer overflows, so stops recording data, or dumps old data. By reading the measurements out more quickly you keep the BioLogic's buffer open so new measurements can be recorded.

There is a difference between data_interval and interval which is why they have different names. data_interval tells the BioLogic how often to take a measurement, while interval tells the easy_biologic program how often to read data from the Biologic. Perhaps renaming interval to data_interval would make things more clear.

I think I will also update interval to be based off of data_interval so it is less likely one has to subclass a base_program.

I appreciate all your testing of the library so we can make it more robust.

I'll close this commetn thread now, but please feel free to open another one if anything else comes up, or you have any suggestions for improvement.