web-dev-qa-db-ja.com

センサーからのデータの平滑化

私は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#でプログラミングしていますが、すべての関数が機能しているわけではないため、独自の関数を作成する必要があります。

24
Mworks

最も簡単なのは、データの移動平均を行うことです。つまり、センサーデータの読み取り値の配列を保持し、それらを平均化します。このようなもの(疑似コード):

  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必要なローパスフィルターについてのコード: ローパスフィルターソフトウェア? のコードを次に示します。この回答のコードでは、配列を使用していることに注意してください。サイズ4の(または信号処理の用語では次数4のようなフィルターは4次フィルターと呼ばれるため、実際には4次多項式でモデル化できます:ax ^ 4 + bx ^ 3 + cx ^ 2 + dx)

65
slebetman

そこで私は同じ問題(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のリンクを教えてくれてありがとう。少し読んだところ、Wikipediaのローパスフィルターに関する記事のアルゴリズムが表示されました。私は最高のアルゴリズムを持っているとは断言しません(あるいは正しいことも!)。

22
thom_nic

センサーデータを平滑化する方法はたくさんありますが、センサーの種類とそれに類する類推によって異なります。私のプロジェクトではこれらのアルゴリズムを使用しました:

  1. ハイパスフィルター[HPF]およびローパスフィルター[LPF]-選択した回答で表現されます。
  2. 移動平均アルゴリズム-MAA
  3. Gaely's 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;
        }
3
Jayant Arora

以下は、iOSの イベント処理ガイド の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;
}
1
rockfakie

ここで古い質問を掘り下げますが、.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");

明らかに間隔が長いほど、平滑化は大きくなりますが、最初の読み取りを待つ時間も長くなります。

0
CatBusStop