Ayuda con el código de suavizado retrasado

1

Estoy colgado de cómo suavizar los datos de sensores analógicos de una manera específica. Matemáticas / código no es mi experiencia, así que gracias de antemano.

Mi boceto necesita escuchar un AnalogPin y suavizar / eliminar cualquier valor atípico a medida que los valores cambian, aunque se ajustan suavemente en el valor final de AnalogPin.

Ej. si el sensor es un Mic en una habitación vacía y en más de 30-60 segundos la sala se llena de gente, necesitaría un MicValue que crezca lentamente hasta el nuevo volumen, pero omite cualquier pasos iniciales del pie o picos principales.

Ej. si el pin AnalogRead es un potenciómetro, girar la perilla rápidamente durante 5 segundos no tendría mucho efecto, pero cuando la perilla termina, el valor se asentará lentamente.

Cualquier ayuda para definir lo que estoy buscando, o ayuda con el código sería muy apreciada. Gracias!

    
pregunta joshjingles

4 respuestas

5

Se puede obtener un estimador suavizado simple simplemente mediante una combinación lineal del nuevo valor muestreado y el valor suavizado existente:

smoothed_value := (1 - alpha) * smoothed_value + alpha * new_value

Por ejemplo, si alfa es 0.20 (20%), entonces tenemos:

smoothed_value = 0.8 * smoothed_value + 0.2 * new_value

En otras palabras, tome el 80% del valor existente y el 20% de la nueva muestra.

Al hacer algo de manipulación algebraica, podemos demostrar que también se puede calcular de esta manera:

smoothed_value := smoothed_value + alpha * (new_value - smoothed_value)

En otras palabras, actualice el valor suavizado agregándole solo la fracción alpha del paso entre este y el nuevo valor.

Si hace todo entero y usa una potencia de dos para alpha o un múltiplo de una potencia de dos, puede hacerlo de manera muy eficiente incluso en procesadores poco sofisticados que no admiten la multiplicación o la división. Por ejemplo, supongamos que queremos hacer alpha 3/16. En C, podemos multiplicar por 3 y dividir por 16 con turnos y adiciones:

delta = new_value - smoothed_value
smoothed_value += ((delta << 1) + delta) >> 4;

Este tipo de suavizado exhibe decaimiento exponencial. Es similar a procesos en la naturaleza como, oh, la forma en que un circuito RC se carga o descarga para rastrear los cambios en el voltaje aplicado.

El parámetro alpha está en el rango [0, 1]. Si es cero, los nuevos valores se ignoran; no hay convergencia Si es 1, entonces smoothed_value no se suaviza en absoluto; sigue new_value al instante. Los valores bajos cercanos a cero proporcionan una convergencia lenta.

Este algoritmo, o algo muy similar, se usa en el protocolo TCP para establecer una base para el tiempo de espera de retransmisión basado en las mediciones del tiempo de ida y vuelta de la conexión.

    
respondido por el Kaz
2

Llama a esto en un intervalo bastante lento:

int ReadValue() {
  static int value = 0;
  int inputValue = ReadAnalogPin();

  if (inputValue > value) value++;
  if (inputValue < value) value--;

  return value;
}
    
respondido por el PkP
0

Al muestrear sistemas ruidosos, es una práctica normal tomar varias muestras y promediarlas. Podría hacer algo similar aquí para evitar que los picos menores en la señal afecten significativamente su medición.

Además de eso, podría mantener un historial de "hitos" de medición con, digamos, un período de 1 segundo. Si este historial de mediciones tuviera un tamaño finito (10 mediciones, quizás), entonces podría presionar su último hito de medición cada segundo y luego tomar un promedio de su historial de mediciones al mismo tiempo. De esta manera, cuando el volumen promedio en la sala se hace cada vez más alto, el valor promedio de su historial de mediciones también será cada vez más grande. Lo contrario sería cierto si la habitación se volviera constantemente más silenciosa.

    
respondido por el Brian J Hoskins
0

Muy útil, gracias a todos. Aquí hay una prueba para cualquier persona en caso de que la necesiten. Rodar la olla afectará lentamente el brillo de un LED:

int sensorPin = A0;  //pot dial to test
int led = 9;

int brightness = 0;
int smooth_return = 0;
int smoothed = 0;
int new_value;

void setup() {
  pinMode(led, OUTPUT);  
  pinMode(sensorPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  smoothed = Smooth(); 
  brightness = map(smoothed, 0, 1023, 0, 255); 
  analogWrite(led, brightness);    

  Serial.print("new smoothed: ");
  Serial.print(smoothed);
  Serial.print(" vs raw data: ");
  Serial.print(new_value);
  Serial.println();                              
} 

int Smooth(){
  new_value = analogRead(A0);

  smooth_return = 0.95 * smooth_return + 0.05 * new_value;
  return smooth_return;
} 
    
respondido por el joshjingles

Lea otras preguntas en las etiquetas