|
Усреднение значений энкодера, Как посчитать среднее около нуля? |
|
|
|
Jun 14 2013, 17:33
|

Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 24-04-08
Из: Зеленоград
Пользователь №: 37 056

|
Добрый день! Есть инкрементный энкодер - разрядность 14 бит. Из-за несовершенства механики значения немного дрожат. Примерно на 1-3 значения. Чтобы избавиться от этого вычисляю арифметическое среднее для нескольких измерений. И всё бы хорошо, но в окрестности нуля такой путь не работает. Т.е. имеем набор значений 0, 0, 1, 16383, 0. После усреднения получим 3277 Собственно, вопрос: как лучше всего обойти эту ситуацию? Пока вижу единственный путь - считать обороты и использовать их как старшие биты для значения текущего положения. А потом усреднять. Но может быть есть способ проще? Задача выглядит стандартной, но что-то ничего путного не нагуглилось. Может не так ищу... Заранее спасибо.
|
|
|
|
|
Jun 14 2013, 18:50
|
Частый гость
 
Группа: Свой
Сообщений: 80
Регистрация: 8-12-12
Из: Б.М.
Пользователь №: 74 760

|
может быть что то типа этого код содран от сюдаКод #include<math.h> #include<stdio.h> double meanAngle (double *angles, int size) { double y_part = 0, x_part = 0; int i; for (i = 0; i < size; i++) { x_part += cos (angles[i] * M_PI / 180); y_part += sin (angles[i] * M_PI / 180); } return atan2 (y_part / size, x_part / size) * 180 / M_PI; } int main () { double angleSet1[] = { 350, 10 }; double angleSet2[] = { 90, 180, 270, 360}; double angleSet3[] = { 10, 20, 30}; printf ("\nMean Angle for 1st set : %lf degrees", meanAngle (angleSet1, 2)); printf ("\nMean Angle for 2nd set : %lf degrees", meanAngle (angleSet2, 4)); printf ("\nMean Angle for 3rd set : %lf degrees\n", meanAngle (angleSet3, 3)); return 0; } Output: Mean Angle for 1st set : -0.000000 degrees Mean Angle for 2nd set : -90.000000 degrees Mean Angle for 3rd set : 20.000000 degrees
|
|
|
|
|
Jun 14 2013, 19:17
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(BvDV @ Jun 14 2013, 22:50)  может быть что то типа этого круто! однако, у ТС целочисленные значения, дабл ему не уперся ни в куда (да еще cos с sin, да еще деление...), да и копипастить тут все могут осмыслите, что пишет человек - значения от 0 до 16384. Логический 0 - это около 16384 и 0. Т.е. 3-2-1-0-16384-16383-16382 кстати.. я тут тоже маху дал. не будет моя идея работать.. надо еще подумать  ТС, объясните задачу по-конкретнее. Есть у устройства этот самый "0" или нет, должен ли счет остановиться на этом "0" или спокойно может идти в одну или другую сторону
|
|
|
|
|
Jun 14 2013, 20:00
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(cant @ Jun 14 2013, 23:21)  наиболее просто сделать исключение и принять 2-1-0-16384-16383 за 0. да не должно быть сингулярностей никаких, тогда в районе нуля постоянно будет "прыгать" значение Цитата(cant @ Jun 14 2013, 23:21)  или сделать матрицу на 16383 значений. тогда будет известно с какой стороны приближение к 0. отлично. Отдать 32К контроллера просто под таблицу? (с) Поллитра? Поллитра! Вдребезги? Вдребезги! ДА Я ТЯ!! Кстати. Если это число воспринимать как знаковое, а не как unsigned? Да, точно. Усредняем как знаковое, а результат берем как беззнаковое с той же разрядностью
|
|
|
|
|
Jun 15 2013, 05:54
|
self made
   
Группа: Свой
Сообщений: 855
Регистрация: 7-03-09
Из: Toronto, Canada
Пользователь №: 45 795

|
Код MixedSigns = (V1 | V2 | V3 | V4) ^ (V1 & V2 & V3 & V4) & 0x2000;
If (MixedSigns) { V1 = (V1+0x1000) & 0x3FFF; V2 = (V2+0x1000) & 0x3FFF; V3 = (V3+0x1000) & 0x3FFF; V4 = (V4+0x1000) & 0x3FFF; }; AVG = (V1+V2+V3+V4)>>2; If (MixedSigns) AVG = (AVG - 0x1000) & 0x3FFF; Цитата(toweroff @ Jun 14 2013, 15:00)  Усредняем как знаковое, а результат берем как беззнаковое с той же разрядностью Не получится, вы просто разрыв в другое место передвинули - из 0x3FFF-0 в 0x2FFF-0x3000 Цитата(BvDV @ Jun 14 2013, 13:50)  может быть что то типа этого Жесть.
|
|
|
|
|
Jun 15 2013, 06:43
|

Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 24-04-08
Из: Зеленоград
Пользователь №: 37 056

|
Цитата(toweroff @ Jun 14 2013, 23:17)  ТС, объясните задачу по-конкретнее. Есть у устройства этот самый "0" или нет, должен ли счет остановиться на этом "0" или спокойно может идти в одну или другую сторону Устройство - это энкодер. Ноль, разумеется, есть. Крутиться может в любую сторону. Значение считывается в любой произвольный момент. BvDVВот это близко к тому, что нужно.  Но сложность вычисления убивает. Попробую поискать в этом направлении, может есть более простые способы. Про знаковые-беззнаковые была идея, но это, действительно, только перемещает проблему по оси в другую точку. Про медианную фильтрацию - можно, конечно. Но, неужели, нет более элегантного и простого решения?
|
|
|
|
|
Jun 15 2013, 11:44
|

Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 24-04-08
Из: Зеленоград
Пользователь №: 37 056

|
adnegaСпасибо. Сейчас попробую разобраться. Цитата(Alex11 @ Jun 15 2013, 13:15)  А если по-простому? У Вас же не бывает скачков на четверть оборота? Сначала по первому принятому значению оцениваете квадрант, затем применяете знаковое или беззнаковое усреднение. Должно получиться достаточно компактно. На четверть не бывает. Первое значение и все последующие могут быть в разных квадрантах. Спасибо всем за идеи Краткое резюме: Вариант нахождения среднего угла. В лоб - через синусы с арктангенсами. Алгоритм красивый - не требует введения разнообразных граничных условий и возможность ошибки минимальна. На вычислительная сложность высокая. Наверняка, можно упростить вычисления. Нашёл ветку на stackoverflow http://stackoverflow.com/questions/491738/...a-set-of-anglesразбираюсь. Вариант второй - анализ входных данных и их фильтрация. Вычислительная сложность - низкая. Но вероятность ошибки, и возможность нарваться на такой набор данных, где алгоритм даст ошибку - высока. Так что требуется тщательное тестирование. Буду думать и проверять UPD Нашёл, как эта задача называется по-аглицки. Mean of circular quantities http://en.wikipedia.org/wiki/Mean_of_circular_quantitiesИз обсуждения на SO выбрал следующий код для среднего 2-х значений. Дальше в цикл и готово Код diff = (a-b+24576)%16384-8192; avg = (16384 + b + (diff/2)) % 16384; Прогнал в экселе, вроде всё корректно. Ещё раз всем спасибо.
|
|
|
|
|
Jun 16 2013, 12:19
|
Участник
  
Группа: Свой
Сообщений: 462
Регистрация: 2-04-07
Из: Иркутск
Пользователь №: 26 695

|
Цитата(Fujitser @ Jun 16 2013, 19:14)  Просто используйте числа со знаком. Тогда 16384 преобразуется в -1, и усреднение будет работать. Уже предлагали выше, это не устраняет проблему, а сдвигает её на пол-оборота. Около нуля будет хорошо: -1,0,+1, а середине будет +8191,-8192,-8191, тот же самый скачок на 16384.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|