2011-01-06 2 views
18

У меня есть 3D-датчик, который измеряет данные v (x, y, z). Я использую только данные x и y. Сглаживания только х и у было бы достаточно.Сглаживание данных с датчика

Если я использую журнал для отображения данных, он показывает мне что-то вроде этого: (время) 0,1 ... (журнал данных) х = 1,1234566667 (время) 0,2 ... (Журнал данных) х = 1.1245655666 (время) 0,3 ... (журнал данных) x = 1.2344445555

Ну, данные точнее, но я хочу сгладить между значением 1.1234 и значением 1.2344, потому что для меня это то же самое, я может использовать целые числа, показывая только «x = 1», но мне тоже нужны десятичные знаки, тогда мне нужно показать своеобразное «сглаженное» значение здесь.

У кого-нибудь есть идеи? Я программирую в C#, но не все функции работают, поэтому мне нужно создать свою собственную функцию.

ответ

56

Проще всего сделать скользящее среднее ваших данных. То есть хранить массив данных датчиков и усреднять их. Что-то вроде этого (псевдокод):

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); 
    } 

При этом возникает компромисс. Чем больше массив, который вы используете, тем более гладким будет результат, но чем больше отставание между результатом и фактическим показанием. Например:

      /\_/\ 
         /\/  \_/\ 
    Sensor reading: __/\/   \/\ 
             \/\ _/\___________ 
              \/ 
           _ 
          __/ \_ 
         ___/  \__ 
    Small array:  ___/    \_/\_  _ 
             \ __/ \________ 
              \_/ 

           ____ 
           __/ \__ 
          __/   \__ 
    Large array:  _______/     \__  __ 
               \_ /\__ 
               \_/ 


(forgive my ASCII-ART but I'm hoping it's good enough for illustration). 

Если вы хотите быстрый ответ, но хорошее сглаживание в любом случае, то, что вы будете использовать это взвешенное среднее значение массива. Это в основном цифровая обработка сигналов (с капиталом DSP), которая вопреки ее названию более тесно связана с аналоговым дизайном. Вот короткая статья о википедии об этом (с хорошими внешними ссылками, которые вы должны прочитать, если вы хотите пойти по этому пути): http://en.wikipedia.org/wiki/Digital_filter

Вот несколько кодов от SO об фильтре нижних частот, который может подходить вашим потребностям: Low pass filter software?. Обратите внимание, что в коде в этом ответе он использует массив размером 4 (или заказать 4 в терминологии обработки сигналов, поскольку такие фильтры называются фильтром четвертого порядка, он может быть фактически смоделирован с помощью уравнения многочлена 4-го порядка: ax^4 + bx^3 + cx^2 + dx).

+0

Большое спасибо !!! Это действительно помогло мне, сейчас я реализую код, теперь я буду помогать людям, как и вы, ну, если можно, конечно. Thax !! – Mworks

+3

Фильтр скользящей средней является частным случаем фильтра нижних частот, который является довольно мутным фильтром (с точки зрения производительности). Фильтр нижних частот первого порядка часто (обычно?) Лучше, чем скользящие средние с точки зрения частотной характеристики и вычислительной нагрузки и сложности программ. Для многих приложений вы можете игнорировать эти данные, например, дисплей компаса, который может реагировать медленно, скользящее среднее будет большим. Если у вас есть игра, в которой вы хотите быстро реагировать с помощью шумных датчиков, скользящая средняя будет плохим решением из-за задержки, которую она несет за определенный объем фильтрации. – Hucker

+12

Отличный ответ, сделанный ASCII art – Spaceghost

21

Так что я пришел сюда в поисках решения той же задачи (вход датчика сглаживания в Android), и вот что я придумал:

/* 
* 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; 
} 

Спасибо @slebetman указал мне к ссылке Википедии, которая после небольшое чтение привлекло меня к алгоритму в статье фильтра нижних частот wikipedia. Я не буду поклясться, что у меня есть лучший алгоритм (или даже правый!), Но, по-видимому, некоторые факты свидетельствуют о том, что он делает трюк.

+1

просто хотел скажем, что если вы используете этот код на android, сначала возвращайте input.copy() вместо самого массива. Мой сенсор записывает в тот же массив, т. Е. Ввод и вывод - это один и тот же массив, и сглаживание не будет работать. –

0

Здесь вы можете найти старый вопрос, но если вы работаете в .NET, вы можете использовать RX для этого.

Например, при использовании RX в сочетании с WebClient.DownloadFileAsync для расчета «сглаженный» скорость загрузки:

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"); 

Очевидно, что чем больше интервал, тем больше сглаживание будет, но чем дольше вы будете придется дождаться начального чтения.

1

Вот пример, основанный на логике в разделе MotionEvents для Event Handling guide для 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; 
} 
3

Ну, есть много способов сгладить данные датчиков, зависит от того, какой датчик он и какая аналогия подойдет. Я использовал эти алгоритмы в своих проектах:

  1. High Pass Filter [HPF] и Low Pass Filters [LPF] - выраженное в выбранном ответе.
  2. Moving Average алгоритм -MAA
  3. Algorithmm Gaely в [Лучше версия для MAA]
  4. быстрое преобразование Фурье -FFT

Код:

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; 
    } 

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; 
    } 

MAA-Moving Average

 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; 
     } 
Смежные вопросы