seƱal promedio promediar ponderado movil lecturas filtro estabilizar escalamiento datos captura analogica algorithm sensor smoothing

algorithm - promedio - Suavizar datos de un sensor



promedio de lecturas arduino (5)

Así que vine aquí para resolver el mismo problema (suavizado de entrada del sensor en Android) y esto es lo que se me ocurrió:

/* * time smoothing constant for low-pass filter * 0 ≤ α ≤ 1 ; a smaller value basically means more smoothing * See: http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization */ static final float ALPHA = 0.2f; protected float[] accelVals; public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) accelVals = lowPass( event.values, accelVals ); // use smoothed accelVals here; see this link for a simple compass example: // http://www.codingforandroid.com/2011/01/using-orientation-sensors-simple.html } /** * @see http://en.wikipedia.org/wiki/Low-pass_filter#Algorithmic_implementation * @see http://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter */ protected float[] lowPass( float[] input, float[] output ) { if ( output == null ) return input; for ( int i=0; i<input.length; i++ ) { output[i] = output[i] + ALPHA * (input[i] - output[i]); } return output; }

Gracias a @slebetman por indicarme el enlace de Wikipedia, que después de una pequeña lectura me llevó al algoritmo del artículo de filtro de paso bajo de wikipedia. No juraré que tengo el mejor algoritmo (¡o incluso el correcto!) Pero la evidencia anecdótica parece indicar que está haciendo el truco.

Tengo un sensor 3D que mide datos v (x, y, z). Sólo estoy usando los datos xey. Suavizar sólo xey sería suficiente.

Si uso un registro para mostrar los datos, me muestra algo como esto: (tiempo) 0.1 ... (Registro de datos) x = 1.1234566667 (tiempo) 0.2 ... (Registro de datos) x = 1.1245655666 (tiempo) 0.3. .. (registro de datos) x = 1.2344445555

Bueno, los datos son más exactos en realidad, pero quiero suavizar entre el valor de 1.1234 y el valor de 1.2344, porque para mí es lo mismo, puedo usar números enteros para mostrar solo "x = 1" pero también necesito los decimales. , Necesito mostrar una especie de valor "suavizado" aquí.

Alguien tiene alguna idea? Estoy programando en c # pero no todas las funciones están funcionando, así que necesito crear mi propia función.


Bueno, hay muchas maneras de suavizar los datos del sensor dependiendo de qué tipo de sensor sea y qué analogía se adapte. He usado estos algoritmos en mis proyectos:

  1. Filtro de paso alto [HPF] y filtros de paso bajo [LPF] - como se expresa en la respuesta seleccionada.
  2. Algoritmo de media móvil -MAA
  3. Gaely''s Algorithmm [Mejor versión para MAA]
  4. Transformada rápida de Fourier -FFT

Código:

Filtro de paso alto HPF

private float[] highPass(float x, float y, float z) { float[] filteredValues = new float[3]; gravity[0] = ALPHA * gravity[0] + (1 – ALPHA) * x; gravity[1] = ALPHA * gravity[1] + (1 – ALPHA) * y; gravity[2] = ALPHA * gravity[2] + (1 – ALPHA) * z; filteredValues[0] = x – gravity[0]; filteredValues[1] = y – gravity[1]; filteredValues[2] = z – gravity[2]; return filteredValues; }

Filtro de paso bajo LPF

private float[] lowPass(float x, float y, float z) { float[] filteredValues = new float[3]; filteredValues[0] = x * a + filteredValues[0] * (1.0f – a); filteredValues[1] = y * a + filteredValues[1] * (1.0f – a); filteredValues[2] = z * a + filteredValues[2] * (1.0f – a); return filteredValues; }

Media móvil MAA

private final int SMOOTH_FACTOR_MAA = 2;//increase for better results but hits cpu bad public ArrayList<Float> processWithMovingAverageGravity(ArrayList<Float> list, ArrayList<Float> gList) { int listSize = list.size();//input list int iterations = listSize / SMOOTH_FACTOR_MAA; if (!AppUtility.isNullOrEmpty(gList)) { gList.clear(); } for (int i = 0, node = 0; i < iterations; i++) { float num = 0; for (int k = node; k < node + SMOOTH_FACTOR_MAA; k++) { num = num + list.get(k); } node = node + SMOOTH_FACTOR_MAA; num = num / SMOOTH_FACTOR_MAA; gList.add(num);//out put list } return gList; }


Descubriendo una vieja pregunta aquí, pero si estás en .NET land, puedes usar el RX para hacer esto por ti.

Por ejemplo, usando RX junto con WebClient.DownloadFileAsync para calcular una velocidad de descarga "suavizada":

double interval = 2.0; // 2 seconds long bytesReceivedSplit = 0; WebClient wc = new WebClient(); var downloadProgress = Observable.FromEventPattern< DownloadProgressChangedEventHandler, DownloadProgressChangedEventArgs>( h => wc.DownloadProgressChanged += h, h => wc.DownloadProgressChanged -= h) .Select(x => x.EventArgs); downloadProgress.Sample(TimeSpan.FromSeconds(interval)).Subscribe(x => { Console.WriteLine((x.BytesReceived - bytesReceivedSplit) / interval); bytesReceivedSplit = x.BytesReceived; }); Uri source = new Uri("http://someaddress.com/somefile.zip"); wc.DownloadFileAsync(source, @"C:/temp/somefile.zip");

Obviamente, cuanto más largo sea el intervalo, mayor será el suavizado, pero también más tiempo tendrá que esperar una lectura inicial.


Este es un ejemplo basado en la lógica en la sección MotionEvents de la Guía de Manejo de Eventos para iOS.

float ALPHA = 0.1; protected float[] lowPass( float[] input, float[] output ) { if ( output == null ) return input; for ( int i=0; i<input.length; i++ ) { output[i] = (input[i] * ALPHA) + (ouptut[i] * (1.0 - ALPHA)); } return output; }


Lo más simple es hacer un promedio móvil de sus datos. Es decir, mantener una serie de lecturas de datos de sensores y promediarlas. Algo así (pseudocódigo):

data_X = [0,0,0,0,0]; function read_X () { data_X.delete_first_element(); data_X.push(get_sensor_data_X()); return average(data_X); }

Hay una compensación al hacer esto. Cuanto mayor sea la matriz que utilice, más suave será el resultado, pero mayor será el retraso entre el resultado y la lectura real. Por ejemplo:

//_// /// /_// Sensor reading: __/// /// /// _//___________ // _ __/ /_ ___/ /__ Small array: ___/ /_//_ _ / __/ /________ /_/ ____ __/ /__ __/ /__ Large array: _______/ /__ __ /_ / /__ /_/ (forgive my ASCII-ART but I''m hoping it''s good enough for illustration).

Si desea una respuesta rápida pero una buena suavización, entonces lo que usaría es un promedio ponderado de la matriz. Esto es básicamente un procesamiento de señal digital (con DSP de capital) que, a diferencia de su nombre, está más estrechamente relacionado con el diseño analógico. Aquí hay un breve artículo de wikipedia al respecto (con buenos enlaces externos que deberías leer si quieres seguir este camino): http://en.wikipedia.org/wiki/Digital_filter

Aquí hay un código de SO sobre un filtro de paso bajo que puede satisfacer sus necesidades: ¿Software de filtro de paso bajo? . Tenga en cuenta que en el código de esa respuesta está usando una matriz de tamaño 4 (o un orden 4 en la terminología de procesamiento de señales, ya que dichos filtros se denominan filtros de cuarto orden; en realidad, pueden modelarse mediante una ecuación polinómica de cuarto orden: ax ^ 4 + bx ^ 3 + cx ^ 2 + dx) .