LORD-MicroStrain / MSCL

MicroStrain Communication Library
https://www.microstrain.com/software/mscl
MIT License
77 stars 57 forks source link

¿How to export data in CSV archive? #146

Open SSI7210153 opened 3 years ago

SSI7210153 commented 3 years ago

Hi.

I'm new to programming and I work with the mscl library for python and LORD Wireless Sensors. I want to know if there is a function of the library that exporting data in CSV or if I have to make a step for step. Also, I like to know examples with the following functions, please:

¿The Histogram function makes graphics of the data?

Thank you for the help, and looking forward to your reply.

msclissa commented 3 years ago

Hi - sorry for the delayed response!

CSV export We do not provide CSV export functionality within MSCL, you'll need to implement that yourself, but if you run into any issues streaming or accessing data we'd be happy to help!

Histogram MSCL does not have any visualization functionality. The Histogram isn't so much a function as a specific data format that is output by our SHM-Link nodes. I suppose you could use the Histogram class to build your own histogram data over time, but we don't have any examples of this. Let me know if you're using an SHM-Link and I can provide more direction for interpreting the output histogram data.

DatalogDownloader Unfortunately we don't currently have published examples for this, but I do have a code snippet in C++ that should be pretty straightforward to switch over. There is one known outstanding issue in this workflow for Python in accessing the calibration coefficients of the datalog sessions. We're working on resolving this, but in the mean time the issue and a workaround is documented in Issue 136 here. The workaround assumes that the calibration configuration has not changed since the time of data collection. The C++ snippet is below - let us know if you run into any issues in implementation!

void datalogDownload(mscl::WirelessNode& node)
{
    mscl::DatalogDownloader downloader(node);
    mscl::SampleRate currentSampleRate;
    mscl::ChannelCalMap currentCalCoefs;

    while (!downloader.complete())
    {
        // get next sweep
        mscl::LoggedDataSweep sweep = downloader.getNextData();

        // check if sample rate or cal coefficients have changed
        if (downloader.metaDataUpdated())
        {
            currentSampleRate = downloader.sampleRate();
            currentCalCoefs = downloader.calCoefficients();
        }

        // access data
        for (mscl::WirelessDataPoint data : sweep.data())
        {
            // access timestamp
            sweep.timestamp();

            // access channel name, id, number
            data.channelName();
            data.channelId();
            data.channelNumber();

            // can access actual type based on storedAs but will convert to float fine regardless
            mscl::ValueType storedAs = data.storedAs();
            float val = data.as_float();

            // if cals not already applied to sweep, apply them (optional)
            if (!sweep.calApplied())
            {
                // get cal for this data point channel
                mscl::CalCoefficients calCoef = currentCalCoefs.at(data.channelId());

                // apply coef, access unit
                val = (val * calCoef.linearEquation().slope()) + calCoef.linearEquation().offset();
                mscl::WirelessTypes::CalCoef_Unit unit = calCoef.unit();
            }
        }
    }
}
SSI7210153 commented 3 years ago

Thank you very much. The information is clear now. I try to graphic data, and this is what I made.

import time from time import sleep import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np import mscl import re import csv import threading IP = "xxx.xxx.xxx" #WSDA-2000 PORT = xxxx NODE_ADDRESS1 = xxxxx #G-LINK-200-OEM NODE_ADDRESS2 = xxxxx data= [] data.append([0.0]) data.append([0.0]) data.append([0.0]) data.append([0.0]) saveData={} `

Function for loop of reading in data

def readingData(baseStation): archive= open('datos.txt','a') while True:

get all of the data sweeps that have been collected by the BaseStation, with a timeout of 500 milliseconds

    sweeps = baseStation.getData(500)

    for sweep in sweeps:
        # print out information about the sweep
        # print("Packet Received", end=' ')
        # print("Node", sweep.nodeAddress(), end=' ')
        # print("Timestamp", sweep.timestamp(), end=' ')
        # print("Tick", sweep.tick(), end=' ')
        # print("Sample Rate", sweep.sampleRate().prettyStr(), end=' ')
        # print("Base RSSI: ", sweep.baseRssi(), end=' ')
        # print("Node RSSI: ", sweep.nodeRssi(), end=' ')

        # print("DATA: ", end=' ')
        # iterate over each point in the sweep
        for dataPoint in sweep.data():
            #print out the channel data
            match = re.match('^ch\d', dataPoint.channelName())
            if match != None:
                archive.write(dataPoint.as_string()+'\n')
                # print(dataPoint.channelName(), ":", dataPoint.as_float(), end=' ')
        # print("")

Function for loop of reading and graphic data

def graphicData(data, baseStation):

archive= open('datos.txt','a')

while True:

    # if flag:
    #     print('wait, starting acquisition...')
    #     time.sleep(0.1)
    time.sleep(0.03)
 #######################################################

    sweeps = baseStation.getData(500)
    flag= False
    for sweep in sweeps:
        # print('Node', sweep.nodeAddress())
        # iterate over each point in the sweep
        for dataPoint in sweep.data():
            #print out the channel data
            match = re.match('^ch\d', dataPoint.channelName())
            if match != None:
                if dataPoint.channelName() == 'ch1':
                    # print('ch1: ',dataPoint.as_float())
                    data[1].append(np.round(dataPoint.as_float(),5))
                    if len(data[1])>100:
                        data[1].pop(0)

                if dataPoint.channelName() == 'ch2':
                # print('ch1: ',dataPoint.as_float())
                    data[2].append(np.round(dataPoint.as_float(),5))
                    if len(data[2])>100:
                        data[2].pop(0)

                if dataPoint.channelName() == 'ch3':
                # print('ch1: ',dataPoint.as_float())
                    data[3].append(np.round(dataPoint.as_float(),5))
                    if len(data[3])>100:
                        data[3].pop(0)

This function update the lines

def update_line(num, hl1, hl2, hl3, data): dx = np.array(range(len(data[1]))) #Funca con el len de data[1 o 2 o 3] ya que solo nos interesa generar el mismo tamaño de datos que se guardan en las posiciones 1, 2 o 3 dy1 = np.array(data[1]) dy2 = np.array(data[2]) dy3 = np.array(data[3]) hl1.set_data(dx, dy1) hl2.set_data(dx, dy2) hl3.set_data(dx, dy3) return hl1, hl2, hl3, try: baseStation = connectBaseStation(IP, PORT)

disableBaseStation(baseStation)

node1 = createWirelessNode(NODE_ADDRESS1, baseStation)
# getCurrentConfig(node1)
# setCurrentConfig(node1)

#node2 = createWirelessNode(NODE_ADDRESS2, baseStation)
#getCurrentConfig(node2)
#setCurrentConfig(node2)

network = createModeSamplingNet(baseStation)
addNode(node1, network)
#addNode(node2, network)
configNetwork(network)
startSamplingNetwork(network)

fig = plt.figure(figsize=(10,8))
ax = fig.gca()
plt.ylim(-2.00, 2.00)
plt.xlim(0, 100)

hl1, = plt.plot(data[0], data[1], label='Canal 1')
hl2, = plt.plot(data[0], data[2], label='Canal 2')
hl3, = plt.plot(data[0], data[3], label='Canal 3')
plt.legend(loc='upper left')

dataCollector = threading.Thread(target=graphicData, args= (data,baseStation,))
dataSaving = threading.Thread(target=readingData, args= (baseStation,))
dataCollector.start()
dataSaving.start()

line_ani = animation.FuncAnimation(fig, update_line, fargs= (hl1, hl2, hl3, data), interval = 25, blit= False) #repeat= False, 

plt.show()

dataSaving.join()
dataCollector.join()

except Exception as e: print("Error:", e)
` I got it, this code to print a graphic of the data and save data. But this runs very slow, any idea why? If I remove the thread and the save data function, the graph is fluid, as long as I do not remove the 30 ms wait in the graphicData function, because if I remove it, the graph freezes.

I also want to configure the node as an inclinometer. For this, I have used the function sensorOutputMode_tilt, but channels 4 and 5 are not actives, I try to use activeChannels, but so far I have not managed to use the functions well, it always gets me error:

config = mscl.WirelessNodeConfig() config.activeChannels.(4).enable() I also tried with ChannelType, but it does not work: config = mscl.WirelessNodeConfig() config.ChannelType(mscl.WirelessTypes.chType_tilt) Thank you for the help, and looking forward to your reply.

SSI7210153 commented 3 years ago

I realized that the code to graph is not well appreciated, so I better attach the script.

graficar.zip

ingeltro commented 2 years ago

Hi.

I'm new to programming and I work with the mscl library for python and LORD Wireless Sensors. I want to know if there is a function of the library that exporting data in CSV or if I have to make a step for step. Also, I like to know examples with the following functions, please:

  • DatalogDownloader
  • Histogram

¿The Histogram function makes graphics of the data?

Thank you for the help, and looking forward to your reply.

Hi, were you able to implement a csv conversion function? I have the same need.