First, I'll define the following:

- n: an index for the point in the series. The first point is n = 1, the next n = 2, the next n = 3, etc.
- y
_{n}: the series of unfiltered points data values, for example altitudes. - t
_{n}: the series of unfiltered points time values. - Δt: the time separation of the data for uniformly spaced time points.
- Δt
_{n}: when time is not necessarily uniformly spaced, Δt_{n}‒Δt_{n‒1}. - τ: the smoothing time constant.
- u
_{n}: normalized time values, t_{n}/ τ. - Δu: Δt / τ (for uniformly spaced time points).
- Δu
_{n}: Δt_{n}/ τ. - z
_{n}: the series of smoothed time points.

So using these definitions, I want to convert from the unsmoothed series y

_{n}to the smoothed series z

_{n}.

First, if an initial point is encountered, we start things rolling with the following:

z

_{0}= y

_{0}

Then assuming uniformly spaced data, a naive approach is the following:

z

_{n}= z

_{n‒1}exp(‒|Δt| / τ) + y

_{n}[1 ‒ exp(‒|Δt| / τ)].

The above formula can be extended to data where the time points aren't uniform simply enough:

z

_{n}= z

_{n‒1}exp(‒|Δt

_{n}| / τ) + y

_{n}[1 ‒ exp(‒|Δt

_{n}| / τ)].

This works fairly well (but not always). Convolution, which is what we're doing here, is a continuous operation, where variables are defined for all values of time. However, the data we have are discrete: the data are described only at particular values of time. In general, one first converts the discrete data stream to a continuous function, then applies the convolution operation (smoothing function) to the continuous data, then converts back to a discrete time-series.

In this case, the above formula assumes the continuous data series is:

- y = y
_{1}for all time ≤ t_{1}. - y jumps immediately to y
_{2}as t passes t_{1}. - y = y
_{2}for t_{1}< t ≤ t_{2}. - y jumps immediately to y2 as t passes t
_{1}. - y = y
_{3}for t_{2}< t ≤ t_{3}. *etc.*

Depending on the nature of the samples, this assumption may or may not be a good one. Suppose, for example, an Edge computer is reporting speed. It counts the number of wheel rotations in a second (interpolating for fractional rotations, perhaps) and divides by the time since the last data point, multiplying by the rolling distance per rotation. Then speed reported is actually the average since the last reported number, not the speed at a particular point in time. On the other hand, suppose it reads a temperature or altitude exactly at the time point it is reporting. Then this isn't an average over the last interval, but rather an estimation of the point

*now*. In this case, the above assumptions may not be the best.

Suppose instead I assume the following about the continuous function:

- y = y
_{1}for all time ≤ t_{1}. - y varies linearly from y
_{1}to y_{2}as t goes from t_{1}to t_{2}. - y varies linearly from y
_{2}to y_{3}as t goes from t_{2}to t_{3}. *etc.*

This seems more reasonable for an intrinsically continuous function like altitude.

With this assumption, exponential convolution gets a bit tricker, but still well within the domain of high school calculus. Here's the result I got:

z

_{1}= y

_{1}

z

_{n}= z

_{n‒1}exp ‒|Δu

_{n}| + y

_{n}(1 - exp ‒|Δu

_{n}|) +

(Δy

_{n}/ Δu

_{n}) [ (Δu

_{n}+ 1) exp ‒|Δu

_{n}| - 1 ], n > 1

where I've for the first time used the "u" variable as a substitute for t / τ. A quick check: if Δy

_{n}= 0 it gives the same result as the previous version, which is of course what's expected, because in each case the assumptions lead to the function y being constant over the interval from t

_{n-1}to t

_{n}.

I like this one a lot better, since for a given point y

_{n}and t

_{n}, I'm no longer assuming the data is going in the forward-time direction. With the old assumptions, I assumed the point y

_{n}was an average over the real-time value over the preceding interval. If I were to flip the time axis, this becomes an average over the next time interval. With this newer, linear interpolation assumption, I can flip the time axis without any issue.

A quick comment on that: there's two types of filters: causal and noncausal. Causal filters need to evaluate a smoothed value at time t

_{n}using only data from times t < t

_{n}. For example, if I'm writing firmware for a Garmin Edge computer, and I want it to display power, but want the displayed value to jump around less than the power meter reports, I can write a causal filter to smooth the data. I don't have the luxury of looking at future data. On the other hand, if I'm programming Golden Cheetah to display power data from a ride after that ride is over, it would be foolish to restrict myself to causal filters, since I have access to all of the data from the ride at once. In this case, my goal is to estimate power after a ride is finished, so there's no reason to restrict myself to a causal filter. Simple exponential convolution filters are excellent causal filters, but relatively poor when the causality constraint is absent. So I'll go beyond simple exponential filtering when I continue on this subject.

## No comments:

Post a Comment