Усреднение углов... Опять
Я хочу вычислить среднее значение из набора углов, который представляет исходный азимут (от 0 до 360 градусов) - (аналогично направлению ветра)
Я знаю, что это обсуждалось ранее (несколько раз). Принятым ответом было вычислить единичные векторы по углам и взять угол их среднего.
Однако этот ответ определяет среднее не интуитивным способом. Среднее значение 0, 0 и 90 будет atan( (sin(0)+sin(0)+sin(90)) / (cos(0)+cos(0)+cos(90))) = atan(1/2)= 26,56 град
Я ожидаю, что среднее значение 0, 0 и 90 будет 30 градусов.
Поэтому я думаю, что было бы справедливо задать вопрос еще раз: как бы вы рассчитали среднее значение, поэтому такие примеры дадут интуитивный ожидаемый ответ.
Изменить 2014:
Задав этот вопрос, я разместил статью о CodeProject, в которой предлагается тщательный анализ. В статье рассматриваются следующие справочные задачи:
- Приведенное время суток [00:00-24:00) для каждого рождения, произошедшего в США в 2000 году. Рассчитать среднее время рождения при рождении.
- При наличии множества измерений направления от стационарного передатчика к стационарному приемнику с использованием методики измерения с обернутой нормальной распределенной ошибкой - оцените направление.
- Учитывая мультимножество оценок азимута между двумя точками, сделанных "обычными" людьми (при условии, что они подверглись усеченной усеченной нормальной распределенной ошибке) - Оцените направление.
13 ответов
Спасибо всем за то, что помогли мне увидеть мою проблему более четко.
Я нашел то, что искал. Это называется метод Мицуты.
Входы и выходы находятся в диапазоне [0..360).
Этот метод хорош для усреднения данных, которые были отобраны с использованием постоянных интервалов выборки.
В этом методе предполагается, что разница между последовательными выборками составляет менее 180 градусов (что означает, что если мы не будем производить выборку достаточно быстро, изменение дискретизированного сигнала на 330 градусов будет неправильно определено как изменение на 30 градусов в другом направлении и будет вставить ошибку в расчет). Теорема отсчетов Найквиста – Шеннона?
Вот код C++:
double AngAvrg(const vector<double>& Ang)
{
vector<double>::const_iterator iter= Ang.begin();
double fD = *iter;
double fSigD= *iter;
while (++iter != Ang.end())
{
double fDelta= *iter - fD;
if (fDelta < -180.) fD+= fDelta + 360.;
else if (fDelta > 180.) fD+= fDelta - 360.;
else fD+= fDelta ;
fSigD+= fD;
}
double fAvrg= fSigD / Ang.size();
if (fAvrg >= 360.) return fAvrg -360.;
if (fAvrg < 0. ) return fAvrg +360.;
return fAvrg ;
}
Это объясняется на странице 51 по адресу http://www.epa.gov/scram001/guidance/met/mmgrma.pdf
Спасибо Маре за отправку ссылки в качестве комментария.
Если данные выборки являются постоянными, но наше устройство для выборки имеет неточность с распределением фон Мизеса, будет уместным вычисление единичных векторов.
[Обратите внимание, что вопрос ОП (но не заголовок), по-видимому, изменился на довольно специализированный вопрос ("... среднее ПОСЛЕДОВАТЕЛЬНОСТИ углов, где каждое последующее сложение не отличается от скользящего среднего более чем на определенную величину".) - см. @MaR комментарий и мой.Мой следующий ответ касается названия ОП и основной части обсуждения и ответов, связанных с ним.]
Это не вопрос логики или интуиции, а определения. Это обсуждалось на SO раньше без какого-либо реального консенсуса. Углы должны быть определены в пределах диапазона (который может быть от -PI до +PI, или от 0 до 2*PI или может быть от -Inf до +Inf. Ответы будут разными в каждом случае.
Мир "угол" вызывает путаницу, поскольку это означает разные вещи. Угол зрения представляет собой величину без знака (и обычно это PI > theta > 0. В этом случае могут быть полезны "нормальные" средние значения. Угол поворота(например, общее вращение, если фигуристка) может или не может быть подписан и может включать в себя тета> 2* пи и тета <-2 * пи.
Здесь определяетсяугол = направление, для которого требуются векторы. Если вы используете слово "направление" вместо "угол", вы поймете намерение ОП (кажущийся оригинальным), и это поможет отойти от скалярных величин.
Википедия показывает правильный подход, когда углы определяются кругово, так что
theta = theta+2*PI*N = theta-2*PI*N
Ответом для среднего является НЕ скаляр, а вектор. ОП может не чувствовать, что это интуитивно понятно, но это единственный полезный правильный подход. Мы не можем переопределить квадратный корень из -4, чтобы он был равен -2, потому что это более наглядно - это должно быть +-2*i. Точно так же среднее значение подшипников -90 градусов и +90 градусов - это вектор нулевой длины, а не 0,0 градусов.
Википедия ( http://en.wikipedia.org/wiki/Mean_of_circular_quantities) имеет специальный раздел и состояния (Уравнения LaTeX и их можно увидеть в Википедии):
Большинство обычных средних значений терпят неудачу на круглых величинах, таких как углы, дневное время, дробные части действительных чисел. Для этих величин вам нужно среднее значение круговых величин.
Поскольку среднее арифметическое не является эффективным для углов, можно использовать следующий метод для получения как среднего значения, так и показателя дисперсии углов:
Переведите все углы в соответствующие точки на единичной окружности, например, α в (cosα,sinα). То есть конвертировать полярные координаты в декартовы. Затем вычислите среднее арифметическое этих точек. Полученная точка будет лежать на диске устройства. Переведите эту точку обратно в полярные координаты. Угол является разумным средним из входных углов. Результирующий радиус будет 1, если все углы равны. Если углы равномерно распределены по окружности, то результирующий радиус будет равен 0, а круговое среднее отсутствует. Другими словами, радиус измеряет концентрацию углов.
Учитывая углы \alpha_1,\dots,\alpha_n, среднее значение вычисляется как
M \alpha = \operatorname{atan2}\left(\frac{1}{n}\cdot\sum_{j=1}^n
\sin\alpha_j, \frac{1}{n}\cdot\sum_{j=1}^n \cos\alpha_j\right)
используя вариант функции арктангенса atan2, или
M \alpha = \arg\left(\frac{1}{n}\cdot\sum_{j=1}^n
\ Ехр (\ CDOT \alpha_j)\ справа)
используя комплексные числа.
Обратите внимание, что в вопросе OP угол 0 является чисто произвольным - нет ничего особенного в том, что ветер приходит от 0, а не к 180 (за исключением того, что в этом полушарии на велосипеде холоднее). Попробуйте изменить 0,0,90 на 289, 289, 379 и посмотрите, как простая арифметика больше не работает.
(Есть некоторые распределения, где углы 0 и PI имеют особое значение, но они здесь не входят в объем).
Вот некоторые интенсивные предыдущие обсуждения, которые отражают текущее распространение взглядов:-)
http://mathforum.org/library/drmath/view/53924.html
Как вы рассчитываете среднее значение для набора циклических данных?
Что это вообще значит для среднего источника подшипников? Начните с ответа на этот вопрос, и вы приблизитесь к тому, чтобы определить, что вы подразумеваете под средним углом.
На мой взгляд, угол с касательной, равной 1/2, является правильным ответом. Если у меня есть единичная сила, толкающая меня в направлении вектора (1, 0), другая сила, толкающая меня в направлении вектора (1, 0), и третья сила, толкающая меня в направлении вектора (0, 1).), то результирующая сила (сумма этих сил) - это сила, толкающая меня в направлении (1, 2). Это векторы, представляющие подшипники 0 градусов, 0 градусов и 90 градусов. Угол, представленный вектором (1, 2), имеет касательную, равную 1/2.
Отвечая на ваше второе редактирование:
Допустим, мы измеряем направление ветра. Наши 3 измерения были 0, 0 и 90 градусов. Поскольку все измерения одинаково надежны, почему наша лучшая оценка направления ветра не должна составлять 30 градусов? установка его на 25,56 градусов - это смещение в сторону 0...
Хорошо, вот проблема. Единичный вектор с углом 0 не обладает такими же математическими свойствами, как действительное число 0. Использование обозначений 0v
чтобы представить вектор с углом 0, обратите внимание, что
0v + 0v = 0v
ложно, но
0 + 0 = 0
верно для реальных чисел. Так что если 0v
представляет ветер с единичной скоростью и углом 0, то 0v + 0v
ветер с удвоенной единицей скорости и углом 0. А потом, если у нас есть третий вектор ветра (который я буду представлять с помощью обозначения 90v
), который имеет угол 90 и единичную скорость, то ветер, возникающий из суммы этих векторов, имеет уклон, потому что он движется с удвоенной частотой вращения в горизонтальном направлении, но только с единичной скоростью в вертикальном направлении.
Это неверно на каждом уровне.
Векторы добавляются в соответствии с правилами сложения векторов. "Интуитивный, ожидаемый" ответ может быть не таким интуитивным.
Возьмите следующий пример. Если у меня есть один единичный вектор (1, 0) с источником в (0,0), который указывает в направлении +x, и другой (-1, 0), который также имеет начало в (0,0), который указывает в -x-направление, каким должен быть "средний" угол?
Если я просто добавлю углы и разделю на два, я могу утверждать, что "среднее" составляет либо +90, либо -90. Как вы думаете, какой из них должен быть?
Если я добавлю векторы в соответствии с правилами сложения векторов (компонент за компонентом), я получу следующее:
(1, 0) + (-1, 0) = (0, 0)
В полярных координатах это вектор с нулевой величиной и нулевым углом.
Так каким должен быть "средний" угол? У меня есть три разных ответа для простого случая.
Я думаю, что ответ заключается в том, что векторы не подчиняются той же интуиции, что и числа, потому что они имеют величину и направление. Может быть, вам лучше описать, какую проблему вы решаете.
Какое бы решение вы ни выбрали, я бы посоветовал вам основывать его на векторах. Так будет всегда правильно.
На мой взгляд, речь идет об углах, а не векторах. По этой причине среднее значение 360 и 0 действительно равно 180. Среднее значение за один оборот и без поворотов должно быть половиной оборота.
Изменить: Эквивалентный, но более надежный алгоритм (и более простой):
- разделить углы на 2 группы, [0-180) и [180-360)
- численно среднее значение обеих групп
- усредните 2 средних по группе с правильным взвешиванием
- если произошло завертывание, исправить на 180˚
Это работает, потому что усреднение чисел работает "логически", если все углы находятся в одном и том же полукруге. Затем мы откладываем получение ошибки обтекания до самого последнего шага, где ее легко обнаружить и исправить. Я также добавил некоторый код для обработки случаев с противоположными углами. Если средние значения противоположны, мы отдаем предпочтение полусфере, в которой было больше углов, а в случае равных углов в обоих полушариях мы возвращаемся None
потому что никакой средний не будет иметь смысла.
Новый код:
def averageAngles2(angles):
newAngles = [a % 360 for a in angles];
smallAngles = []
largeAngles = []
# split the angles into 2 groups: [0-180) and [180-360)
for angle in newAngles:
if angle < 180:
smallAngles.append(angle)
else:
largeAngles.append(angle)
smallCount = len(smallAngles)
largeCount = len(largeAngles)
#averaging each of the groups will work with standard averages
smallAverage = sum(smallAngles) / float(smallCount) if smallCount else 0
largeAverage = sum(largeAngles) / float(largeCount) if largeCount else 0
if smallCount == 0:
return largeAverage
if largeCount == 0:
return smallAverage
average = (smallAverage * smallCount + largeAverage * largeCount) / \
float(smallCount + largeCount)
if largeAverage < smallAverage + 180:
# average will not hit wraparound
return average
elif largeAverage > smallAverage + 180:
# average will hit wraparound, so will be off by 180 degrees
return (average + 180) % 360
else:
# opposite angles: return whichever has more weight
if smallCount > largeCount:
return smallAverage
elif smallCount < largeCount:
return largeAverage
else:
return None
>>> averageAngles2([0, 0, 90])
30.0
>>> averageAngles2([30, 350])
10.0
>>> averageAngles2([0, 200])
280.0
Вот немного наивный алгоритм:
- убрать все углы откоса из списка
- взять пару углов
- поверните их в первый и второй квадрант и усредните их
- повернуть средний угол назад на ту же величину
- для каждого оставшегося угла усредните таким же образом, но с последовательно увеличивающимся весом до составного угла
некоторый код на Python (шаг 1 не реализован)
def averageAngles(angles):
newAngles = [a % 360 for a in angles];
average = 0
weight = 0
for ang in newAngles:
theta = 0
if 0 < ang - average <= 180:
theta = 180 - ang
else:
theta = 180 - average
r_ang = (ang + theta) % 360
r_avg = (average + theta) % 360
average = ((r_avg * weight + r_ang) / float(weight + 1) - theta) % 360
weight += 1
return average
Вот ответ, который я дал на этот же вопрос:
Как вы рассчитываете среднее значение для набора циклических данных?
Это дает ответы в соответствии с тем, что ОП говорит, что он хочет, но внимание должно быть уделено этому:
"Я также хотел бы подчеркнуть, что хотя это истинное среднее углов, в отличие от векторных решений, это не обязательно означает, что это решение, которое вы должны использовать, среднее значение соответствующих единичных векторов вполне может быть значением, которое вы на самом деле следует использовать ".
Вы правы в том, что принятый ответ об использовании традиционного среднего значения неверен.
Среднее значение набора балловx_1 ... x_n
в метрическом пространствеX
является элементомx in X
который минимизирует сумму квадратов расстояний до каждой точки (см. среднее значение Фреше ). Если вы попытаетесь найти этот минимум, используя простое исчисление с обычными действительными числами, вы вернетесь к стандартному «сложите и разделите наn
"формула.
Для угла наши элементы на самом деле являются точками на единичной окружности.S1
. Наша метрика — это не евклидово расстояние, а длина дуги, которая пропорциональна углу.
Таким образом, средний угол - это тот, который минимизирует квадрат угловой разницы между каждым другим углом. Другими словами, если у вас есть функцияangleBetween(a, b)
Вы хотите найти уголa
такой, чтоsum over i of angleBetween(a_i, a)
сведен к минимуму.
Это задача оптимизации, которую можно решить с помощью численного оптимизатора. Некоторые из ответов здесь утверждают, что предоставляют более простые закрытые формы или, по крайней мере, лучшие приближения.
Статистика
Как вы указываете в своей статье, вам нужно предположить, что ошибки следуют распределению Гаусса, чтобы оправдать использование метода наименьших квадратов в качестве оценки максимальной вероятности. Так в этом приложении где ошибка? Является ли случайной ошибкой положение двух вещей, а угол — это просто нормаль линии между ними? Если это так, эта нормаль не будет следовать распределению Гаусса, даже если ошибка в положении точки соответствует. Использование средних углов действительно имеет смысл только в том случае, если случайная ошибка наблюдается в самом угле.
Я думаю, что проблема связана с тем, как вы относитесь к углам больше 180 (и к углам больше 360). Если вы уменьшите углы до диапазона от +180 до -180, прежде чем добавить их к общему значению, вы получите нечто более разумное:
int AverageOfAngles(int angles[], int count)
{
int total = 0;
for (int index = 0; index < count; index++)
{
int angle = angles[index] % 360;
if (angle > 180) { angle -= 360; }
total += angle;
}
return (int)((float)total/count);
}
Что плохого в том, чтобы принимать набор углов в качестве реальных значений и просто вычислять среднее арифметическое этих чисел? Тогда вы получите интуитивный (0+0+90)/3 = 30 градусов.
Редактировать: Спасибо за полезные комментарии и указание, что углы могут превышать 360. Я считаю, что ответом может быть обычное среднее арифметическое значение, уменьшенное по модулю 360: мы суммируем все значения, делим на количество углов и затем вычитаем / добавляем кратное 360, так что результат лежит в интервале [0..360).
Ну вот! Ссылка https://www.wxforum.net/index.php?topic=8660.0
def avgWind(directions):
sinSum = 0
cosSum = 0
d2r = math.pi/180 #degree to radian
r2d = 180/math.pi
for i in range(len(directions)):
sinSum += math.sin(directions[i]*d2r)
cosSum += math.cos(directions[i]*d2r)
return ((r2d*(math.atan2(sinSum, cosSum)) + 360) % 360)
a= np.random.randint(low=0, high=360, size=6)
print(a)
avgWind(a)
Возможно, вы могли бы представить углы как кватернионы и взять среднее значение этих кватернионов и преобразовать их обратно в угол.
Я не знаю, дает ли это вам то, что вы хотите, потому что кватернионы - это скорее вращения, чем углы. Я также не знаю, даст ли это вам что-то отличное от векторного решения.
Кватернионы в 2D упрощаются до комплексных чисел, так что я думаю, что это просто векторы, но, возможно, какой-нибудь интересный алгоритм усреднения кватернионов, например http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872_2007014421.pdf при упрощении до 2D будет вести себя лучше, чем просто векторное среднее.
Вы можете сделать это: скажем, у вас есть набор углов в массиве angle
Затем для вычисления массива сначала выполните: angle[i] = angle[i] mod 360
Теперь выполните простое среднее по массиву. Поэтому, когда у вас есть 360, 10, 20, вы в среднем 0, 10 и 20 - результаты интуитивно понятны.