как рассчитать отрицательное ускорение? - PullRequest
10 голосов
/ 19 февраля 2010

Я реализую прокрутку в сенсорном интерфейсе, но в данный момент я слишком устал, чтобы обернуться вокруг какой-то тривиальной математики:

y (distance/velocity)
|********
|        ******
|              ****
|                  ***
|                     ***
|                        **
|                          **
|                            *
|                             *
-------------------------------- x (time)

е (х) ->

Предполагается, что пользовательский интерфейс позволяет пользователю перетаскивать и «бросать» представление в любом направлении и удерживать его в течение некоторого времени, даже после того, как он отпустит палец с экрана. Это своего рода импульс, который зависит от того, насколько быстро пользователь перетаскивал, прежде чем убрать палец.

Итак, у меня есть начальная скорость (v0), и каждые 20 мс я прокручиваю на величину, относящуюся к текущей скорости. С каждой итерацией прокрутки я немного понижаю скорость, пока она не падает ниже порогового значения, когда я ее останавливаю. Это просто не выглядит правильно, когда я уменьшаю его на фиксированную величину (линейную), поэтому мне нужно смоделировать отрицательное ускорение, но не могу найти приличную простую формулу, как рассчитать величину, на которую мне нужно снизить скорость в каждой итерации.

Обновление:

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

Предположим, что на определенной улице едет определенная машина, и водитель нажимает на тормоза до максимума, пока машина не останавливается. Водитель делает это с одним и тем же автомобилем на одной и той же улице несколько раз, но начинает тормозить с разными скоростями. Пока машина замедляется, я хочу иметь возможность рассчитать скорость, которую она будет иметь ровно через одну секунду, основываясь только на текущей скорости. Для этого расчета не должно иметь значения, на какой скорости ехал автомобиль, когда водитель начал тормозить, поскольку все факторы окружающей среды остаются неизменными. Конечно, в формуле будут некоторые константы, но когда автомобиль опускается до 30 м / с, он будет проходить то же расстояние в следующую секунду, независимо от того, проезжал ли он 100 или 50 м / с, когда водитель начал тормозить , Таким образом, время, прошедшее с момента появления перерывов, также не будет параметром функции. Замедление при определенной скорости всегда будет одинаковым.

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

Обновление 2 Теперь я вижу, что ускорение автомобиля будет в течение одного года, и это на самом деле не то, что я искал. Я уберу это и попробую новые предложения завтра. Спасибо за ваш вклад.

Ответы [ 15 ]

8 голосов
/ 20 февраля 2010

[Короткий ответ (при условии C синтаксис)]

double v(double old_v, double dt) {
    t = t_for(old_v); 
    new_t = t - dt; 
    return (new_t <= 0)?0:v_for(t);
} 

double t_for(double v) и double v_for(double t) - это возвращаемые значения из двунаправленного отображения v-to-t (функция в математическом смысле), которое является произвольным с ограничением, что оно монотонно и определено для v >=0 (и, следовательно, имеет точка, где v=0). Пример:

double v_for(double t) { return pow(t, k); }
double t_for(double v) { return pow(v, 1.0/k); }

где имеет:

  1. k>1 дает уменьшение замедления по модулю с течением времени.
  2. k<1 дает увеличение замедления по модулю с течением времени.
  3. k=1 дает постоянное замедление.

[Более длинный (с обоснованием и графиками)]

Итак, цель заключается в следующем:

  1. Чтобы найти функцию v(t+dt)=f(v(t),dt), которая принимает текущее значение скорости v и дельта времени dt и возвращает скорость в момент t+dt (фактически не требуется указывать t с * 1040) * уже известен и предоставляется в качестве параметра, а dt - это просто дельта времени). Другими словами, задача заключается в реализации подпрограммы double next_v(curr_v, dt); со специальными свойствами (см. Ниже).

  2. [Обратите внимание] У рассматриваемой функции есть полезное свойство (и желательно) для возврата того же результата независимо от «истории» предыдущих изменений скорости. Это означает, что, например, если ряд последовательных скоростей равен [100, 50, 10, 0] (для начальной скорости v0=100), любая другая последовательность, большая, чем эта, будет иметь такой же «хвост»: [150 , 100, 50, 10, 0] (для начальной скорости v0=150) и т. Д. Другими словами, независимо от начальной скорости, все графики скорости-времени будут фактически копиями каждого другие просто смещаются вдоль оси времени, каждая на свое значение (см. график ниже, обратите внимание, что части графиков между строками t=0.0 и t=2.0 идентичны) .

  3. Кроме того, ускорение w(t)=dv(t)/dt должно быть убывающей функцией времени t (с целью визуально приятного и "интуитивного" поведения движущегося объекта графического интерфейса, который мы здесь моделируем).

Предложенная идея:

  1. Сначала вы выбираете монотонную функцию скорости с желаемыми свойствами (в вашем случае это постепенное уменьшение ускорения, хотя, как показано в примере ниже, легче использовать "ускоренные"). Эта функция также не должна иметь верхней границы , чтобы ее можно было использовать для любых больших значений скорости. Также должна иметь точку, где скорость равна нулю . Вот некоторые примеры: v(t) = k*t (не совсем ваш случай, поскольку здесь замедление k постоянно), v=sqrt(-t) (это нормально, определяется в интервале t <= 0).

  2. Затем для любой заданной скорости вы найдете точку с этим значением скорости на графике вышеупомянутой функции (будет точка, поскольку функция не является связанной, и только одна, поскольку она монотонна), по дельте времени к меньшим значениям скорости, таким образом, получая следующее. Итерация постепенно (и неизбежно) приведет вас к точке, где скорость равна нулю.

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

Для двух простых случаев этот маленький скрипт на python создает графики ниже (начальные скорости даны от 1.0 до 10.0), и, как вы можете видеть, от любого заданного уровня скорости и «вниз» графики «ведут себя» одинаково , что имеет смысл, потому что независимо от того, с какой скоростью вы начинаете замедляться (замедляться), вы «движетесь» по одной и той же кривой ОТНОСИТЕЛЬНО к точке, где скорость равна нулю :

import numpy
import pylab

import math


class VelocityCurve(object):
    """
    An interface for the velocity 'curve'.
    Must represent a _monotonically_ _growing_
        (i.e. with one-to-one correspondence
        between argument and value) function
        (think of a deceleration reverse-played)
    Must be defined for all larger-than-zero 'v' and 't'
    """
    def v(self, t):
        raise NotImplementedError

    def t(self, v):
        raise NotImplementedError



class VelocityValues(object):

    def __init__(self, v0, velocity_curve):
        assert v0 >= 0
        assert velocity_curve

        self._v = v0
        self._vc = velocity_curve

    def next_v(self, dt):
        t = self._vc.t(self._v)
        new_t = t - dt

        if new_t <= 0:
            self._v = 0
        else:
            self._v = self._vc.v(new_t)

        return self._v


class LinearVelocityCurve(VelocityCurve):

    def __init__(self, k):
        """k is for 'v(t)=k*t'"""
        super(LinearVelocityCurve, self).__init__()

        self._k = k

    def v(self, t):
        assert t >= 0
        return self._k*t

    def t(self, v):
        assert v >= 0
        return v/self._k


class RootVelocityCurve(VelocityCurve):

    def __init__(self, k):
        """k is for 'v(t)=t^(1/k)'"""
        super(RootVelocityCurve, self).__init__()

        self._k = k

    def v(self, t):
        assert t >= 0
        return math.pow(t, 1.0/self._k)

    def t(self, v):
        assert v >= 0
        return math.pow(v, self._k)


def plot_v_arr(v0, velocity_curve, dt):
    vel = VelocityValues(v0, velocity_curve)
    v_list = [v0]

    while True:
        v = vel.next_v(dt)
        v_list.append(v)

        if v <= 0:
            break

    v_arr = numpy.array(list(v_list))
    t_arr = numpy.array(xrange(len(v_list)))*dt

    pylab.plot(t_arr, v_arr)


dt = 0.1

for v0 in range(1, 11):
    plot_v_arr(v0, LinearVelocityCurve(1), dt)

for v0 in range(1, 11):
    plot_v_arr(v0, RootVelocityCurve(2), dt)


pylab.xlabel('Time ')
pylab.ylabel('Velocity')

pylab.grid(True)

pylab.show()

Это дает следующие графики (линейные для линейного замедления (то есть постоянное замедление), "пышные" - для случая "квадратный корень" (см. Код выше)):

image

Также, пожалуйста, имейте в виду, что для запуска вышеуказанного скрипта необходимо установить pylab, numpy и друзей (но только для части прорисовки классы "core" ни от чего не зависят и, конечно, могут использоваться на их самостоятельно).

P.S. При таком подходе можно действительно «построить» (например, увеличивая различные функции для различных интервалов t или даже сглаживая нарисованную от руки (записанную) «эргономичную» кривую) «перетаскивание», которое ему нравится:)

5 голосов
/ 19 февраля 2010

После прочтения комментариев я хотел бы изменить свой ответ: умножьте скорость на k <1, например, k = 0,955, чтобы она экспоненциально затухала. </p>

Объяснение (с графиками:и настраиваемое уравнение!) следует за ...

Я интерпретирую график в вашем исходном вопросе как показывающий, что скорость остается около начального значения, а затем быстро уменьшается.Но если вы представите, что книга скользит по столу, она быстро уходит от вас, затем замедляется, а затем останавливается.Я согласен с @Chris Farmer, что подходящая модель - это сила сопротивления, пропорциональная скорости.Я собираюсь взять эту модель и получить ответ, который я предложил выше.Я заранее прошу прощения за длину этого.Я уверен, что кто-то лучше в математике может значительно упростить это. Кроме того, я вставляю ссылки на графики напрямую, в ссылках есть некоторые символы, которые парсеру SO не нравятся. Исправлены URL-адреса.

IЯ собираюсь использовать следующие определения:

x -> time
a(x) -> acceleration as a function of time
v(x) -> velocity as a function of time
y(x) -> position as a function of time
u -> constant coefficient of drag
colon : denotes proportionality

Мы знаем, что сила из-за сопротивления пропорциональна скорости.Мы также знаем, что сила пропорциональна ускорению.

a(x) : -u v(x)        (Eqn. 1)

Знак минус гарантирует, что ускорение противоположно текущему направлению движения.

Мы знаем, что скорость - это интегрированное ускорение.

v(x) : integral( -u v(x) dx )        (Eqn. 2)

Это означает, что скорость пропорциональна ее собственному интегралу.Мы знаем, что e^x удовлетворяет этому условию.Таким образом, мы предполагаем, что

v(x) : e^(-u x)        (Eqn. 3)

Коэффициент сопротивления в экспоненте таков, что когда мы решаем интеграл в уравнении.2 u отменяется, чтобы вернуться к уравнению.3.

Теперь нам нужно вычислить значение u.Как указывалось @BlueRaja, e^x никогда не равно нулю независимо от x.Но он приближается к нулю для достаточно отрицательного х.Давайте рассмотрим 1% нашей первоначальной скорости как «остановленный» (ваше представление о пороге) , и, скажем, мы хотим остановиться в течение x = 2 секунд (вы можете настроить это позже).Затем нам нужно решить

e^(-2u) = 0.01        (Eqn. 4)

, что приводит нас к вычислению

u = -ln(0.01)/2 ~= 2.3        (Eqn. 5)

Давайте построим график v(x).

Похоже, это экспоненциальнозатухает до небольшого значения за 2 секунды.Пока все хорошо.

Нам не обязательно вычислять экспоненты в нашем графическом интерфейсе.Мы знаем, что можем легко конвертировать экспоненциальные базы,

e^(-u x) = (e^-u)^x        (Eqn. 6)

Мы также не хотим отслеживать время в секундах.Мы знаем, что у нас частота обновления 20 мс, поэтому давайте определим временной интервал n с частотой тиков 50 тиков / с.

n = 50 x        (Eqn. 7)

Подставляя значение u из уравнения.5 в уравнение6, в сочетании с уравнением.7, и подставляя в уравнение.3, мы получим

v(n) : k^n, k = e^(ln(0.01)/2/50) ~= 0.955        (Eqn. 8)

Давайте построим это с нашей новой осью X в временных метках.

Опять же, наша функция скорости пропорциональна чему-то, что уменьшается до 1% в желаемом количестве итераций и следует модели «выбегания под воздействием трения».Теперь мы можем умножить нашу начальную скорость v0 на уравнение.8 для получения фактической скорости в любой момент времени n:

v(n) = v0 k^n        (Eqn. 9)

Обратите внимание, что при реализации нет необходимости отслеживать v0!Мы можем преобразовать закрытую форму v0 * k^n в рекурсию, чтобы получить окончательный ответ

v(n+1) = v(n)*k        (Eqn. 10)

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

Стоит проверить, чтобы убедиться, что поведение позиции имеет смысл.Положение, следующее за такой скоростной моделью, равно

y(n) = y0 + sum(0..n)(v(n))        (Eqn. 11)

. Сумма в уравнении.11 легко решается с помощью формы (9 ).Используя индексную переменную p:

sum(p = 0..n-1)(v0 k^p) = v0 (1-k^n)/(1-k)        (Eqn. 12)

Итак, у нас есть

y(n) = y0 + v0 (1-k^n)/(1-k)        (Eqn. 13)

Давайте построим это с y0 = 0 и v0 = 1.

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

В общем, вы можете настроить k с помощью уравнения

k = e^(ln(Threshold)/Time/Tickrate)        (Eqn. 14)
where:
Threshold is the fraction of starting velocity at which static friction kicks in
Time is the time in seconds at which the speed should drop to Threshold
Tickrate is your discrete sampling interval

(СПАСИБО @poke за демонстрацию использования Wolfram Alpha для сюжетов - это очень мило.)

СТАРЫЙ ОТВЕТ

Умножьте скорость на k <1, например, k = 0,98, чтобы она экспоненциально затухала. </p>

4 голосов
/ 20 февраля 2010

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

Это было бы определениемускорение.Например, если ускорение было a = -9 meters/sec/sec, а скорость сейчас 20 meters/sec, то через 1 секунду скорость будет 11 meters/sec.

Другими словами, изменение скорости Δvмежду настоящим моментом и t секундами с этого момента (при условии постоянного ускорения) будет

Δv = a*t

, что означает (классическая физика) уравнение для скорости при любой время t, учитывая начальную скорость в t=0 (эта скорость называется v 0 ), равную

v(t) = v 0+ a*t


Используя то, что вы изучите в первые две недели занятий по исчислению, вы также можете получить уравнение для x(t) (расстояние до автомобиля ввремя t) из вышеприведенного уравнения;это даст вам

x(t) = x 0 + v 0 *t + 0.5*a*t 2

(также можно получить это без исчисления, см. здесь )


Наконец , если вы делаете это для игры, а несимуляция физики (что означает, что вам не нужны точные результаты), вам нужно просто изменить положение и скорость каждого кадра, а не пересчитывать положение каждого кадра.Для этого вам нужно будет выполнять каждый следующий кадр, предполагая, что скорость (и ускорение) измеряется в пикселях в секунду (-per-second):

velocity_new = velocity_old + acceleration/frames_per_second
position_new = position_old + velocity_old/frames_per_second
2 голосов
/ 20 февраля 2010

Я тоже добавлю мысль. Похоже, вы не хотите постоянного (отрицательного) ускорения. Это привело бы к уравнению как:

v(t) = v(0) + a*t,

, где a - отрицательное ускорение, t - время, а v(t) - скорость во время t. Это дает вам:

v(t2) - v(t1) = a(t2-t1),

и это означает, что для данного & Delta; t разность скоростей равна & Delta; t, константе.

То, что вы можете искать, это термин "трение", который зависит от текущей скорости. Согласно этому допущению скорость изменения скорости пропорциональна текущей скорости:

d v(t) / d t = -b*v(t).

Решение вышеуказанного легко, и вы получите: v (t) = v (0) e & minus; b t .

Интегрируя это уравнение, мы получаем x (t) = v (0) (1 & plusmn; e & minus; b t ) / b, где x - это позиция. График положения 1 для v (0) = 1, b = 0.1 выглядит как то, что вы могли бы использовать. Возможно, вам стоит поиграть со значениями b и добавить в уравнение коэффициент масштабирования.


1 http://www.wolframalpha.com/input/?i=plot+%281+-+1+e^%28-0.1+x%29+%29+%2F+0.1+for+x+%3D+0+to+100

2 голосов
/ 20 февраля 2010

Если вы хотите увеличить замедление, как вы сказали в своем комментарии к ответу mtrw, и вы НЕ очень разборчивы в физическом реализме, то уравнение ниже может быть тем, что вы ищете:

V (t + dt) = V (t) - K1 + K2 x V (t)

V (t) = текущая скорость V (t + dt) = скорость при следующем увеличении K1 и K2 - это константы, которые вы калибруете. Просто убедитесь, что (K2 x Vmax)

Если это не так, попробуйте V (t + dt) = V (t) - K1 + K2 x f (V (t))

где f (x) - монотонно возрастающая функция, которую вы выбираете, может быть квадратный или квадратный корень в зависимости от того, где вы хотите получить чувство. Просто убедитесь, что (K2 x f (V (t)))

(монотонно возрастающая функция означает, что f (x) всегда увеличивается при увеличении x)

2 голосов
/ 20 февраля 2010

Вы можете просто уменьшить скорость на постоянную величину в каждой итерации.Пример: вы начинаете со скорости 50, на следующей итерации это 40, затем 30, 20, 10, стоп.Это будет представлять постоянное «трение», не зависящее от скорости, и это на самом деле очень близко к реальности (см. трение в Википедии ).

Если вам не нравится появление этоговам нужно сделать трение зависимым от скорости.Я бы предположил, что линейной зависимости friction = base-friction + (coefficient * velocity) с довольно малым коэффициентом будет достаточно.

2 голосов
/ 19 февраля 2010

Похоже, вы ищете замедление, которое увеличивается со временем.

Попробуйте вычислить

Delta_v = -(A*t + B), выбрав подходящие константы A и B, которые вам подходят.

t - общее время до этой точки.

Измените вашу скорость, добавив Delta_v.

Это в основном соответствует линейному отрицательному ускорению.

Вы можете в основном выбрать любую функциюкоторый увеличивается со временем (скажем, f (t))

и вычисляет

Delta_v = -f(t)

Подходящий выбор для f (t) даст вам желаемый эффект.

Некоторые примеры, которые вы могли бы использовать:

f(t) = At + B.
f(t) = A*exp(Bt)

Конечно, вам придется немного поиграться и попытаться определить правильные константы.

1 голос
/ 20 февраля 2010

Нелинейное изменение скорости означает, что ускорение не является постоянным.Непостоянное ускорение означает, что система находится под воздействием рывка .Возьмите все уравнения ускорения и добавьте «(1/6) jt 3 ».Исправьте a и дайте ja небольшое отрицательное значение, пока v не достигнет 0.

0 голосов
/ 20 февраля 2010
y(x) = y0 - a * e ^ ( k * x )

, где y0 - постоянная начала, а a и k - факторы.

Пример участка .

0 голосов
/ 20 февраля 2010

Немного непрограммного обсуждения примера автомобиля.

Во-первых, я предполагаю, что водитель не может заставить тормоза блокироваться на скорости.

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

Это поведение маскирует другую особенность, но это можно заметить во время обычного ускорения в автомобиле с механической коробкой передач. при ускорении (или замедлении), если водитель внезапно отключает передачу, все пассажиры внезапно кренится вперед. На самом деле происходит то, что ускоряющая сила, прижимающая их к спинкам сидений, внезапно исчезает, и они возвращаются в нейтральное положение сидя. Более удобный способ - постепенно включать сцепление, чтобы постепенно снижать движущую силу двигателя.

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

...