This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Single float division causing ~7x higher current draw

Hi, I'm facing an extremely strange problem with a product I'm developing.

I've been getting significant idle current measurements (around 7 mA), and I couldn't for the love of me figure out what was causing it. I stripped the application code down and added parts in one by one, watching the idle current. The current while advertising is about 1 mA, which seems reasonable. I narrowed it down to a single C++ class instance. This is the class:

.h file:

#ifndef ERROR_MODEL_GYRO_LEARNING_H
#define ERROR_MODEL_GYRO_LEARNING_H

#include "error_model.h"

/**
 * @brief      An error model for gyroscopes, using an accelerometer to learn bias values.
 */
class ErrorModelGyroLearning: public ErrorModel {
private:
    Vector3 m_lastAccel;
    Vector3 m_bias;

    float m_sampleRate;
    float m_alpha;
    uint32_t m_sampleCount = 0;

public:

    /**
     * @brief      Constructs the error model instance.
     *
     * @param[in]  sampleRate  The rate at which the data is sampled
     */
    ErrorModelGyroLearning(float sampleRate);

    void processSample(SensorData& data) override;
}; 

#endif  // ERROR_MODEL_GYRO_LEARNING_H

.cpp file:

#include "error_model_gyro_learning.h"

// Gyroscope noise level
#define FUZZY_GYRO_ZERO             0.20 * RAD_TO_DEG
#define FUZZY_GYRO_ZERO_SQUARED     (FUZZY_GYRO_ZERO * FUZZY_GYRO_ZERO)

// Accelerometer noise level
#define FUZZY_ACCEL_ZERO            0.05
#define FUZZY_ACCEL_ZERO_SQUARED    (FUZZY_ACCEL_ZERO * FUZZY_ACCEL_ZERO)


ErrorModelGyroLearning::ErrorModelGyroLearning(float sampleRate):
    ErrorModel(SensorType::Gyroscope),
    m_sampleRate(sampleRate),
    m_alpha(2.0 / sampleRate) {}
    // m_alpha(2.0 / 100.0) {}

void ErrorModelGyroLearning::processSample(SensorData& data) {
    if(m_enabled) {
        if(!m_valid) {
            Vector3 delta_accel = m_lastAccel - data.accel;
            m_lastAccel = data.accel;

            if(delta_accel.squareLength() < FUZZY_ACCEL_ZERO_SQUARED &&
                data.gyro.squareLength() < FUZZY_GYRO_ZERO_SQUARED) 
            {
                // What we are seeing on the gyros should be bias only so learn from this
                m_bias.setX((1.0 - m_alpha) * m_bias.x() + m_alpha * data.gyro.x());
                m_bias.setY((1.0 - m_alpha) * m_bias.y() + m_alpha * data.gyro.y());
                m_bias.setZ((1.0 - m_alpha) * m_bias.z() + m_alpha * data.gyro.z());
            
                if(m_sampleCount < (5 * m_sampleRate)) {
                    m_sampleCount++;

                    if(m_sampleCount == (5 * m_sampleRate)) {
                        m_valid = true;
                    }
                }
            }
        }

        data.gyro -= m_bias;
    }
}

In fact, I've narrowed it down to this line in the initializer list: m_alpha(2.0 / sampleRate) {}. I'm passing in a sampleRate value of 100. When the m_alpha value is initialized using the sampleRate value, the idle/advertising current draw is over 7 mA. When I initialize m_alpha by hardcoding the sampleRate value, I measure a current of 1 mA.

I'm simply stumped why a single line can cause this much current draw. Could it be a bug in the FPU?

In fact, just putting these three lines at the top of my main.cpp file causes the same behaviour (7 mA idle):

uint32_t interval = 10;
float sampleRate = 1000 / interval;
float m_alpha = 2.0 / sampleRate;

Commenting out the last line results in a current draw of around 1 mA.

Hoping to find the cause of this, because it's driving me insane! I'm using nRF52832 QFAA variant, SoftDevice 132 v3.0.0 and compiling using GCC/G++. My CFLAGS include -mfloat-abi=hard -mfpu=fpv4-sp-d16

Related