multichannelsystems / McsUsbNet_Examples

C#, Python and Matlab code examples to interact with the McsUsbNet.dll
BSD 2-Clause "Simplified" License
7 stars 2 forks source link

Getting accurate data from the MEA2100 device in Python #16

Open happypanda94 opened 1 year ago

happypanda94 commented 1 year ago

Hello,

We intend to use the MEA2100 system to record from and stimulate cultured neuron cells. We have managed to successfully set up the device (with noise testing and signal acquisition with the provided generator), and now we intend to use Python to write our own codes for the device. We tried using the Python examples provided by your company on GitHub, and while the code runs without any issues, we were unable to gain the proper signals from it. We are currently trying to read the sinusoidal signals generated using the signal generator provided along with the system. When we use the MEA data experimenter, we can clearly see the sinusoidal signals as seen in the picture below:

image

When we try to do it using MATLAB, we run into some issues regarding communication with the device, but we can still obtain the sinusoidal signal as intended.

Unfortunately, when we try using the Python code provided as an example, we do not get any intelligible signal from the device. We are getting something like this:

image

image

We would have been worried if there were some issues with the device or our computer, but both the experimenter and even MATLAB can read the sinusoidal signal. However, we would like to perform some additional data processing which is much more convenient in Python, so we would like to write our codes in Python if possible.

We also tried to reduce the number of channels in the block to 1 by changing the number of electrodes to 1 and disabling the checksum channel reading to see where the issue was, but it did not solve the problem. We also tried to implement the MATLAB code for data acquisition (run_mea.m) in Python since it could read the sinusoidal signal (we disabled the OnChannelData handler to do it), but again we did not get any sinusoidal signal. I have added the full code in the comments for your reference.

It is to be noted that the computer we are using for this has Windows 10 (64-bit) with a .NET version of 7.0.302. We tried installing an instance of version 4.7.2, but the OS did not let us do it as there is a higher version already installed. The documentation also says that higher versions would work so we did not try doing anything further. We also thought about whether our computer is properly interpreting the “clr_array_to_numpy.py” script, but it seems unlikely to have any issues.

We greatly look forward to your response.

happypanda94 commented 1 year ago

import time import os

from pythonnet import load ### Without this, the *.dll file was not loading due to belonging to a lower .NET version load("coreclr")

import clr import ctypes import numpy as np import matplotlib.pyplot as plt

from System import * clr.AddReference('System.Collections') from System.Collections.Generic import List

from clr_array_to_numpy import asNumpyArray

clr.AddReference(os.getcwd() + '\..\..\McsUsbNet\x64\\McsUsbNet.dll') from Mcs.Usb import CMcsUsbListNet from Mcs.Usb import DeviceEnumNet

from Mcs.Usb import CMeaDeviceNet from Mcs.Usb import McsBusTypeEnumNet from Mcs.Usb import DataModeEnumNet from Mcs.Usb import SampleSizeNet from Mcs.Usb import SampleDstSizeNet

%%

def OnChannelData(x, cbHandle, numSamples): if dataMode == DataModeEnumNet.Unsigned_16bit: data, frames_ret = device.ChannelBlock.ReadFramesUI16(0, 0, callbackThreshold, Int32(0)); np_data = asNumpyArray(data, ctypes.c_uint16) print(".Net numSamples: %d frames_ret: %d size: %d" % (numSamples, frames_ret, len(np_data))) else: # dataMode == DataModeEnumNet.Signed_32bit data, frames_ret = device.ChannelBlock.ReadFramesI32(0, 0, callbackThreshold, Int32(0)); np_data = asNumpyArray(data, ctypes.c_int32) print(".Net numSamples: %d frames_ret: %d size: %d" % (numSamples, frames_ret, len(np_data)))

if len(np_data)<1000:
    return

plt.figure()
plt.plot(np_data)

def OnError(msg, info): print(msg, info)

%%

deviceList = CMcsUsbListNet(DeviceEnumNet.MCS_DEVICE_USB) DataModeToSampleSizeDict = { DataModeEnumNet.Unsigned_16bit : SampleSizeNet.SampleSize16Unsigned, DataModeEnumNet.Signed_32bit : SampleSizeNet.SampleSize32Signed }

DataModeToSampleDstSizeDict = { DataModeEnumNet.Unsigned_16bit: SampleDstSizeNet.SampleDstSize16, DataModeEnumNet.Signed_32bit: SampleDstSizeNet.SampleDstSize32 }

%%

print("found %d devices" % (deviceList.Count))

for i in range(deviceList.Count): listEntry = deviceList.GetUsbListEntry(i) print("Device: %s Serial: %s" % (listEntry.DeviceName,listEntry.SerialNumber))

%%

dataMode = DataModeEnumNet.Unsigned_16bit;

dataMode = DataModeEnumNet.Signed_32bit;

device = CMeaDeviceNet(McsBusTypeEnumNet.MCS_USB_BUS);

device.ChannelDataEvent += OnChannelData

device.ErrorEvent += OnError

%%

device.Connect(deviceList.GetUsbListEntry(0))

Samplingrate = 10000; device.SetSamplerate(Samplingrate, 1, 0);

%%

miliGain = device.GetGain(); voltageRanges = device.HWInfo.GetAvailableVoltageRangesInMicroVoltAndStringsInMilliVolt(miliGain); for i in range(0, len(voltageRanges)): print("(" + str(i) + ") " + voltageRanges[i].VoltageRangeDisplayStringMilliVolt);

%%

device.SetVoltageRangeByIndex(0, 0);

device.SetDataMode(dataMode, 0) device.SetNumberOfChannels(1) ### Here the number of channels is changed from 2 to 1 device.EnableDigitalIn(Boolean(False), UInt32(0)) device.EnableChecksum(False, 0) ### For now, we disabled the acquisition for checksum channels block = device.GetChannelsInBlock(0); print("Channels in Block: ", block) callbackThreshold = Samplingrate // 10

%%

if dataMode == DataModeEnumNet.Unsigned_16bit: mChannels = device.GetChannelsInBlock(0) else: # dataMode == DataModeEnumNet.Signed_32bit mChannels = device.GetChannelsInBlock(0) // 2; print("Number of Channels: ", mChannels) device.ChannelBlock.SetSelectedChannels(mChannels, callbackThreshold * 10, callbackThreshold, DataModeToSampleSizeDict[dataMode], DataModeToSampleDstSizeDict[dataMode], block)

analogChannels,digitalChannels,checksumChannels,timestampChannels,mChannels=0,0,0,0,0 analogChannels,digitalChannels,checksumChannels,timestampChannels,mChannels=device.GetChannelLayout(analogChannels,digitalChannels,checksumChannels, timestampChannels,mChannels,0) print(analogChannels,digitalChannels,checksumChannels,timestampChannels,mChannels)

%%

device.StartDacq()

time.sleep(0.99)

The code below is copied from the MATLAB example and converted to suit Python

x=0 while True: for i in range(1): while device.ChannelBlock.AvailFrames(i, -1)<1000: time.sleep(0.01) number = device.ChannelBlock.AvailFrames(i, -1) print('Number: ',number)

wait until at least 5000 samples are available

    if number >= 1000:
        print('Bingo')
        #read 5000 samples
        data, frames_ret = device.ChannelBlock.ReadFramesUI16(i, 0, 1000, Int32(0));

        if i == 0:
           #Because the data is acquired in 16 Bit unsigned format, we need to subtract 2^15 to center it around Zero.
           y = asNumpyArray(data, ctypes.c_uint16)
           # mask = bitshift(1, 15); # Create a mask with the 16th bit set to 1
           # y = bitxor(y, mask); # XOR the variable with the mask
           y = y-32768;
           plt.figure()
           plt.plot(y[0:100]);

time.sleep(0.1);
x = x + 1;
print("x: ",x)
if (x == 5):
    break # stop after 500 data packets (~ 5 seconds)

device.StopDacq()

%%

device.Disconnect()