Сглаживание данных с датчика
У меня есть 3D-датчик, который измеряет данные v (x, y, z). Я использую только данные x и y. Сглаживания только х и у было бы достаточно.
Если я использую журнал для отображения данных, он показывает мне что-то вроде этого:
(время) 0,1... (журнал данных) x = 1.1234566667
(время) 0,2... (журнал данных) x = 1.1245655666
(время) 0,3... (журнал данных) x = 1.2344445555
Ну, данные точнее, но я хочу сгладить между значением 1.1234 и значением 1.2344, потому что для меня это то же самое, я могу использовать целые числа, показывая только "x = 1", но мне нужны десятичные знаки тоже, тогда, мне нужно показать своеобразное "сглаженное" значение здесь.
У кого-нибудь есть идея? Я программирую в С#, но не все функции работают, поэтому мне нужно создать свою собственную функцию.
Ответы
Ответ 1
Проще всего сделать скользящее среднее ваших данных. То есть хранить массив данных датчиков и усреднять их. Что-то вроде этого (псевдокод):
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 good enough for illustration).
Если вам нужен быстрый ответ, но хороший сглаживание в любом случае, то то, что вы будете использовать, является средневзвешенным значением массива. Это в основном цифровая обработка сигналов (с капиталом DSP), которая вопреки его названию более тесно связана с аналоговым дизайном. Здесь короткая статья о википедии (с хорошими внешними ссылками, которые вы должны прочитать, если хотите пойти по этому пути): http://en.wikipedia.org/wiki/Digital_filter
Вот некоторый код из SO о низкочастотном фильтре, который может удовлетворить ваши потребности: Программное обеспечение фильтра низких частот?. Обратите внимание, что в коде в этом ответе он использует массив размером 4 (или порядок 4 в терминологии обработки сигналов, потому что такие фильтры называются фильтром четвертого порядка, он может быть фактически смоделирован с помощью полиномиального уравнения 4-го порядка: ax ^ 4 + bx ^ 3 + cx ^ 2 + dx).
Ответ 2
Итак, я пришел сюда, чтобы решить ту же проблему (сглаживание сенсора ввода в 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 за то, что указали мне на ссылку в Википедии, которая после небольшого чтения привлекла меня к алгоритму в статье с фильтром нижних частот википедии. Я не буду поклясться, что у меня есть лучший алгоритм (или даже правый!), Но, по-видимому, некоторые свидетельства указывают на то, что он делает трюк.
Ответ 3
Ну, есть много способов сгладить данные датчиков, зависит от того, какой датчик он и какая аналогия подойдет.
Я использовал эти алгоритмы в своих проектах:
- Фильтр высоких частот [HPF] и фильтры низких частот [LPF] - как указано в выбранном ответе.
- Алгоритм скользящего среднего -MAA
- Gaely Algorithmm [Лучшая версия для MAA]
- Быстрое преобразование Фурье -FFT
код:
Фильтр HPF-High Pass
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;
}
Ответ 4
Вот пример, основанный на логике в разделе MotionEvents в Руководстве по обработке событий для 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;
}
Ответ 5
Выкалывайте старый вопрос здесь, но если вы находитесь в среде .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");
Очевидно, чем дольше интервал, тем больше будет сглаживание, но и дольше вам придется ждать начального чтения.