Which filter for different noise

Hi all,
I have an imu on a pendulum and I am recording the angle with respect of vertical. The frequency and the amplitude is not constant. The sample rate is 10 Hz more. I am noticing that if I record for more time I will see some noise. The sensor is calibrated. Thus, I don't associate this behaviour to a drift, even more because I guess that the drift shall be is one only direction.

Is there some way to have a range of excurcion more constant? I used a moving average filter but with not success (in the image it is the red line and has the same behaviour of the blue line) :

void setup() {
  Serial.begin(9600);
}

int const fsize = 50;
int fil[fsize];
int i = 0;
float avg = 90;

void loop() {
  int s = analogRead(A0);

  fil[i] = s;
  if (i < (fsize-1)) i++;
  else i = 0;

  for (int j = 0; j < fsize; j++) {
    avg += (float)fil[j];  
  }
  avg = avg / (float)(fsize+1);
  
  Serial.print(s);Serial.print(",");Serial.println(avg);
  delay(10);
}

Thank You so much

And what speed is the pendulum going?
I suspect you are not seeing noise, this just looks like the pendulum movement.
If you want to find the maximum excursion then search for a maximum or minimum and reset on the zero crossing point.

This is a project i did with pendulums some time ago.

The speed is 4km/h. The behaviour is that of a pendulum but in the reality, the imu is on the thigh of a person who walks on tapis roulant. The periodicity of oscillation is weird. Anyway I guess that it shall be a method to standardize the maximum and the minimum. What do you think?

I had to look that up. In English it is called a "Tread Mill"

Have you a link to the imu you are using?
Anything attached to a human walking is going to give you less than consistent results.

Example of use.


void fReadBattery( void * parameter )
{
  float adcValue = 0.0f;
  const float r1 = 50500.0f; // R1 in ohm, 50K
  const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
  float Vbatt = 0.0f;
  int printCount = 0;
  float vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
  uint64_t TimePastKalman  = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 1000; //delay for mS
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_0); //read and discard
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
    KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
    Vbatt = adcValue * vRefScale;
    xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
    CalculatedVoltage = Vbatt;
    xSemaphoreGive( sema_CalculatedVoltage );
    
      printCount++;
      if ( printCount == 3 )
      {
      log_i( "Vbatt %f", Vbatt );
      printCount = 0;
      }
    
    TimePastKalman = esp_timer_get_time(); // time of update complete
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( "fReadBattery %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}

Makes things real smooth.

this is the imu. For sure it can feel movement artefacts. but the angle is computed in order to have a constant behaviour. Indeed this trend is figuring only when a lot of time is passed (only one minute) and it has a kind of periodicity.

I have had a play with one of these some time ago and couldn't get it to calibrate correctly, and couldn't get much sense out of it. So I can't help with this sorry.

thus, which is your suggestion? can you link me some imu with easier calibration and more accurate output?

Well I don't have any, other than I would jus one of the tilt switch sensors that you use in pedometers.

The human thigh is not a good conductor of movement. There is too much flesh that moves in non-determinate ways. Just above the kneecap is probably the best location for mounting an IMU on the thigh. The bone is near the surface so provides fairly good conductance of movement of the thigh.

From: Test-Retest Reliability of Kinematic and Temporal Outcome Measures for Clinical Gait and Stair Walking Tests, Based on Wearable Inertial Sensors
"...on the right and left thigh three centimeters above the apex patella..."

From: Assessment of Stability of MIMU Probes to Skin-Marker-Based Anatomical Reference Frames During Locomotion Tasks: Effect of Different Locations on the Lower Limb
"...in the thigh, the frontal position was the most stable in all tasks, especially in gait..."

and you might be interested in:
Human Gait Modeling, Prediction and Classification for Level Walking Using Harmonic Models Derived from a Single Thigh-Mounted IMU

1 Like

You never reset avg to zero, so this can't possibly produce meaningful results.

I am recording the angle

Well, you are attempting, but so far failing, to average some acceleration values.

That is, if the unidentified "imu" is an accelerometer with an analog output.

it looks like you're undersampling.

the serial prints are adding additional delay. print the the samples only when the array index wraps

int const fsize = 50;
int fil[fsize];
int i = 0;

void loop()
{
    fil [i++] = analogRead (A0);

    if (i >= fsize)  {
        for (unsigned n = 0; n < fsize; n++)
            Serial.println (fil [n]);
        Serial.println ();
        i = 0;
    }
    delay(10);
}

void setup() {
    Serial.begin(9600);
}

also verify the data without any movement and then with very slow movement

what exactly is you input? angle, distance, acceleration

And

See post #6 guys.

Right.

The BNO055 is a digital sensor, so the analogRead() values ARE just noise.

In addition to the other problems.

1 Like

Thank You so much, your info are very useful

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.