Самый эффективный способ найти минимум и максимум кривой sin/cos в С#

Предыстория: в моей программе есть функция, которая берет набор точек и находит минимум и максимум на кривой, созданной этими точками. Дело в том, что он невероятно медленный, так как использует цикл while для определения минимума/максимума на основе аппроксимированной ошибки. Не совсем уверен, что это за формальный метод, потому что я не писал его сам, но я знаю, что нам нужен новый и более эффективный.

Вопрос: Мой вопрос заключается в следующем: каков наилучший и наиболее эффективный метод/алгоритм для нахождения минимальных максимальных точек на кривой с использованием C#, который также является очень точным?

О кривой: рядом со мной лежит книга по численному анализу из колледжа, поэтому все, что мне нужно, — это название метода и толчок в правильном направлении. Я могу сгенерировать столько точек, сколько захочу для аппроксимации кривой, но я хочу свести количество точек к эффективному минимуму. Кривая всегда имеет форму одного сегмента кривой Sin/Cos, но не всегда одна и та же кривая и всегда будет меньше одного периода. Диапазон Theta составляет от 0 до 359,999... Он имеет некоторый сдвиг фазы и амплитуды, а Y никогда не будет отрицательным. Эта функция/алгоритм должна работать быстро, так как она будет запускаться каждые несколько сотен миллисекунд по мере изменения кривой.

Любые предложения приветствуются.

ИЗМЕНИТЬ

Дополнительная информация о кривой: точки генерируются при движении мыши. Точки представляют собой набор точек, основанный на длине резинового ремня в конструкции привода с натяжным роликом, такой как поликлиновой ремень в автомобиле. Положение натяжного ролика определяет длину ремня, и я получаю кривую [длина ремня (y) в зависимости от положения натяжного ролика (x)]. Натяжной ролик в этом случае представляет собой поворотный натяжной ролик и будет иметь постоянное круговое движение. Если конструкция привода изменится, кривая изменится либо из-за изменения точек длины, либо из-за того, что диапазон движения натяжного ролика был ограничен. Диапазон движения холостого хода потенциально составляет от 0 до 359,999... и является тета, как указано выше. Для натяжного ролика с прорезями максимальный диапазон составляет 1/2 периода кривой (более простая задача).

Я предполагаю, что мне нужен общий решатель для обоих типов бездельников, но реальная проблема связана с поворотным бездельником.


person Mike Webb    schedule 06.07.2010    source источник
comment
Как генерируются ваши баллы? Сначала я предположил, что они взяты из какого-то другого места, но теперь я увидел, что они меняются, когда вы двигаете мышью. Означает ли это, что у вас есть уравнение, которое каким-то образом изменяется движением мыши? Если вы программно создаете эти точки, вы должны иметь (или иметь возможность вывести) уравнение для вашей кривой...   -  person Chris    schedule 06.07.2010
comment
@Chris, добавил больше информации в сообщение по вашему вопросу.   -  person Mike Webb    schedule 06.07.2010
comment
Минимальное/максимальное значение sin (или cos) в некотором диапазоне равно -1, 1 или sin (или cos) конечных точек. Что тебе еще надо?   -  person sigfpe    schedule 07.07.2010
comment
@Mike: У вас есть значения в виде массива или списка?   -  person Waleed A.K.    schedule 07.07.2010
comment
Похоже, вы должны быть в состоянии напрямую рассчитать мин./макс., но, к сожалению, я не до конца понимаю механику рассматриваемой проблемы - главным образом потому, что я не уверен в том, что такое бездельник или что он делает (и я немного не уверен в особенности приводных ремней и т. д. Я собираюсь бросить здесь, если у вас нет времени сделать диаграмму или что-то, чтобы объяснить бедному маленькому мне, как именно выглядит проблема. ;-) Надеюсь, другие поймут вашу проблему лучше и хотя бы помочь. :)   -  person Chris    schedule 07.07.2010
comment
@Mike: Пока у вас есть массив для ваших значений {ввод и вывод}, независимо от функции, вы можете использовать linq для решения своей проблемы. Скоро напишу код.   -  person Waleed A.K.    schedule 08.07.2010
comment
@Mike: посмотри мой код, надеюсь, это решит твою проблему   -  person Waleed A.K.    schedule 08.07.2010


Ответы (7)


Алгоритм, который вы должны использовать (и параметры, которые вы ему задаете), зависит от того, как выглядит ваш набор данных. Похоже, вы оцениваете форму волны какого-то физического измерения, которое регистрируется непрерывно.

Если да, то вам нужно решить, хотите ли вы игнорировать локальные минимумы и максимумы (например, выбросы из-за шума в сигнале). Кроме того, вам понадобится какой-то способ обработки границ вашего набора данных. Другими словами, считается ли начало ваших данных максимумом, если это самая высокая точка в текущем наборе данных, но она просто спускается с большого пика в предыдущем?

Алгоритмы обнаружения фиксированных пиков обычно имеют какой-то способ указать порог, а также ширину (для управления чувствительностью к пикам) и размер буфера (для обработки действительно постепенных пиков).

Существует множество алгоритмов, просто выберите один или два и настраивайте параметры, пока он не даст ожидаемых результатов.

person Angelo    schedule 06.07.2010
comment
Не могли бы вы указать мне место, где я могу их найти? Должен ли я просто гуглить алгоритмы обнаружения пиков? Кроме того, отвечая на ваш вопрос, набор очень ограничен. Это форма волны, генерируемая точками [длина ремня в зависимости от положения натяжного ролика] для ременного привода с прикрепленным натяжным роликом, очень похожего на змеевиковый ременной привод в автомобильном двигателе. - person Mike Webb; 06.07.2010
comment
Необходимость в постоянном обновлении возникает из-за необходимости обновлять минимальное и максимальное значение, когда пользователь моей программы изменяет конструкцию диска при перемещении мыши. - person Mike Webb; 06.07.2010
comment
Кроме того, как вы просили выше, учитываются и начало, и конец. - person Mike Webb; 06.07.2010
comment
Алгоритмы обнаружения пиков AFAIK включают в себя вещи, похожие на то, что Бретана описала в предыдущем посте. Однако критически важным шагом, который обычно выполняется, является некоторая фильтрация перед поиском. Вы захотите отфильтровать сигнал ровно настолько, чтобы пики, которые намного уже (или намного шире), чем ожидаемый пик, игнорировались. Таким образом, можно пропустить большее количество точек при измерении уклона в наборе данных. Возможность делать большие пропуски в поиске ускорит его. - person Angelo; 06.07.2010

Если у вас есть квадратное уравнение, то максимум или минимум всегда будет в точке, когда дифференциал уравнения равен 0. Если ваше квадратное уравнение имеет формулу ax ^ 2 + bx + c = 0, то эта точка будет, когда x = -b/2а.

Является ли это максимальным минимумом opr, можно определить, взглянув на a. Если a > 0, то это минимум, а если a ‹ 0, то это максимум (если a = 0, то это не квадратичное число).

Надеюсь, это поможет. Если у вас нет уравнения кривой в такой форме, не могли бы вы сказать, из чего вы должны работать?

Редактировать: вопрос изменен таким образом, что кривая является частью синусоиды, а не квадратичной кривой. Поэтому этот ответ больше не подходит.

Изменить2:

Для синусоидальной кривой общее уравнение будет y = a sin(mx+t) + c. Вы никогда не сможете точно определить исходное уравнение, потому что для любого решения будет решение с более высокой частотой, которое также соответствует. В настоящее время я не уверен, сколько точек необходимо, чтобы точно рассчитать, каким будет a (что даст минимальное и максимальное значение кривой).

person Chris    schedule 06.07.2010
comment
У меня есть набор точек для работы. Как я уже упоминал, я могу генерировать столько точек, сколько захочу, но мне нужно свести их к минимуму, чтобы функция оставалась эффективной. - person Mike Webb; 06.07.2010
comment
Он сказал, что может создать столько точек, сколько захочет, поэтому я сделал вывод, что у него есть уравнение для кривой. Вы можете получить уравнение для кривой из трех точек на этой кривой, поэтому с тремя точками вы сможете использовать этот метод. Мне просто нужно понять, как решить одновременные уравнения в коде... - person Chris; 06.07.2010
comment
Формула кривой представляет собой уравнение степени n-1. Для пяти точек это формула четвертой степени, такая как y=ax^4+bx^3+cx^2+dx+e. Вам просто нужно вывести его и определить, где это ноль, чтобы найти минимальную и максимальную точки. - person Guffa; 06.07.2010
comment
У вас есть y = ax^2 + bx + c Подставьте 3 точки (x1, y1), (x2, y2), (x3, y3), узнайте a, b и c и тогда этот ответ должен быть тем, что вам нужно. - person IVlad; 06.07.2010
comment
Я больше думал о кривой, созданной точками, которые у меня есть, и обнаружил, что она будет иметь форму кривой sin/cos, а не квадратичной кривой. Он всегда будет в этой форме и всегда будет меньше одной фазы. Я отредактировал свой пост соответственно. - person Mike Webb; 06.07.2010
comment
Меньше одного периода, я имею в виду. - person Mike Webb; 06.07.2010
comment
@Chris, уравнение, которое вы получаете всего из трех точек, действительно только для этих трех точек. Это не обязательно справедливо для любой из других точек, не используемых для создания уравнения. - person Charles Bretana; 06.07.2010
comment
Если все точки лежат на квадратном (что обсуждалось, когда я сказал, что вам нужно только три точки), то уравнение, которое вы получаете из трех точек, справедливо для всех других точек на этой кривой. Теперь, когда кривая является сегментом произвольной синусоидальной кривой, это совершенно другая ситуация, и я еще недостаточно усердно думал о том, как ее решить, думал, что вы правы в том, что трех точек больше не будет достаточно. И чем больше я об этом думаю, тем больше я думаю, что для любого конечного набора точек вы можете создать синусоиду произвольной величины, которая соответствовала бы всем точкам. - person Chris; 06.07.2010
comment
With a sine curve the general equation will be y = a sin(mx+t) + c. You will never be able to exactly determine the original equation because for any solution there will be a higher frequency solution that also matches. независимо от частоты min/max равны c-a и c+a соответственно - person BlueRaja - Danny Pflughoeft; 06.07.2010
comment
@BlueRaja - Дэнни Пфлугхофт: Да, min/max — это c-a и c+a, но на самом деле это не ответ, пока вы не узнаете, что такое c-a и c+a. И частота может иметь значение. Для любого набора точек и решения существует более высокочастотное решение с большей амплитудой. У меня слишком много математических набросков на бумаге передо мной, чтобы расшифровать. ;-) - person Chris; 07.07.2010

Поскольку кривая всегда квадратична (и, следовательно, всегда выпукла), должно быть много доступных методов (хотя, поскольку я не программирую на С#, я не знаю, доступен ли исходный код). Сначала на ум приходит метод Ньютона, но есть и другие (например, методы внутренних точек). Математические основы этих алгоритмов (но, к сожалению, не их реализации) см. в этом. учебник (pdf). Если вы используете любой из этих методов, они будут работать и для других выпуклых кривых.

person Jan Gorzny    schedule 06.07.2010
comment
Вообще-то, я не заметил, что у тебя был только набор очков. Не уверен, насколько применим ответ в этом случае, но посмотрите ссылку, если вас интересуют методы выпуклой оптимизации в целом. - person Jan Gorzny; 06.07.2010
comment
Теперь, когда я думаю об этом, он может оказаться в форме сегмента кривой sin/cos, но всегда меньше, чем одна целая фаза. Я отредактировал свой пост соответственно. - person Mike Webb; 06.07.2010
comment
В этом случае, если вы можете ограничить домен набором, где функция выпукла (например, от пи до 2 * пи на стандартном синусоидальном графике), и найти метод выпуклой оптимизации, который применим к вам, вы можете найти минимум. (И вы можете проделать аналогичный трюк для нахождения максимума.) - person Jan Gorzny; 06.07.2010
comment
Меньше одного периода, я имею в виду. - person Mike Webb; 06.07.2010
comment
Если он значительно меньше одного периода и не содержит точки перегиба, сегмент кривой всегда будет либо выпуклым, либо вогнутым. - person Jan Gorzny; 06.07.2010
comment
Он потенциально может содержать точку перегиба, но не более одной. Диапазон тета составляет 0-359,999... Кривая имеет некоторый сдвиг фазы и амплитуды, и точка Y никогда не будет отрицательной. - person Mike Webb; 06.07.2010

Это все, что у вас есть в наличии набор очков? И нет ли ограничений на «форму» функции, которую представляют эти точки? Если это так, то вы, вероятно, застряли, итерация по точкам будет вашим лучшим выбором...
Хотя, если у вас есть какая-либо другая работа над этим набором, вы можете отсортировать его по координате Y для использовать для будущей обработки.

(Держите оба массива рядом - тот, который вы получили в качестве входных данных (он, вероятно, отсортирован по x-corrd?) и тот, отсортированный по значению функции (y-coord))...

Редактировать: если вы знаете, что кривая всегда будет иметь форму, "подобную" части кривой Sin/Cos, то если вы знаете наименьший период, который может быть представлен, вы можете выполнить некоторую оптимизацию, используя алгоритм бинарного поиска, чтобы «искать» точки перегиба (где наклон (изменение Y влево и вправо) имеет разные знаки. Для каждой точки, рассмотренной на влево, двигайтесь вправо порциями = половина допустимого периода, пока не найдете точку перегиба или наклон не изменит знак... Затем двигайтесь назад на половину последнего изменения x, пока не найдете точку перегиба. [ Сделайте противоположное для точек справа]

Рекурсивная процедура, которая проверяет/находит первую и последнюю точки перегиба, сравнивает их, чтобы определить, какая из них наибольшая, а затем рекурсивно проверяет и находит точку заражения на полпути между ними, пока две задействованные точки не станут меньше наименьшего допустимого периода между друг друга, даст некоторый прирост производительности...

2nd EDIT: поскольку я читал в другом комментарии, этот набор никогда не будет содержать более одной точки перегиба... Если это так, то просто выполните двоичный поиск, чтобы найти его.

Псевдокод:

  Check Leftmost point to see slope (Up Down or Zero)
       If Zero, done
  Check RightMost Slope 
       If Zero - Done
  If two Slopes are same sign - Done 
        - pick Bigger of two points ( - or smaller if looking for min)
  Check point in the Middle slope
     If Zero, Done
     If slope has same sign as left pt, Change Left to this Point and repeat
     If slope has same sign as right pt, Change Right to this Point and repeat
person Charles Bretana    schedule 06.07.2010
comment
Форма всегда будет иметь форму некоторого сегмента кривой sin/cos, хотя она всегда будет меньше одной фазы. Я отредактировал свой пост, чтобы включить эту информацию. - person Mike Webb; 06.07.2010
comment
Меньше одного периода, я имею в виду. - person Mike Webb; 06.07.2010
comment
@Charles, это то, что алгоритм делает прямо сейчас. Оценка хорошая, но недостаточно эффективная для того, что мне нужно, и создает отставание в моей программе при постоянном обновлении. - person Mike Webb; 06.07.2010
comment
@Mike, тогда, боюсь, у меня нет других идей получше... извините! - person Charles Bretana; 06.07.2010
comment
@ Чарльз Бретана, не беспокойся. Спасибо за помощь. - person Mike Webb; 07.07.2010

После того, как вы наберете несколько точек (>=4), вы можете использовать форму локального поиска, чтобы сопоставить ваши точки с кривой синусоиды y = A cos(Bx+C)+D, а затем использовать простую формулу, основанную на производной, чтобы найти минимум. При поиске следует как можно меньше оставлять B, чтобы избежать избыточных высокочастотных решений. Просто идея, может быть очень неэффективной.

person Mau    schedule 06.07.2010

Из комментария вход X и выход Y являются массивами

"@Mike: я генерирую значения и помещаю их в массив"

Я предлагаю использовать этот подход. Все, что вам нужно от моего кода, это {getMaxIndex}

    private void Test()
    {
        double[] X = SetLinearRange(0, Math.PI * 2, 1000);
        double[] Y = GetOutput(X);
        int MaxIndex = getMaxIndex(Y);
        double MaxX = X[MaxIndex];
        double MaxY = Y[MaxIndex];
    }
    private double[] SetLinearRange(double Start, double End, int Sample)
    {
        double Step = (End - Start) / Sample;
        double CurrentVaue = Start;
        double[] Array = new double[Sample];
        for (int Index = 0; Index < Sample; Index++)
        {
            Array[Index] = CurrentVaue;
            CurrentVaue += Step;
        }
        return Array;
    }
    private double[] GetOutput(double[] X)
    {
        double[] Array;
        Array = (from double Item in X select myFunction(Item)).ToArray();
        return Array;
    }
    private double myFunction(double x)
    {
        double y;
        //put any function
        y = 3 * Math.Sin(5 * x + 2);
        return y;
    }
    private int getMaxIndex(double[] Y)
    {
        double YM = Y.Max();
        int Index = Y.ToList().IndexOf(YM);
        return Index;
    }

Я надеюсь, что это будет быстро.

person Waleed A.K.    schedule 08.07.2010

Я немного запутался.

Если вы сами генерируете точки, почему бы просто не отслеживать самые большие/наименьшие точки при создании?

Если у вас есть функция, как, я уверен, указывали другие, просто получите производную и решите для 0. Это даст вам точку (точки) мин/макс.

person Noon Silk    schedule 08.07.2010