2011-01-06 114 views
18

我有一個測量v(x,y,z)數據的3D傳感器。我只使用x和y數據。僅平滑x和y就足夠了。 (時間)0.1 ...(數據記錄)x = 1.1234566667 (時間)0.2 ...(數據記錄)x = 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

下面是關於低通濾波器的一些代碼,它可能適合你的需求:Low pass filter software?。請注意,在該答案的代碼中,他使用了一個大小爲4 (或信號處理術語中的4階數組),因爲這樣的濾波器稱爲四階濾波器,實際上它可以用四階多項式方程建模:ax^4 + bx^3 + cx^2 + dx)

+0

非常感謝您!這真的對我有幫助,我現在正在執行代碼,從現在開始,我會幫助像你一樣的人,當然,如果我能的話。 Thax! – Mworks 2011-01-07 00:20:52

+3

移動平均濾波器是低通濾波器的一種特殊情況,它是非常不好的濾波器(就性能而言)。一階低通濾波器通常(通常?)比頻率響應和計算負荷以及程序複雜度方面的移動平均更好。 對於很多應用程序,您可以忽略這些細節,例如可以緩慢響應的指南針顯示,移動平均值會非常好。如果你有一個需要使用噪聲傳感器進行快速響應的遊戲,那麼移動平均值將是一個不好的解決方案,因爲對於給定的濾波量,它會產生滯後。 – Hucker 2011-10-05 14:55:19

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指着我向維基百科的鏈接,該鏈接後一點點閱讀吸引了我對維基百科低通濾波器文章的算法。我不會發誓我擁有最好的算法(甚至是對的!),但傳聞證據似乎表明它正在訣竅中。

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

下面是基於iOS的Event Handling guide的MotionEvents部分中邏輯的示例。

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. 高通濾波器[HPF]和低通濾波器[LPF] - 在所選擇的答案表示。
  2. 移動平均算法-MAA
  3. Gaely的Algorithmm [爲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移動平均

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