MetaWear C LowPower Sampling

I configured the Bmi160Accelerometer to run at an ODR slower than 12_5_Hz (e.g., 6_25_Hz) and the board cannot return live sample stream after I enabled and started the Bmi160Accelerometer with bmi160.start() command.

However, when I used the bmi160.startLowPower((byte) 0); method, it's streaming at a rate of 46 records per minute (around 0_78125_Hz) whatever ODR I used (e.g., 6.25, 3.125, and etc.).

How can I use the lowPower mode correctly? I didn't quite understand the byte parameter required by the startLowPower(Param) in the API doc. And how can I configure the sensor to sample at the correct ODR?

Comments

  • There is a bug in the API with regards to undersampling.  It accidentally combines low power mode with undersampling which results ina  fixed sampling rate of 0.78125Hz.  This will be fixed in the next API update along with an updated way to enable to use the lower frquencies.

    The byte parameter controls the number of acceleration samples that are averaged for undersampling.
  • I pushed a commit to the GitHub that addresses the undersampling issue, commit fdcd84d5.  You should give the update a whirl to see if you can sample at lower frequencies.  To use lower frequencies, you must explicitly enable undersampling when configuring the acceleration sampling.

    accelModule.configureAxisSampling()
            .setOutputDataRate(Bmi160Accelerometer.OutputDataRate.ODR_3_125_HZ)
            .enableUndersampling((byte) 4)
            .commit();


  • Do you have an estimated timeline for the next API update? Or can you provide with a hotfix on the bug?
  • edited January 2016
    You can use the hotfix by downloading the source code of the library at that commit hash and importing the code directly into your main project.  The next APi release will happen sometime next week.
  • Hi Eric, I found something interesting.

    I used the code you sent:
    accelModule.configureAxisSampling()
            .setOutputDataRate(Bmi160Accelerometer.OutputDataRate.ODR_3_125_HZ)
            .enableUndersampling((byte) 4)
            .commit();

    And I successfully logged the data onto the logger. However, the number of samples is alway twice as much as I wanted. When I use 3.125Hz, I supposed to get around 180 samples per minute, but I retrieved around 360 different samples. I switched to 1.5625Hz, I got 180 samples.

    I minimized my logging configuration to make sure I wasn't logging duplicated records. Also, the data points I retrieved were not the same, which means they were not duplicated. Should there be any problem with the Undersampling configuration?

    BTW, since I do not have a signal processing background, can you kindly explain to me what's the intuition behind undersampling and the parameter "size"? What's going to change if I tune "size" up or down? I am not able to understand the documentation "size - Number of samples to be averaged for undersampling" and not able to configure this parameter. 
  • What is the time difference between two consecutive data points in your set of data?  When I stream the accelerometer at 3.125Hz, I see data every ~320ms which corresponds to 3.125Hz sampling frequency.

    How are you calculating your 360 samples / minute ratio @ 3.125Hz?

    For the BMI160, undersampling is an average of several data samples.  If you're not sure what to use, then use size = 1.
  • I connect to the sensor every minute and download the logs. 360 is the number I downloaded from the board. I organized the code a bit below.

    //configuring sampling
    Logging logger = mwBoard.getModule(Logging.class);
    logger.startLogging(true);
    Bmi160Accelerometer accel = mwBoard.getModule(Bmi160Accelerometer.class);

    accel.configureAxisSampling()
    .setOutputDataRate(Bmi160Accelerometer.OutputDataRate.ODR_3_125_HZ)
    .enableUndersampling((byte) 4)
    .commit();

    accel.routeData().fromAxes().log(SENSOR_DATA_LOG).commit().onComplete(accelHandler);
    accel.enableAxisSampling();
    accel.start();

    private final AsyncOperation.CompletionHandler<RouteManager> accelHandler = new AsyncOperation.CompletionHandler<RouteManager>() {
            @Override
            public void success(RouteManager result) {
                state = mwBoard.serializeState();
                routeID = result.id();
                Log.i("info", String.format("RouteID: %d", routeID));
                result.setLogMessageHandler(SENSOR_DATA_LOG, loggingMessageHandler);
            }
        };

    private final RouteManager.MessageHandler loggingMessageHandler = new RouteManager.MessageHandler() {
            @Override
            public void process(Message message) {
                Log.i("data", message.getData(CartesianFloat.class).toString());
            }
        };

    //retrieve log
    final Logging logger = mwBoard.getModule(Logging.class);
    logger.downloadLog(0.1f, new Logging.DownloadHandler() {
                                @Override
                                public void onProgressUpdate(int nEntriesLeft, int totalEntries) {
                                    Log.i("data", String.format("Progress: %d/%d", totalEntries-nEntriesLeft, totalEntries));
                                    if (nEntriesLeft==0) {
                                        Log.i("data", "Download Completed");
                                        mwBoard.disconnect();
                                    }
                                }
  • edited January 2016
    The number of log entries downloaded is not the same as the number of accelerometer data points.  Again, what is the time difference between two consecutive data points in your set of data?  Or alternatively, if you stored all the messages received from the logger into an array, what is the array size after the download is completed?
This discussion has been closed.