Как рассчитать отрицательное ускорение?

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

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

F (X) →

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

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

Update:

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

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

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

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

Ответ 1

[Короткий ответ (предполагающий синтаксис 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); }

где имеет:

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

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

Таким образом, важная цель:

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

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

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

Предлагаемая идея:

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

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

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

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

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()

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

4.png

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

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

Ответ 2

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

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

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

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

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 мс, поэтому давайте определим timetick 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 в timeticks.

Опять же, наша функция скорости пропорциональна чему-то, что распадается на 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 для сюжетов - это очень мило.)

OLD ANSWER

Умножьте скорость на k < 1, например k = 0,98, чтобы он экспоненциально распадался.

Ответ 3

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

Это будет определение ускорения. Например, если ускорение было 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

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


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

velocity_new = velocity_old + acceleration/frames_per_second
position_new = position_old + velocity_old/frames_per_second

Ответ 4

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

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

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)

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

Ответ 5

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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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

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

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

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

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

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

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

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

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


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

Ответ 8

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

Ответ 9

Вы можете отслеживать скорость и сокращать ее на долю скорости каждый раз. Я уверен, что это будет симулировать трение.

Ответ 10

acceleration = (force / mass) 
velocity = (acceleration * time)
(force from user finger) = acceleration / mass = velocity / time
  • дайте виду массу (подстройте его, пока все не кажется разумным, и пусть пользователь настраивает его).
  • определить новую силу (перетащить)
  • дать новую силу (перетащить) величину (настроить до разумного, пусть пользователь настраивает ее)
  • применить новую силу к объекту и посмотреть, как он замедляется.

Ответ 11

Я бы сократил скорость как нечто вроде v = v * 0.9 Тогда у меня будет скорость, которая считается остановленной скоростью. Таким образом, объект в конце концов успокоится и не будет продолжать потреблять ресурсы как движущиеся. так что-то вроде для (V = startingVelocity; v < 1,0, V * = 0,9) { х + = v; }

Ответ 12

Ускорение - производная первого порядка от скорости и производной второго порядка от расстояния. Ваш график выглядит как парабола второго порядка, что-то вроде C-k * x ^ 2 для некоторых констант C и k. Если y действительно расстояние, вам нужно a = -2k, если y - скорость, вам нужно a = -2kx. В любом случае скорость v (x) = V0 + a (x) * x. (Где x - это время. Я следую вашему соглашению и не использую t.)

Ответ 13

Я пробовал это, что работает (в Ruby). Не уверен, что математика звучит, но выход выглядит правильно, а это означает, что вы становитесь быстрее, когда вы приближаетесь к центру:

velocity=100;
(100.downto(0)).each { |distance_from_black_hole |  velocity=velocity+9.8/distance_from_black_hole; puts velocity; }

Ответ 14

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

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

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

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

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

Ответ 15

y(x) = y0 - a * e ^ ( k * x )

где y0 - начальная константа, а a и k являются факторами.

Пример графика.