简体   繁体   中英

How to determine the amplitude and the frequency of an “oscillating” trajectory

This is the trajectory of a pedestrian moving in jam 在此输入图像描述

As you can see, his/her head perform an oscillation-like movement. So not a perfect sinus curve but neither a line.

Is it possible to define for this irregular curve an "amplitude" and a "frequency"?

UPDATE :

So far I tried two different approaches:

  1. The first one is based on calculating the turning points and then make a spline with them.
  2. The second approach is based on the suggestion of unutbu and uses the Ramer-Douglas-Peucker algorithm.

The results are as follows:

在此输入图像描述

The problem that I see with the RDP is the free parameter dist . low values (means more details) imply oscillations in the resulting trajectories. So I'm forced to be careful with this parameter. Besides, the splin ed curve is much more smoother.

What do you think?

There is no absolute correct way to do this. Below is just one way.

Let's start with the assumption/claim that people generally intend to walk in straight lines. So you could use the Ramer-Douglas-Peucker algorithm to estimate the intended path of the person with a small set of line segments. (There is a Python implementation of the algorithm here .)

Then generate the distances of the true data points from the line segments .

timeseries = []
for point in  points: 
    timeseries.append(
        min((distance between point and segment) 
             for segment in segments))

This array of distances is a timeseries. You could then take the root-mean-squared of the timeseries as a measure of amplitude, and take a Fourier transform to find its dominant frequency (or frequencies).

Here is an update to RDP module you were linked to that should work with Python 3.x using Vectors:

import functools

def autocast(function):
    @functools.wraps(function)
    def wrapper(self, other):
        if isinstance(other, self.__class__):
            if len(other) != len(self):
                raise ValueError('Object dimensions are not equivalent!')
            return function(self, other)
        return function(self, self.__class__(size=len(self), init=other))
    return wrapper

class Vector:

    __slots__ = '__data'

    def __init__(self, *args, size=0, init=0):
        self.__data = list(map(float, args if args else [init] * size))

    def __repr__(self):
        return self.__class__.__name__ + repr(tuple(self))

    @autocast
    def __cmp__(self, other):
        return (self.__data > other.__data) - (self.__data < other.__data)

    def __lt__(self, other):
        return self.__cmp__(other) < 0

    def __le__(self, other):
        return self.__cmp__(other) <= 0

    def __eq__(self, other):
        return self.__cmp__(other) == 0

    def __ne__(self, other):
        return self.__cmp__(other) != 0

    def __gt__(self, other):
        return self.__cmp__(other) > 0

    def __ge__(self, other):
        return self.__cmp__(other) >= 0

    def __bool__(self):
        return any(self)

    def __len__(self):
        return len(self.__data)

    def __getitem__(self, key):
        return self.__data[key]

    def __setitem__(self, key, value):
        self.__data[key] = float(value)

    def __delitem__(self, key):
        self[key] = 0

    def __iter__(self):
        return iter(self.__data)

    def __reversed__(self):
        return reversed(self.__data)

    def __contains__(self, item):
        return item in self.__data

    @autocast
    def __add__(self, other):
        return Vector(*(a + b for a, b in zip(self, other)))

    @autocast
    def __sub__(self, other):
        return Vector(*(a - b for a, b in zip(self, other)))

    @autocast
    def __mul__(self, other):
        return Vector(*(a * b for a, b in zip(self, other)))

    @autocast
    def __truediv__(self, other):
        return Vector(*(a / b for a, b in zip(self, other)))

    @autocast
    def __floordiv__(self, other):
        return Vector(*(a // b for a, b in zip(self, other)))

    @autocast
    def __mod__(self, other):
        return Vector(*(a % b for a, b in zip(self, other)))

    @autocast
    def __divmod__(self, other):
        result = tuple(divmod(a, b) for a, b in zip(self, other))
        return Vector(*(a for a, b in result)), Vector(*(b for a, b in result))

    @autocast
    def __pow__(self, other):
        return Vector(*(a ** b for a, b in zip(self, other)))

    @autocast
    def __radd__(self, other):
        return Vector(*(a + b for a, b in zip(other, self)))

    @autocast
    def __rsub__(self, other):
        return Vector(*(a - b for a, b in zip(other, self)))

    @autocast
    def __rmul__(self, other):
        return Vector(*(a * b for a, b in zip(other, self)))

    @autocast
    def __rtruediv__(self, other):
        return Vector(*(a / b for a, b in zip(other, self)))

    @autocast
    def __rfloordiv__(self, other):
        return Vector(*(a // b for a, b in zip(other, self)))

    @autocast
    def __rmod__(self, other):
        return Vector(*(a % b for a, b in zip(other, self)))

    @autocast
    def __rdivmod__(self, other):
        result = tuple(divmod(a, b) for a, b in zip(other, self))
        return Vector(*(a for a, b in result)), Vector(*(b for a, b in result))

    @autocast
    def __rpow__(self, other):
        return Vector(*(a ** b for a, b in zip(other, self)))

    @autocast
    def __iadd__(self, other):
        for key in range(len(self)):
            self[key] += other[key]
        return self

    @autocast
    def __isub__(self, other):
        for key in range(len(self)):
            self[key] -= other[key]
        return self

    @autocast
    def __imul__(self, other):
        for key in range(len(self)):
            self[key] *= other[key]
        return self

    @autocast
    def __itruediv__(self, other):
        for key in range(len(self)):
            self[key] /= other[key]
        return self

    @autocast
    def __ifloordiv__(self, other):
        for key in range(len(self)):
            self[key] //= other[key]
        return self

    @autocast
    def __imod__(self, other):
        for key in range(len(self)):
            self[key] %= other[key]
        return self

    @autocast
    def __ipow__(self, other):
        for key in range(len(self)):
            self[key] **= other[key]
        return self

    def __neg__(self):
        return Vector(*(-value for value in self))

    def __pos__(self):
        return Vector(*(+value for value in self))

    def __abs__(self):
        return Vector(*(abs(value) for value in self))

    def __get_magnitude(self):
        return sum(value ** 2 for value in self) ** 0.5

    def __set_magnitude(self, value):
        self *= value / self.magnitude

    magnitude = property(__get_magnitude, __set_magnitude)

###############################################################################

def point_line_distance(point, start, end):
    if start == end:
        return (point - start).magnitude
    es, sp = end - start, start - point
    return abs(es[0] * sp[1] - es[1] * sp[0]) / es.magnitude

def rdp(points, epsilon):
    dmax = index = 0
    start, *middle, end = points
    for i in range(1, len(points) - 1):
        d = point_line_distance(points[i], start, end)
        if d > dmax:
            index, dmax = i, d
    if dmax >= epsilon:
        return rdp(points[:index+1], epsilon)[:-1] + \
               rdp(points[index:], epsilon)
    return start, end

Similar to the demonstration given by the original module, the following is an example usage scenario:

>>> from pprint import pprint
>>> line = [Vector(0.0, 0.0),
            Vector(1.0, 0.0),
            Vector(2.0, 0.0),
            Vector(2.0, 1.0),
            Vector(2.0, 2.0),
            Vector(1.0, 2.0),
            Vector(0.0, 2.0),
            Vector(0.0, 1.0),
            Vector(0.0, 0.0)]
>>> pprint(rdp(line, 1.0))
(Vector(0.0, 0.0),
 Vector(2.0, 0.0),
 Vector(2.0, 2.0),
 Vector(0.0, 2.0),
 Vector(0.0, 0.0))
>>> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM