Brains 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба Доброго дня, форумчане! У меня есть периодическая величина, значение которой нужно усреднить средним арифметическим (X1+X2+..+Хn)/n - в простейшем случае (Х1+Х2)/2. Величина - это угол сдвига фаз, меняющийся от 0 до 359 градусов. Измерение ведется путем захвата таймером интервала времени между фронтами прямоугольных импульсов. При условии синфазности сигналов (должно измеряться значение 0 градусов), появляется неразрешимая пока мною проблема: из-за джиттера, являющегося следствием шума на входе, начинается гонка фронтов сигналов, при этом я получаю захваченные таймером интервалы, соответствующие углу в градусах, к примеру в такой последовательности: 1, 359, 1, 359.... Если попытаться усреднить эту последовательность, то получится значение 180 градусов, вместо ожидаемого нуля. Вариант перехода к формату -180->0->+180 уже рассматривался, и он имеет такую же проблему при усреднении, возникающую в окрестностях 180 градусов (-179,+179 после усреднения дает 0 вместо 180). Алгоритм нужен для целочисленного МК, желательно простой арифметическо-логический. Какие есть варианты решения этой проблемы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба Вообще-то угол - это величина из двумерного пространства. Там числа должны быть двумерными/комплексными. Но математика там будет посложнее целочисленной и сложности эти нужны не всегда. Проще можно так. Если конечно фаза не скачет по всему кругу. Перед прибавлением очередного значения к сумме, новое значение корректируется на -360 или 0 и выбирается ближайшее. Потом, результат можно так же скорректировать на -360, если он превысит 360 (360*N). Или на +360, если он будет отрицательным, а нужен положительный. Изменено 24 ноября, 2011 пользователем GetSmart Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Brains 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба Перед прибавлением очередного значения к сумме, новое значение корректируется на -360 или 0 и выбирается ближайшее. GetSmart, извините, не уловил смысл того что нужно сделать. Можете пояснить на примере: что нужно сделать с цифрами, если сначала приходит значение 1, затем 359, чтобы получить результат 0? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MKS 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба Можно от угла перейти к декартовым координатам (x,y) и усреднять их а потом обратно к углу вернуться (это реализуемо в целочисленой арифметике). Или детектировать скачок фазы при разрыве и компенсировать его. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба GetSmart, извините, не уловил смысл того что нужно сделать. Можете пояснить на примере: что нужно сделать с цифрами, если сначала приходит значение 1, затем 359, чтобы получить результат 0? 359 можно представить как -1, если прибавить к исходному значению -360. Вообще, можно прибавлять к углу хоть -360, хоть +360 и это будет тот же угол. Так что, если первое число было 1, а второе 359, то смотрим разницу между ними = 358. А если к 359 прибавить -360, то разница между числами будет 2 (1 - (359-360)). А 2 меньше чем 358. Значит его и используем в среднем арифметическом. Соответственно, 1+(-1) = 0. 0 это и есть среднее значение. Разницу только нужно сравнивать по модулю (без знака). Изменено 24 ноября, 2011 пользователем GetSmart Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Brains 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба Можно от угла перейти к декартовым координатам (x,y) и усреднять их а потом обратно к углу вернуться (это реализуемо в целочисленой арифметике). Но, насколько я понимаю, это преобразование задействует тригонометрические функции, а они выполняются долго. GetSmart, спасибо, я попробую этот метод. Если переложить в псевдокод получится: if(|Xn - Xn-1| < |Xn - 360 - Xn-1|) Acc += Xn - 360; else Acc += Xn; Xn-1 = Xn; Понятно стало, что кроме аккумулятора и счетчика накопления потребуется еще переменная предыдущего отчета Xn-1, необходимая для предложенного вами кастинга. Но еще не понял как тогда ее инициализировать. Изменено 24 ноября, 2011 пользователем Brains Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба Понятно стало, что кроме аккумулятора и счетчика накопления потребуется еще переменная предыдущего отчета Xn-1, необходимая для предложенного вами кастинга. Но еще не понял как тогда ее инициализировать. Во-первых, "кастинг" должен быть именно с аккумулятором. Во-вторых, сравнивать нужно модуль, то есть abs(acc/n - X), либо abs(acc-X*n). Обычно проще и быстрее умножать, чем делить. В-третьих, нужно контролировать диапазон аккумулятора, чтобы он был диапазоне 0..360*n. Иначе корректировать на -360*n, либо на +360*n. Ну и арифметика со знаком ессно. А если после каждого добавление аккума алгоритм считает среднее значение от акка, то так будет даже проще. Защита от переполнения не понадобится. Изменено 24 ноября, 2011 пользователем GetSmart Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Brains 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба Во-первых, "кастинг" должен быть именно с аккумулятором. Во-вторых, сравнивать нужно модуль, то есть abs(acc/n - X), либо abs(acc-X*n). Обычно проще и быстрее умножать, чем делить. Про это понял. В-третьих, нужно контролировать диапазон аккумулятора, чтобы он был диапазоне 0..360*n. Иначе корректировать на -360*n, либо на +360*n. А эту фразу нет. Вы имеете ввиду, что после каждого прибавления (и увеличения n на единицу) в аккумуляторе должно быть число не больше чем 360*n ? А если после каждого добавление аккума алгоритм считает среднее значение от акка, то так будет даже проще. Защита от переполнения не понадобится. Этого, к сожалению, достичь нельзя, нет ресурсов для деления на любое число, а потому рассчитываю n как степень двойки, подбираю разрядность аккума для худшего случая, и после накопления 2^n отсчетов делю аккум сдвигами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба А эту фразу нет. Вы имеете ввиду, что после каждого прибавления (и увеличения n на единицу) в аккумуляторе должно быть число не больше чем 360*n ? Да. Причём акк может стать и отрицательным. И тогда его нужно увеличить на 360*n. Либо допускать отрицательные значения до -180*n. Тогда диапазон будет от -180 до +359(.9999). А каждое новое значение угла должно быть в диапазоне 0..359(.9999 если fixed point). И когда уже в акке накопится 2^k значений, и если акк отрицательный, то добавить к нему 360*(2^k) чтобы сдвигать исключительно положительные числа. Изменено 24 ноября, 2011 пользователем GetSmart Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fontp 0 25 ноября, 2011 Опубликовано 25 ноября, 2011 · Жалоба Вариант перехода к формату -180->0->+180 уже рассматривался, и он имеет такую же проблему при усреднении, возникающую в окрестностях 180 градусов (-179,+179 после усреднения дает 0 вместо 180). Алгоритм нужен для целочисленного МК, желательно простой арифметическо-логический. Какие есть варианты решения этой проблемы? Можно разрыв арктангенса сделать на противоположной стороне круга по отношению к текущим данным, т.е. например к первому отсчету fi0 + 180 % 360 а все другие значения приводить уже к этому новому интервалу (который определяется точкой разрыва) и просто суммировать. Если есть такие сильные помехи, что выбивают угол больше чем на 180 градусов, то от них всё равно нельзя избавиться любым способом Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alexey Lukin 0 25 ноября, 2011 Опубликовано 25 ноября, 2011 (изменено) · Жалоба Есть способ лучше: построить гистограмму углов, сгладить её круговой свёрткой и найти максимум. Он даст "основной угол". А затем все значения углов из несглаженной гистограммы суммируются относительно "основного угла". А с аккумулятором будет нестабильно: последовательность типа {0, 0, 90, 180, 270, 0, 0, 90, 180, 270, ...} будет ваш аккумулятор водить кругами... Впрочем, это, наверное, редкий на практике случай. Изменено 25 ноября, 2011 пользователем Alexey Lukin Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 25 ноября, 2011 Опубликовано 25 ноября, 2011 (изменено) · Жалоба Можно разрыв арктангенса сделать на противоположной стороне круга по отношению к текущим данным, т.е. например к первому отсчету fi0 + 180 % 360 а все другие значения приводить уже к этому новому интервалу (который определяется точкой разрыва) и просто суммировать. Воруют © Перельман и китайцы :) PS. Это там деление, или мне показалось? :) Изменено 25 ноября, 2011 пользователем GetSmart Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fontp 0 25 ноября, 2011 Опубликовано 25 ноября, 2011 · Жалоба Воруют © Перельман и китайцы :) PS. Это там деление, или мне показалось? :) Это там остаток по модулю 360. Сначада интервал был 0-360. Вычисляем то что там написано Х. В этой точке делаем на круге разрыв. Т.е. все последующие значения фазы приводятся к интервалу [X-360, Х] и тупо суммируются. Здесь, есть конечно неустойчивость к забитости первой точки помехой - вдруг она ляжет криво по отношению к среднему. Собственно разрыв на круге нужно сделать бы в точке среднего, но оно нам как раз неизвестно заранее Поэтому действительно как-то так Есть способ лучше: построить гистограмму углов, сгладить её круговой свёрткой и найти максимум. Он даст "основной угол". А затем все значения углов из несглаженной гистограммы суммируются относительно "основного угла". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 25 ноября, 2011 Опубликовано 25 ноября, 2011 · Жалоба Это там остаток по модулю 360. То есть остаток по модулю имеем без деления? Как-то с полуслова Вы меня не понимаете. ТС-у делить в напряг. Он же написал. Сначада интервал был 0-360. Вычисляем то что там написано Х. В этой точке делаем на круге разрыв. Т.е. все последующие значения фазы приводятся к интервалу [X-360, Х] и тупо суммируются. Здесь, есть конечно неустойчивость к забитости первой точки помехой - вдруг она ляжет криво по отношению к среднему. Собственно разрыв на круге нужно сделать бы в точке среднего, но оно нам как раз неизвестно заранее Я так и не понял, чем это отличается от предложенного мной? Поэтому действительно как-то так А свёртка это вообще жесть. Причём свёртка будет каждого элемента в гистограмме. Хотя результат вобщем достоверный. Но сложение векторов в декартовых координатах будет явно проще. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fontp 0 25 ноября, 2011 Опубликовано 25 ноября, 2011 · Жалоба Я так и не понял, чем это отличается от предложенного мной? Где вы предлагали смещать интервал? Не вижу. Вы же рассматривали стандартный интервал [0, 360] или аналогичный стандартный [-180, 180],а я предложил убрать разрыв от данных подальше. Проблема же в точке разрыва. То есть остаток по модулю имеем без деления? Как-то с полуслова Вы меня не понимаете. ТС-у делить в напряг. Он же написал. Да нет там деления, это просто запись, там 2 if Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться