sccn / lsl_archived

Multi-modal time-synched data transmission over local network
242 stars 134 forks source link

How can i get Live Amp Impedance Data? #303

Open antonello87 opened 6 years ago

antonello87 commented 6 years ago

Hello, I am trying to get the impedance data with the Live Amp amplifier. I have seen in the library (Amplifier.h) that there is a method for doing this (getImpedanceData) but till now I wasn't able to get what I want. As I understand from the description of the library the data might be returned differently compared to the getData method (there are additional values, such as GND and REF for example) and maybe the buffer that receives and demuxes these data should be built differently. Am I wrong? Has someone successfully tried to do the same thing? Do I have to enable channels differently? How can I tell the library what kind of electrode (active or passive) I am using? Thanks in advance, Antonello

dmedine commented 6 years ago

This is pretty complicated but everything you need to know is in the API to LiveAmp (Amplifier_LIB.h) and the class defined in LiveAmp.h/c.

There is a function called ampGetImpedanceData which will grab the data from the enabled channels for you (it demuxes the same way that data grabbed via ampGetData does) and you can check electrode type with ampGetProperty using the CPROP_I32_Electrode property. Ground is defined in the hardware and the reference channel can be set with ampSetProperty and the CPROP_B32_ReferenceChannel property (you also have to tell it which channel is the reference channel).

"Read the source, Luke!" and good luck!

On 06/14/2018 02:30 PM, antonello87 wrote:

Hello, I am trying to get the impedance data with the Live Amp amplifier. I have seen in the library (Amplifier.h) that there is a method for doing this (getImpedanceData) but till now I wasn't able to get what I want. As I understand from the description of the library the data might be returned differently compared to the getData method (there are additional values, such as GND and REF for example) and maybe the buffer that receives and demuxes these data should be built differently. Am I wrong? Has someone successfully tried to do the same thing? Do I have to enable channels differently? How can I tell the library what kind of electrode (active or passive) I am using? Thanks in advance, Antonello

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/sccn/labstreaminglayer/issues/303, or mute the thread https://github.com/notifications/unsubscribe-auth/ADch7kvhEkmbq-b9HmDA_fAnaSwYj4S0ks5t8ldkgaJpZM4Un3nr.

antonello87 commented 6 years ago

Dear dmedine, thanks for the answer :) I actually went through the library already and struggled to understand if I have to adapt the function pushAmpData when I set the recording mode to RM_IMPEDANCE. For instance let's say I have 1 Live Amp 32 ch module connected to the active electrodes via 1 SplitterBox (aC-eb32) with 6 EEG Channels enabled, no bipolar channels, no auxiliary channels, accelerometers disabled and just 2 channels for triggers and 2 digital channels (always enabled), REF and GND channels on the earlobes with their clips When I have call the method ampGetImpedanceData how will the returned packet be composed? Based on what I read on the Amplifier_LIB I should receive a packet structured like this: M0_GND, M0_REF, CH1,CH2,CH3,CH4,CH5,CH6 All this values are INT_32, plus 2 UINT_16 for the trigger ones and 1 UINT_32 and 1 UINT_16 for the digital ones, for a total sample size of 42.

dmedine commented 6 years ago

The impedance grabbing functionality of Amplifier_LIB.h is not implemented in LiveAmp.c/h. If you want to use it, you need to call the functions in Amplifier_LIB.h yourself. I haven't actually done this myself yet, so I might be inaccurate, but the comments in Amplifier_LIB.h are pretty clear and this is how I interpret them (could be wrong, though...).

  • Am I right? Is the packet composed like this?

Yes.

  • Are the impedance values returned by the method actually INT_32 or are they FLOAT_something?

Should be float and in Ohms according to the library comments. So your buffer that you pass to getImpedanceData will have to be of type float and the size of the number of channels you are checking, i.e. the number of enabled EEG channels. Triggers channels should not have anything to do with this..

  • Do I have to take other not enabled channels into account for the sample size and then the offset?

Check the sample size to be sure, but my guess would be that you need to enable the channels you want to read and the amp will give you the data for those channels alone.

  • Do I have to set the reference channels even if I have the REF and GND channels placed on the earlobes and i want to use them?

GND is always set in hardware. I seem to remember the same is true for REF also. So probably you don't need to do anything special with them.

  • More specifically, can I access GND and REF channels to set the reference channel to the REF clips I have?

Should always be set to the black one (GND) and the blue one (REF).

  • What are the "always enabled" Digital channels for?

Not sure what your referring to here. Is "always enabled" in the code comments somewhere? Please point me to this.

  • Thanks a lot and sorry for all these questions,

No problem! I hope my answers are actually correct. When I am back at my desk I can check to make sure, but that won't be before a couple of weeks. Hopefully this is enough to get you started, though.—

You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/sccn/labstreaminglayer/issues/303#issuecomment-398114745, or mute the thread https://github.com/notifications/unsubscribe-auth/ADch7uUJU0jsnheBxT0cKtlN5zoraJ_aks5t99WggaJpZM4Un3nr.

antonello87 commented 6 years ago

Thanks dmedine for your prompt answer, following some comments based on what I tried today after your answer:

The impedance grabbing functionality of Amplifier_LIB.h is not implemented in LiveAmp.c/h. If you want to use it, you need to call the functions in Amplifier_LIB.h yourself.

I created a method pullImpedanceData in the LiveAmp.h and LiveAmp.cpp which grab the impedance in the same way pullAmpData does.

Are the impedance values returned by the method actually INT_32 or are they FLOAT_something? Should be float and in Ohms according to the library comments. So your buffer that you pass to getImpedanceData will have to be of type float and the size of the number of channels you are checking, i.e. the number of enabled EEG channels.

The receive buffer cannot be a vector of float because I believe, but I may be wrong, that ampGetImpedanceData returns a flow of bytes the same way ampGetData does.

This means that I need, also in this case, to call the pushAmpData method which scans the received byte flow and demuxes it correctly based on the channel data type. But doing as described the problem still remains, as you can see from the attached image, I keep receiving inconsistent value every column in the image refers to an electrode. In this case I run the program with REF and GND on my earlobs and just one electrode out of six (the number 1) touching the head. This led me to think that maybe the problem is in the pushAmpData function which in this case should demuxes the data differently from when I want to acquire EEG data.

impedancecheckoutput

What are the "always enabled" Digital channels for? Not sure what your referring to here. Is "always enabled" in the code comments somewhere? Please point me to this.

Code from LiveAmp.cpp, almost the end of enableChannels function

if(cnt!=enabledChannelCnt+2) // add two because we are ignoring (for now) the CT_DIG channels, which are enabled

P.s. I will be very grateful if you can check when you will be back at your desk :)

dmedine commented 6 years ago

pushAmpData is merely a convenience function for transforming the data buffer needed by ampGetData (void*) and LSL's push_data (std::vector). It has nothing to do with getting impedance data and is undoubtedly doing the wrong thing if you are using it to demux.

I don't clearly understand what you are trying to do, design wise. Do you want to transmit impedance data via LSL? Do you need to check impedances intermittently during a recording? If you do want to do this, I would recommend making a completely separate process and a separate outlet just for impedances. The data is quite different than the EEG data (structure-wise, different units, etc.), so it doesn't make sense to combine the two somehow.

I will play around with this in the coming weeks and come up with a simple working example. Ping me if you don't hear from me after a while.

As for the CT_DIG channels, I will have to work back through what that is for when I have an amp in front of me. I think you can probably just ignore that for now.

On 06/19/2018 05:39 PM, antonello87 wrote:

Thanks dmedine for your prompt answer, following some comments based on what I tried today after your answer:

The impedance grabbing functionality of Amplifier_LIB.h is not
implemented in LiveAmp.c/h. If you want to use it, you need to
call the functions in Amplifier_LIB.h yourself.

I created a method pullImpedanceData in the LiveAmp.h and LiveAmp.cpp which grab the impedance in the same way pullAmpData does.

Are the impedance values returned by the method actually INT_32 or
are they FLOAT_something?
Should be float and in Ohms according to the library comments. So
your buffer that you pass to getImpedanceData will have to be of
type float and the size of the number of channels you are
checking, i.e. the number of enabled EEG channels.

The receive buffer cannot be a vector of float because I believe, but I may be wrong, that ampGetImpedanceData returns a flow of bytes the same way ampGetData does.

This means that I need, also in this case, to call the pushAmpData method which scans the received byte flow and demuxes it correctly based on the channel data type. But doing as described the problem still remains, as you can see from the attached image, I keep receiving inconsistent value every column in the image refers to an electrode. In this case I run the program with REF and GND on my earlobs and just one electrode out of six (the number 1) touching the head. This led me to think that maybe the problem is in the pushAmpData function which in this case should demuxes the data differently from when I want to acquire EEG data.

impedancecheckoutput https://user-images.githubusercontent.com/32123994/41606133-44a9ff1c-73e3-11e8-843c-3c983a5a812c.png

What are the "always enabled" Digital channels for?
Not sure what your referring to here. Is "always enabled" in the
code comments somewhere? Please point me to this.

Code from LiveAmp.cpp, almost the end of enableChannels function

|if(cnt!=enabledChannelCnt+2)| |// add two because we are ignoring (for now) the CT_DIG channels, which are enabled|

P.s. I will be very grateful if you can check when you will be back at your desk :)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/sccn/labstreaminglayer/issues/303#issuecomment-398444880, or mute the thread https://github.com/notifications/unsubscribe-auth/ADch7luN29qDRePbh6FdKRSb7wR4Mm4zks5t-RspgaJpZM4Un3nr.

antonello87 commented 6 years ago

I don't clearly understand what you are trying to do, design wise. Do you want to transmit impedance data via LSL? Do you need to check impedances intermittently during a recording?

Basically I would like to check the impedance just once, before starting the recording. Of course once I will be able to receive consistent impedance values the best way to do things will be to create a separate outlet that sends them.

I will play around with this in the coming weeks and come up with a simple working example. Ping me if you don't hear from me after a while.

Thank you very much for that :)

antonello87 commented 6 years ago

Dear dmedine,

I will play around with this in the coming weeks and come up with a simple working example. Ping me if you don't hear from me after a while.

As promised I ping you :) Did you manage to come up with some working examples?

Thanks a lot.

antonello87 commented 5 years ago

Dear dmedine, I'm sorry to bother you again but I have to try to get these impedance data as soon as possible. Did you manage to come up with some working examples?

Thanks in advance and please forgive my stubborness.

dmedine commented 5 years ago

I'm not really in a position where I have time to implement this right now. However, here is how to do it:

  1. stop recording with ampStopAcquisition (https://github.com/sccn/labstreaminglayer/blob/master/Apps/BrainProducts/LiveAmp/Amplifier_LIB.h#L447-L450)
  2. put the amp into impedance mode with ampSetProperty (https://github.com/sccn/labstreaminglayer/blob/master/Apps/BrainProducts/LiveAmp/Amplifier_LIB.h#L447-L450)
  3. in a loop request the impedance data with ampGetImpedanceData (https://github.com/sccn/labstreaminglayer/blob/master/Apps/BrainProducts/LiveAmp/Amplifier_LIB.h#L447-L450)
  4. let it run for 30 seconds or so, then take a few seconds and average
  5. push the average impedances out of an LSL marker outlet
  6. reset the amplifier into recording mode with ampSetProperty
  7. resume recording with ampStartAcquisition etc.

Anyway, if I were to send impedance values as a marker every so often, that is how I would do. The data could also be sent as a signal.

If you know C++, everything you need as an example is in the source code (especially in Amplifier_LIB.h and the calls to that library in LiveAmp.h/cpp). But, you can see that implementing this is fairly complicated from a design standpoint---particularly since in order to do it, you need to stop recording for about a minute in order to get accurate impedance measurements. It is not possible to acquire EEG data and impedance data at the same time.

On 8/27/2018 12:33 PM, antonello87 wrote:

Dear dmedine, I'm sorry to bother you again but I have to try to get these impedance data as soon as possible. Did you manage to come up with some working examples?

Thanks in advance and please forgive my stubborness.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/sccn/labstreaminglayer/issues/303#issuecomment-416185259, or mute the thread https://github.com/notifications/unsubscribe-auth/ADch7j2kWAILvv20FG5aXrhm1nvGDTgFks5uU8rwgaJpZM4Un3nr.