Cómo asignar un valor ADC de 10 bits a un rango con restricciones

Necesito asignar un ADC de 10 bits, es decir, [0-1023] a un rango [1-100]. La fórmula de mapeo en sí es la directa "y=(xa)/(ba)*(dc)+c" para mapear x en [ab] a y en [cd].

La entrada x se calcula como el promedio de, por ejemplo, 1000 lecturas de ADC.

Mi problema es este. La entrada a ADC es un potenciómetro y necesito calcular x SOLAMENTE cuando el potenciómetro está estacionario. ¿Cómo detectas esto? La forma en que lo estoy haciendo actualmente es leer conjuntos de 1000 valores ADC (en un temporizador), calcular su promedio y comparar el "promedio actual" con el "promedio anterior". Si "promedio actual - promedio anterior" es algo "+-delta", asumo que el potenciómetro está estacionario y hago el cálculo.

¿Hay una mejor manera de hacer esto?

Editar: para proporcionar más datos;

  • Estoy usando un MCU C8051F850 de SiLabs que funciona a 24,5 MHz
  • Las muestras de ADC se recogen cada 100us
  • Se calcula un promedio de 2500 muestras ~ 250 ms por conjunto. Por lo tanto, se comparan dos promedios cada 500 ms.
  • Mi "delta" es de 10 unidades (aprox. de 1024/100)
  • Aritmética entera, por lo tanto, errores de redondeo.
No entiendo qué tiene que ver el rango y la ecuación con el problema. Tal vez debería eliminarlo y concentrarse en su problema real aquí. Sin embargo , creo que el problema real al que te enfrentas es algún tipo de problema XY .
@pipe: presenté el problema completo y mi solución actual para que todo el contexto sea claro. Funciona, pero no estoy contento con él y de ahí mi pregunta. Si hay algo en especifico que te gustaria que te aclare?
usar filtro de paso bajo de software

Respuestas (2)

Esto es 'prueba de hipótesis en presencia de ruido'.

Cuando estamos probando hipótesis, definimos un par de condiciones entre las que queremos discriminar, luego definimos una prueba para hacerlo mejor.

Ha definido una condición 'es estacionario' y una prueba |(current_avg - before_avg)| <delta. Implícito en esa definición hay otras dos condiciones, subir y bajar.

Si bien la definición de 'es estacionario' no está bien definida, si aplicamos ingeniería inversa a la prueba que ideó para averiguar qué significa realmente, el cambio en la posición promedio entre los primeros 1000 y los siguientes 1000 de una muestra larga de 2000 de posiciones, encontramos que es algo bastante razonable de hacer.

El promedio de 1000 muestras es la mejor manera de calcular una posición promedio, si asumimos que el ruido en cada muestra es independiente. También es rápido, usa pocos recursos, es fácil de entender y usa poca memoria (no necesita almacenar todas las entradas).

La diferencia entre el primer y el segundo set te da la mejor estimación de la velocidad media del bote durante ese tiempo.

Ahora considere este caso de prueba. Para las primeras 1000 muestras, el bote sube rápidamente, para las siguientes 1000 baja rápidamente. El movimiento medio durante ese período, calculado por su estimador, será cero.

¿Está contento de que esta condición se detecte como estacionaria? Si no, entonces tenemos que cambiar nuestra definición de estacionario. Según tu comentario, no estás contento con algo. ¿Pero que?

Como puede ver, el problema no está en la prueba en sí, sino en (a) su pobre definición de lo que significa 'estacionario' y (b) su pobre definición de lo que encuentra insatisfactorio sobre el desempeño de la presente prueba.

La prueba que ha definido es la prueba más razonable que existe para detectar la velocidad promedio en presencia de ruido. Si esto funciona bien con la física del mundo real y el comportamiento del usuario es otra cuestión.

Si encuentra que realmente necesita detectar la aceleración, para mejorarla en su caso, entonces es bastante fácil tomar tres muestras promediadas sucesivas, calcular ambos deltas y luego calcular el delta-delta.

Si encuentra que un cambio de tamaño promedio, para cambiar la velocidad a la que puede detectar cambios, funciona mejor, entonces hágalo.

Existen otras alternativas que ponen a prueba diferentes hipótesis. El primero sería calcular dos medias de ejecución con diferentes constantes de tiempo. Este es un filtro común para usar como detector de bordes en el procesamiento de imágenes, pero también detectará "bordes" en datos unidimensionales. Como los filtros son recursivos, esto es bastante barato de implementar. Sin embargo, tendría que ajustar las dos constantes de tiempo a su situación, entonces, ¿cómo podría ajustarlas mejor que la única constante de tiempo de su probador actual?

El segundo es hacer una FFT de sus muestras. Luego puede comparar la energía en el contenedor de CC (cantidad de estacionario) con la energía en los contenedores de baja frecuencia (cantidad de movimiento, aceleración, cambio de aceleración...) mientras descarta la energía en los contenedores de alta frecuencia (ruido de lectura) . Pero eso necesita una cantidad significativa de memoria y poder de procesamiento, y parece una exageración.

Un tercero, basado en su comentario acerca de que la latencia es el problema, sería estimar simultáneamente la posición yla pendiente de la línea por regresión lineal. Hay una fórmula recursiva para esto, por lo que es relativamente eficiente calcular en tiempo real sin más memoria. Esto le permitiría 'corregir' el retraso en la recopilación de datos extrapolando ambas estimaciones para obtener la posición promediada 'ahora'. Tenga en cuenta que la regresión lineal puede tener problemas de rango dinámico si se realiza para grandes conjuntos de datos, y como está utilizando aritmética de enteros, debe pensar detenidamente sobre la implementación. Una forma de mejorar las cosas sería diezmar y ejecutar la regresión lineal a una frecuencia de muestreo mucho más baja, más consistente con la velocidad a la que se mueve el bote del mundo real y el tiempo de respuesta que desea que tenga el programa.

¡Gran explicación! Gracias. Mi problema es que cuando el bote se mueve hacia abajo (es decir, obtengo valores de 1023 hacia abajo) frente a cuando el bote se mueve hacia arriba (es decir, obtengo valores de 0 en adelante), el promedio estará sesgado hacia los extremos superior o inferior. Esto se magnificará si la persona gira la olla muy rápidamente. ¿Cómo elimino este sesgo? Un enfoque es usar la prueba anterior para detectar "estacionario", descartar ambos promedios, recopilar y usar un nuevo conjunto de promedios (digamos más de 100 ms) y usarlo como entrada x. Obviamente, esto agrega más latencia a mi tiempo de respuesta que me gustaría evitar si es posible.
Edité mi publicación original con algunos datos más.
@RamanathanR su edición OP parece no agregar nada relevante, pero su comentario anterior sugiere que la latencia es el problema. He actualizado mi pregunta para abordar esto en el último párrafo. También puede considerar reducir la frecuencia de muestreo a algo más acorde con los tiempos de respuesta deseados con un filtro lineal y hacer cosas "inteligentes" a una frecuencia de muestreo mucho más baja. Esto dividirá bien el problema y dará como resultado una mejor implementación. Los detalles están más allá de una discusión en este foro, pero podemos hablar fuera de línea si desea ayuda detallada.

Promediar hace algunas cosas; y hay mejores maneras.

  1. Agrega latencia = n * intervalo de muestra
  2. Reduce el jitter aleatorio en Vpp/ norte
  3. Actúa como un primer filtro de paso bajo, donde un filtro ponderado puede tener el mismo ancho de banda de ruido con faldas más pronunciadas y un retraso de grupo más bajo (latencia) al igual que los filtros activos.

  4. Puede causar errores de aliasing si las señales exceden la frecuencia de Nyquist antes de promediar, por lo que se necesita un poco de filtrado, pero un filtro de pared de ladrillo de >=5to orden es mejor para una latencia baja, que es esencialmente valores de ponderación para promediar.

  5. Si espera a que esté inactivo y el potenciómetro tiene un ruido de oscilación debido a la vibración, agregará una latencia excesiva.

  6. Si diseña un promedio ponderado continuo diferente, puede optimizar el retraso de grupo y el error de movimiento utilizando parámetros como un filtro de Kalman. Esto se utiliza en GPS y otros sensores de posición de movimiento, velocidad y aceleración.

6b. ... como @Neil_UK sugirió que puede hacer una FFT en los valores (o exportar y analizar), entonces podría usar un filtro coincidente en la señal fundamental (tasa de respuesta 10 ~ 90% = tR = 0.35 / f-3dB) en orden para rechazar el ruido usando valores de ponderación en promedios itinerantes.

  1. Puede usar un peso de velocidad por la diferencia media en los valores para predecir la posición debido a la latencia y llegar a un resultado uniforme con menos retraso. Luego, puede reducir la cantidad de muestras necesarias para diezmar (reducir la resolución) a valores del 1% (0 ~ 99)

Dejo el algoritmo de diezmado para que otros lo describan, que es álgebra básica.

PD: usaría un codificador de cuadratura incremental con retenes en lugar de un potenciómetro, para esta aplicación como se usa en los sistemas modernos.

Gracias por todas las ideas. Tengo mucho en lo que pensar (y leer) :-)