Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Android Compass orientación en poco fiable (filtro de paso bajo)

Estoy creando una aplicación donde necesito colocar un ImageView dependiendo de la orientación del dispositivo. Utilizo los valores de un Sensor MagneticField y Acelerómetro para calcular la orientación del dispositivo con

SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerValues, magneticFieldValues) SensorManager.getOrientation(rotationMatrix, values); double degrees = Math.toDegrees(values[0]); 

Mi problema es que el posicionamiento del ImageView es muy sensible a los cambios en la orientación. Haciendo que la vista de la imagen salte constantemente por la pantalla. (porque los grados cambian)

He leído que esto puede ser porque mi dispositivo está cerca de cosas que pueden afectar las lecturas del campo magnético. Pero esta no es la única razón que parece.

Intenté descargar algunas aplicaciones y encontré que la " brújula 3D " y la " brújula " permanecen extremadamente constantes en sus lecturas (al fijar el filtro de ruido para arriba), quisiera el mismo comportamiento en mi uso.

He leído que puedo ajustar el "ruido" de mis lecturas mediante la adición de un " filtro de paso bajo ", pero no tengo idea de cómo implementar esto (debido a mi falta de matemáticas).

Im que espera alguien puede ayudarme a crear una lectura más constante en mi dispositivo, donde un poco movimiento al dispositivo no afectará a la orientación actual. Ahora hago un pequeño

 if (Math.abs(lastReadingDegrees - newReadingDegrees) > 1) { updatePosition() } 

Para filtrar un poco del ruido. Pero no funciona muy bien 🙂

5 Solutions collect form web for “Android Compass orientación en poco fiable (filtro de paso bajo)”

Aunque no he utilizado la brújula en Android, el procesamiento básico que se muestra a continuación (en JavaScript) probablemente funcione para usted.

Se basa en el filtro de paso bajo en el acelerómetro recomendado por el equipo de Windows Phone con modificaciones para adaptarse a una brújula (el comportamiento cíclico cada 360 ").

Supongo que la lectura de la brújula es en grados, un flotador entre 0-360, y la salida debe ser similar.

Desea realizar 2 cosas en el filtro:

  1. Si el cambio es pequeño, para evitar gitter, gire gradualmente hacia esa dirección.
  2. Si el cambio es grande, para evitar el retraso, gire inmediatamente hacia esa dirección (y puede cancelarse si desea que la brújula se mueva sólo de una manera suave).

Para eso tendremos 2 constantes:

  1. El flotador de relajación que define la suavidad del movimiento será (1 no hay suavizado y 0 nunca se está actualizando, mi valor predeterminado es 0,5). Lo llamaremos SmoothFactorCompass.
  2. El umbral en el que la distancia es lo suficientemente grande como para girar inmediatamente (0 es saltar siempre, 360 nunca salta, mi valor predeterminado es 30). Lo llamaremos SmoothThresholdCompass.

Tenemos una variable guardada a través de las llamadas, un flotador llamado oldCompass y es el resultado del algoritmo.

Así que la variable defenition es:

 var SmoothFactorCompass = 0.5; var SmoothThresholdCompass = 30.0; var oldCompass = 0.0; 

y la función recibe newCompass, y devuelve oldCompass como el resultado.

 if (Math.abs(newCompass - oldCompass) < 180) { if (Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) { oldCompass = newCompass; } else { oldCompass = oldCompass + SmoothFactorCompass * (newCompass - oldCompass); } } else { if (360.0 - Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) { oldCompass = newCompass; } else { if (oldCompass > newCompass) { oldCompass = (oldCompass + SmoothFactorCompass * ((360 + newCompass - oldCompass) % 360) + 360) % 360; } else { oldCompass = (oldCompass - SmoothFactorCompass * ((360 - newCompass + oldCompass) % 360) + 360) % 360; } } } 

Veo que el tema se abrió hace 5 meses y probablemente ya no es relevante, pero estoy seguro de que otros programadores podrían encontrarlo útil.

Oded Elyada.

Este filtro de paso bajo funciona para ángulos en radianes. Utilice la función add para cada lectura de la brújula, luego llame al promedio para obtener el promedio.

 public class AngleLowpassFilter { private final int LENGTH = 10; private float sumSin, sumCos; private ArrayDeque<Float> queue = new ArrayDeque<Float>(); public void add(float radians){ sumSin += (float) Math.sin(radians); sumCos += (float) Math.cos(radians); queue.add(radians); if(queue.size() > LENGTH){ float old = queue.poll(); sumSin -= Math.sin(old); sumCos -= Math.cos(old); } } public float average(){ int size = queue.size(); return (float) Math.atan2(sumSin / size, sumCos / size); } } 

Utilice Math.toDegrees() o Math.toRadians() para convertir.

Tenga en cuenta que, por ejemplo, el promedio de 350 y 10 no es 180. Mi solución:

 int difference = 0; for(int i= 1;i <numberOfAngles;i++){ difference += ( (angles[i]- angles[0] + 180 + 360 ) % 360 ) - 180; } averageAngle = (360 + angles[0] + ( difference / numberOfAngles ) ) % 360; 

Un filtro de paso bajo (LPF) bloquea las señales de cambio rápido y
permite sólo cambios lentos en las señales. Esto significa que cualquier pequeño
los cambios repentinos serán ignorados.

La forma estándar de implementar esto en software es tomar un promedio de funcionamiento
de las últimas N muestras e informar ese valor. Comience con N tan pequeño como 3 y
siga aumentando N hasta que encuentre suficiente respuesta suavizada en su aplicación.

Tenga en cuenta que cuanto más alto hagas N, más lenta será la respuesta del sistema.

Vea mi respuesta a esta pregunta relacionada: Suavizar datos de un sensor

Un filtro de paso bajo de software es básicamente una versión modificada de eso. De hecho, en esa respuesta incluso proporcioné este enlace a otra pregunta relacionada: ¿Software de filtro de paso bajo?

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.