私は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#でプログラミングしていますが、すべての関数が機能しているわけではないため、独自の関数を作成する必要があります。
最も簡単なのは、データの移動平均を行うことです。つまり、センサーデータの読み取り値の配列を保持し、それらを平均化します。このようなもの(疑似コード):
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)。
そこで私は同じ問題(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のローパスフィルターに関する記事のアルゴリズムが表示されました。私は最高のアルゴリズムを持っているとは断言しません(あるいは正しいことも!)。
センサーデータを平滑化する方法はたくさんありますが、センサーの種類とそれに類する類推によって異なります。私のプロジェクトではこれらのアルゴリズムを使用しました:
コード:
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;
}
以下は、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;
}
ここで古い質問を掘り下げますが、.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");
明らかに間隔が長いほど、平滑化は大きくなりますが、最初の読み取りを待つ時間も長くなります。