LORD-MicroStrain / MSCL

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

Importing Derived Output Channels - Python #354

Open foxjonesx7 opened 1 year ago

foxjonesx7 commented 1 year ago

Hi,

I have had no luck importing the "Derived Output Channels" such as RMS, Peak-to-Peak, Crest Factor, Velocity, and Mean. For example, the following works great for the regular channels in the Python 3.6 version of the MSCL (Note: I used '#' to replace my actual node addresses):

Import libraries

import mscl

Set COM port and Node Addresses

COM_PORT = "COM3" NODE_ADDRESSES = [####, #####, #####]

Define the channels to display for each node

CHANNELS_TO_DISPLAY = {

: ["ch1", "ch2", "ch3"],

#####: ["ch1"],
#####: ["ch1"]

}

However, I cannot figure out how to call in the derived output channels. I have read through all of the supporting documentation and I cannot find anything that helps with this. Is this even possible? If so, can you please provide guidance.

Thank you!

foxjonesx7 commented 1 year ago

Any updates on this?

msclissa commented 11 months ago

Sorry for the delayed response. Once the node is configured to output the derived channels, those data points are read in from the base station through the same BaseStation::getData() function - any data points the base station receives are included in the sweeps returned from this function.

I've included some sample code below for configuring a node to output derived channels as well as retrieving and printing out different properties of derived channels (channel name, value, derived algorithm type, etc.). The data retrieval code will work for both regular and derived data, regular data just won't print out any of the derived data-specific properties.

The examples are in C++ but hopefully it's pretty straightforward to convert them over. Let us know if you run into any trouble or you need clarification on anything!

Setup and Configure

///////// Setup BaseStation and Node objects /////////
mscl::BaseStation baseStation(connection);
mscl::WirelessNode node(201, baseStation);

///////// Set node to idle /////////
// Note: recommend replacing this with something more robust that cannot hang indefinitely
mscl::SetToIdleStatus idleStatus = node.setToIdle();
while (!idleStatus.complete())
{
    continue;
}

///////// Configure Node /////////
mscl::WirelessNodeConfig config;

// channel mask: enable derived data for chs 1, 2, and 3
mscl::ChannelMask chs;
chs.enable(1);
chs.enable(2);
chs.enable(3);

// specify derived data type and channels
config.derivedChannelMask(mscl::WirelessTypes::DerivedCategory::derivedCategory_peakToPeak, chs);

// specify derived data sample rate (max 1 Hz)
config.derivedDataRate(mscl::WirelessTypes::sampleRate_1Hz);

// enable both derived and regular (raw) data streaming
config.dataMode(mscl::WirelessTypes::DataMode::dataMode_raw_derived);

// apply config to device
node.applyConfig(config);

Setup Network and Start Sampling

///////// Start Sampling /////////
mscl::SyncSamplingNetwork network(baseStation);
network.addNode(node);

// checks for and applies any pending configurations
network.applyConfiguration();

// start sampling network if there are no bandwidth or configuration issues
if (network.ok())
{
    network.startSampling();
}

Collect and Print data

// map to get human-readable labels from derived algorithm type IDs
const std::map<mscl::WirelessTypes::DerivedDataPacketAlgorithmId, std::string> DERIVED_TYPE_LABELS = {
    { mscl::WirelessTypes::DerivedDataPacketAlgorithmId::derivedAlgId_crestFactor, "Crest Factor" },
    { mscl::WirelessTypes::DerivedDataPacketAlgorithmId::derivedAlgId_ips, "IPS" },
    { mscl::WirelessTypes::DerivedDataPacketAlgorithmId::derivedAlgId_mean, "Mean" },
    { mscl::WirelessTypes::DerivedDataPacketAlgorithmId::derivedAlgId_mmps, "mmps" },
    { mscl::WirelessTypes::DerivedDataPacketAlgorithmId::derivedAlgId_peakToPeak, "Peak to Peak" },
    { mscl::WirelessTypes::DerivedDataPacketAlgorithmId::derivedAlgId_rms, "RMS" },
};

// continuously collect data
while (true)
{
    // all data retrieved via getData() function - both derived and regular (raw)
    mscl::DataSweeps sweeps = baseStation.getData();

    // loop through retreived sweeps
    for (int i = 0; i < sweeps.size(); i++)
    {
        mscl::DataSweep s = sweeps[i];
        mscl::ChannelData data = s.data();

        // print node address
        cout << endl << "Sweep: " << s.nodeAddress() << ", " << s.tick();
        for (int j = 0; j < data.size(); j++)
        {
            // print channel name and data value
            mscl::WirelessDataPoint point = data[j];
            cout << endl << "   " << point.channelName()
                << endl << "      Value: " << point.as_string();

            // check if this data point has a derived algorithm ID channel property and print it
            try
            {
                mscl::WirelessTypes::DerivedDataPacketAlgorithmId derivedTypeId = (mscl::WirelessTypes::DerivedDataPacketAlgorithmId)point.channelProperty(mscl::DataPoint::channelPropertyId_derivedAlgorithmId).as_uint8();
                cout << endl << "      Derived Type: " << DERIVED_TYPE_LABELS.at(derivedTypeId) << " (" << derivedTypeId << ")";

            }
            catch(...){/*ignore*/}

            // check if this data point has a derived from channel propery and print it
            try
            {
                mscl::ChannelMask derivedChMask = point.channelProperty(mscl::DataPoint::channelPropertyId_derivedFrom).as_ChannelMask();
                cout << endl << "      Derived From: chs ";

                // loop through each possible channel in the channel mask and print all enabled
                for (uint16_t i = 1; i <= derivedChMask.lastChEnabled(); i++)
                {
                    if (derivedChMask.enabled(i))
                    {
                        cout << i << ", ";
                    }
                }
            }
            catch (...) {/*ignore*/ }
        }
    }
}
foxjonesx7 commented 11 months ago

Thank you so much for your time working on this. I was able to get this up and running in Python 3.6. You are amazing!