Extracting motion data from a list of coordinates - c#

I have a series of CSV files of timestamped coordinates (X, Y, and Z in mm). What would be the simplest way to extract motion data from them?
Measurables
The information I'd like to extract includes the following:
Number of direction changes
Initial acceleration of the first and last movements
...and the bearing (angle) of these movements
Average speed whilst non-stationary
Ideally, I'd eventually like to be able to categorise patterns of motion, so bonus points for anyone who can suggest a way of doing this. It strikes me that one way I could do this would be to generate pictures/videos of the motion from the coordinates and ask humans to categorise them - suggestions as to how I'd do this are very welcome.
Noise
A complication is the fact that the readings are polluted with noise. In order to overcome this, each recording is prefaced with at least 20 seconds of stillness which can serve as a sort of "noise profile". I'm not sure how to implement this though.
Specifics
If it helps, the motion being recorded is that of a persons hand during a simple grabbing task. The data is generated using a magnetic motion tracker attached to the wrist. Also, I'm using C#, but I guess the maths is language agnostic.
Edits
Magnetic tracker spec: http://www.ascension-tech.com/realtime/RTminiBIRD500_800.php
Sample data file: http://tdwright.co.uk/sample.csv
Bounty
For the bounty, I'd really like to see some (pseudo-)code examples.

Let's see what can be done with your example data.
Disclaimer: I didn't read your hardware specs (tl;dr :))
I'll work this out in Mathematica for convenience. The relevant algorithms (not many) will be provided as links.
The first observation is that all your measurements are equally spaced in time, which is most convenient for simplifying the approach and algorithms. We will represent "time" or "ticks" (measurements) on our convenience, as their are equivalent.
Let's first plot your position by axis, to see what the problem is about:
(* This is Mathematica code, don't mind, I am posting this only for
future reference *)
ListPlot[Transpose#(Take[p1[[All, 2 ;; 4]]][[1 ;;]]),
PlotRange -> All,
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Position (X,Y,Z)", Medium, Bold]}]
Now, two observations:
Your movement starts around tick 1000
Your movement does not start at {0,0,0}
So, we will slightly transform your data subtracting a zero position and starting at tick 950.
ListLinePlot[
Drop[Transpose#(x - Array[Mean#(x[[1 ;; 1000]]) &, Length#x]), {}, 950],
PlotRange -> All,
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Position (X,Y,Z)", Medium, Bold]}]
As the curves have enough noise to spoil the calculations, we will convolve it with a Gaussian Kernel to denoise it:
kern = Table[Exp[-n^2/100]/Sqrt[2. Pi], {n, -10, 10}];
t = Take[p1[[All, 1]]];
x = Take[p1[[All, 2 ;; 4]]];
x1 = ListConvolve[kern, #] & /#
Drop[Transpose#(x - Array[Mean#(x[[1 ;; 1000]]) &, Length#x]), {},
950];
So you can see below the original and smoothed trajectories:
Now we are ready to take Derivatives for the Velocity and Acceleration. We will use fourth order approximants for the first and second derivative. We also will smooth them using a Gaussian kernel, as before:
Vel = ListConvolve[kern, #] & /#
Transpose#
Table[Table[(-x1[[axis, i + 2]] + x1[[axis, i - 2]] -
8 x1[[axis, i - 1]] +
8 x1[[axis, i + 1]])/(12 (t[[i + 1]] - t[[i]])), {axis, 1, 3}],
{i, 3, Length[x1[[1]]] - 2}];
Acc = ListConvolve[kern, #] & /#
Transpose#
Table[Table[(-x1[[axis, i + 2]] - x1[[axis, i - 2]] +
16 x1[[axis, i - 1]] + 16 x1[[axis, i + 1]] -
30 x1[[axis, i]])/(12 (t[[i + 1]] - t[[i]])^2), {axis, 1, 3}],
{i, 3, Length[x1[[1]]] - 2}];
And the we plot them:
Show[ListLinePlot[Vel,PlotRange->All,
AxesLabel->{Style["Ticks",Medium,Bold],
Style["Velocity (X,Y,Z)",Medium,Bold]}],
ListPlot[Vel,PlotRange->All]]
Show[ListLinePlot[Acc,PlotRange->All,
AxesLabel->{Style["Ticks",Medium,Bold],
Style["Acceleation (X,Y,Z)",Medium,Bold]}],
ListPlot[Acc,PlotRange->All]]
Now, we also have the speed and acceleration modulus:
ListLinePlot[Norm /# (Transpose#Vel),
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Speed Module", Medium, Bold]},
Filling -> Axis]
ListLinePlot[Norm /# (Transpose#Acc),
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Acceleration Module", Medium, Bold]},
Filling -> Axis]
And the Heading, as the direction of the Velocity:
Show[Graphics3D[
{Line#(Normalize/#(Transpose#Vel)),
Opacity[.7],Sphere[{0,0,0},.7]},
Epilog->Inset[Framed[Style["Heading",20],
Background->LightYellow],{Right,Bottom},{Right,Bottom}]]]
I think this is enough to get you started. let me know if you need help in calculating a particular parameter.
HTH!
Edit
Just as an example, suppose you want to calculate the mean speed when the hand is not at rest. so, we select all points whose speed is more than a cutoff, for example 5, and calculate the mean:
Mean#Select[Norm /# (Transpose#Vel), # > 5 &]
-> 148.085
The units for that magnitude depend on your time units, but I don't see them specified anywhere.
Please note that the cutoff speed is not "intuitive". You can search an appropriate value by plotting the mean speed vs the cutoff speed:
ListLinePlot[
Table[Mean#Select[Norm /# (Transpose#Vel), # > h &], {h, 1, 30}],
AxesLabel -> {Style["Cutoff Speed", Medium, Bold],
Style["Mean Speed", Medium, Bold]}]
So you see that 5 is an appropriate value.

e solution could be as simple as a state machine, where each state represents a direction. Sequences of movements are represented by sequences of directions. This approach would only work if the orientation of the sensor doesn't change with respect to the movements, otherwise you'll need a method of translating the movements into the correct orientation, before calculating sequences of directions.
On the other end, you could use various AI techniques, although exactly what you'd use is beyond me.
To get the speed between any two coordinates:
_________________________________
Avg Speed = /(x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2
--------------------------------------
(t2-t1)
To get the average speed for the whole motion, say you have 100 timestamped coordinates, use the above equation to calculate 99 speed values. Then sum all the speeds, and divide by the number of speeds (99)
To get the acceleration, the location at three moments is required, or the velocity at two moments.
Accel X = (x3 - 2*x + x1) / (t3 - t2)
Accel Y = (y3 - 2*y + y1) / (t3 - t2)
Accel Z = (z3 - 2*z + z1) / (t3 - t2)

Note: This all assumes per axis calculations: I have no experience with two-axis particle motion.
You will have a much easier time with this if you first convert your position measurements to velocity measurements.
First step: Remove the noise. As you said, each recording is prefaced with 20 seconds of stillness. So, to find the actual measurements, search for 20 second intervals where the position doesn't change. Then, take the measurement directly after.
Second step: Calculate velocities using: (x2 - x1)/(t2 - t1); the slope formula. The interval should match the interval of the recordings.
Calculations:
Direction change:
A direction change occurs where the acceleration is zero. Use numeric integration to find these times. Integrate from 0 until a time when the result of the integration is zero. Record this time. Then, integrate from the previous time until you get zero again. Repeat until you hit the end of the data.
Initial accelerations:
These are found using the slope formula again, substituting v for x.
Average speed:
The average speed formula is the slope formula. x1 and t1 should correspond to the first reading, and x2 and t2 should correspond to the final reading.

Related

How do you calculate a rectangular wave from input values?

Here's a picture to make it a little easier:
The blue line represents some input values that resemble waves with variable amplitudes and lengths. The y axis represents the values, the x axis represents time. Please note that there is quite some jitter in the wave. However, every wave has a certain minimum and maximum length.
The green line shows how the input values should be transformed.
Please note: The above picture is just a hand drawn example to explain the task. In an ideal case, the position of the rising and falling edges of the rectangular (green) wave are close to the blue waves average value. The height/amplitude of the green wave segments should match the values of the blue wave.
How do you calculate the green line?
Do you know of any C# libraries or algorithms to do that? I guess this could be a rather common task for electrical engineers, so there are most likely some common approaches available. If so, how are hey called?
How would you approach this requirements?
Any advice that helps in getting started is welcome.
Take a base frequency (f) at an amplitude (a).
Then add ODD harmonics with the inverse amplitude ie f * a + f3 * a/3 + f5 * a/5 + f7 * a/7 ...
This will tend towards a square wave as you add harmonics.
BTW Try doing the same with even harminics, and with all the harmonics - Great fun!!!
Good luck
Tony

Calculation of orig, norm attributes of NormContinous in PMML

Overview
I am currently working on a normalization PMML-Model executor in c#.
These PMML normalization models look like this:
<TransformationDictionary>
<DerivedField displayName="BU01" name="BU01*" optype="continuous" dataType="double">
<Extension name="summary" extender="KNIME" value="Min/Max (0.0, 1) normalization on 17 column(s)"/>
<NormContinuous field="BU01">
<LinearNorm orig="0.0" norm="-0.6148417019560395"/>
<LinearNorm orig="1.0" norm="-0.6140350877192982"/>
</NormContinuous>
</DerivedField>
(...)
I do know how min-max normalization in theory works using
z_i = (x_i - min(x)) / (max(x) - min(x))
to normalize a dataset into the range of 0-1 and obviously it's not hard to reverse this equation.
Problem
So to execute the normlization and denormalization I somehow have to translate this orig, norm values into min, max values. But I just can't figure out how these orig/norm values are being calculated and how they relate to min/max.
Question
So I'm asking if some does know an equation to transform orig/norm to min/max and back. Or is someone able to explain how to directly use orig/norm values to normalize/denormalize my fields?
Further Explanation
EDIT: It loks like as if I did not state clearly what the problem exactly is so here is another approach:
I try to get an attribut of a dataset normalized into the range from 0-1 using Min-Max normalization method (aka Feature Scaling). Using the Data Analysis tool Knime I can do this and export my "scaling" as a PMML Model. (Example of this is the XML provided above)
With these normalized attributes I train my MLP Model. Now if I export my MLP Model as PMML I have to put normalized values in and get normalized output out when caluclating a prediction. (Computing the MLP Network already works)
In a deployed scenario where Knime can't do this normalization for me I want to use my normalization Model. As already described I do know the theory behing Feature Scaling and can easily compute de-/normalization if I am provided with min and max of my attribute. The problem is that PMML has another let's say "notation" for saving this min-max information which is somehow inside the orig and norm value.
So what I am ultimately looking for is a way to convert orig/norm to min/max or how min/max information is "encoded" into orig/norm values.
Extra Info
[Why this "encoding" is done in the first place seems to be because computation speed reasons (which is not important in my scenario) and to easier encode min/max normlization info for ranges other than 0-1.]
Example #1
To give an example:
Let's say I want to normalize the array of [0, 1, 2, 4, 8] into the range of 0-1. Clearly the answer is [0, 0.125, 0.25, 0.5, 1] as computed by Feature Scaling with min = 0, max = 8. Easy. But now if I look at the PMML normalization Model:
<TransformationDictionary>
<DerivedField displayName="column1" name="column1*" optype="continuous" dataType="double">
<Extension name="summary" extender="KNIME" value="Min/Max (0.0, 1) normalization on 1 column(s)"/>
<NormContinuous field="column1">
<LinearNorm orig="0.0" norm="0.0"/>
<LinearNorm orig="1.0" norm="0.125"/>
</NormContinuous>
</DerivedField>
</TransformationDictionary>
Example #2
[1, 2, 4, 8] -> [0, 0.333, 0.667, 1]
With:
<TransformationDictionary>
<DerivedField displayName="column1" name="column1*" optype="continuous" dataType="double">
<Extension name="summary" extender="KNIME" value="Min/Max (0.0, 1) normalization on 1 column(s)"/>
<NormContinuous field="column1">
<LinearNorm orig="0.0" norm="-0.3333333333333333"/>
<LinearNorm orig="1.0" norm="0.0"/>
</NormContinuous>
</DerivedField>
</TransformationDictionary>
Question
So how am I supposed to scale with orig/norm or compute min/max from these values?
What I'm about to say depends on what you mean by (min, max).
I'm going to assume that min equals the value where 0.5% of the total lies below and max equals the value where 0.5% of the total lies above.
If we agree on that, a symmetric normal distribution would have a mean value of approximately mean ~ (max+min)/2. (You call the mean the origin.)
Six standard deviations encompasses 99% of a normal distribution, so the standard deviation is approximately sigma ~ (max-min)/6.
The definition of normalized z = (x - mean)/sigma.
With those values you can get yourself back to the denormalized distribution.
Found the answer. After carefully reading again through the Documentation (which is extremly confusing imo) i came across this sentence:
The sequence of LinearNorm elements defines a sequence of points for a stepwise linear interpolation function. The sequence must contain at least two elements. Within NormContinous the elements LinearNorm must be strictly sorted by ascending value of orig.
Which basically explains it all. Normalization in PMML is done by using a stepwise interpolation with only 2 points. So in fact just a simple conversion function.
In the case of normalization into a range of 0-1 it even get's easier as the two points will always be at x1=0 and x2=1 (orig values). And will therefore always have their y axis intercept at orig=0 norm-value. As far as the slope of the function is concerned it is also very easy to calculate by slope = (y2-y1)/(x2-x1) = (y2-y1)/(1-0) = y2-y1 which are just the 2 norm-values.
So to get our interpolation function which will always be a polynom 1st grade we just calculate:
f(x) = ax + b = (y2-y1)x + y1 = (norm(orig=1)-norm(orig=0) * x + norm(orig=0) This is used for normalization.
and now we can calculate the inverse:
x = (f(x) - norm(orig=0)) / (norm(orig=1)-norm(orig=0)) This is used for de-normalization
Hope this helps everyone who at someday will also go through the hassle of implementing their own PMML executor engine and gets stuck at this topic.

Solving for Amplitude and Frequency in WAV files

I've also asked this here on the Sound Design forum, but the question is heavy computer science/math so it might actually belong on this forum:
So I'm able to successfully find all the information about a WAV file except the amplitude and the frequency (hertz) of the big sin function by reading the binaries in the file (which are unfortunately exactly what I'm looking for). Just to verify what I'm talking about, the file generates one wave only with the equation:
F(s) = A * sin(T * s)
Where s is the current sample, A is the amplitude and T is the period. Now the equation for the T (period) is:
T = (2π * Hz) /(α * ω)
Where Hz is frequency in Hertz, α is Samples per second, and ω is the amount of channels.
Now I know that to solve for amplitude, I could simply find the value of F(s) where
s = (π/2)/T
Because then the value of the sine function would be 1, and the final value would be equivalent to A. The problem is that to divide by T, I have to know the Hertz (or Hz).
Is there any way that I can read a WAV file to discover the Hertz from the data, assuming the file only contains a single wave.
Just to get some terms clarified, the property you're looking for is frequency, and the unit of frequency is Hertz (once per second). By convention, the typical A note has a frequency of 440 Hz.
You got the function wrong, actually. That sine wave in reality has the form F(s) = A * sin(2*pi*s/T + c) - you don't know when it started so you get a constant c in there. Also, you need to divide by T, not multiply.
Getting the amplitude is actually fairly easy. That sine wave has a series op peaks and valleys. Find each peak (higher than both neighbors) and each valley (lower), calculate the average peak and average valley, and the amplitude is TWICE the difference between the two. Pretty easy. The period T can be estimated by counting the average distance from peak to peak, and from valley to valley.
There's one bit where you need to be careful. If there is a slight bit of noise, you may get a slight dent near a peak. Instead of 14 17 18 17 14 you may get 14 17 16 17 14. That 16 isn't a valley. Once you've got a good estimate for the real peaks and valleys, throw out all the distorted peaks.
The question isn't "what frequency?". If your function is anything other than a simple trig function it'll be a combination of frequencies, each with their own amplitude.
The correct approach is digital signal processing using finite Fourier transform. You've got a lot of digging to do.
If you only want to assume a single trig function, you have just 2 (amplitude and frequency) or 3 degrees of freedom (amplitude, frequency, and phase angle) and N time points in the file. That means least squares fitting assuming a sine or cosine function.

How to simulate pendulum movement with high amplitude in C#

I need to make a C# simulator for a simple pendulum.
I have been searching the web for 3 days and I am stuck.
The problem is I have found many equations that would give the angle position as a function of time, which is perfect for my needs for making a visual simulation but the problem is those functions only works for angles smaller than 10, but I should be able to simulate from any angle.
Example of a equation that only works for small angles:
Source: http://hyperphysics.phy-astr.gsu.edu/hbase/pend.html#c2
And the equations that should work for any angle (Amplitude) are too complicated as it involves differential equations, and derivatives. I don't know how to implement these in C#.
Example of a equation that I think would work but I don't know how to use:
Source: http://www.sbfisica.org.br/rbef/pdf/070707.pdf
(Equation number 32)
the problem of this last equation is the "sn" that is Jacobi elliptic function sn(u;m) u, and I don't know how to use in C#
Can someone help? maybe with another equation that I could use programmatically, or helping me understand how I could use this last one if it would really works.
If you want to simulate the pendulum, you don't need the exact solution. The only you need is a sufficiently good approximation at every step of your simulation, combined with sufficient steps. This is similar to approximating a circle with a sufficiently large number of segments, each of them, tangent to the ideal circle.
Now, consider your pendulum has a deviation of theta degrees (or radians) from the vertical as depicted below:
The mass m will have a weight of m * g, where g is the gravity acceleration. Now, let's approximate the angle alpha where the pendulum will move in the next dt seconds (dt is the duration of one step, so dt is just a fraction of a second).
Since the acceleration on the tangent direction is g * cos(theta) we can approximate the tangent distance the pendulum would travel in dt seconds as if the acceleration were constant during this lapse:
d = v * dt + g * sin(theta) (dt)^2 / 2
where v is the tangential speed of the pendulum at the angular position theta. Now we can calculate alpha as
alpha = arcsin(d / r)
where r is the radius. Thus, the only that remains is to update the value of v so we can repeat the same in the next step. Here is how
v := v + g * sin(theta) * dt
Of course, when the pendulum starts you can initialize v = 0.
I haven't tried this myself, so please, let me know if this "simulated" approach worked for you. Good luck!

Vertical Curve Formula

I'm making just a basic application that just writes pixels along a curve in C#.
I came across this website with a formula that looks promising. I believe this website is also talking about the same thing here.
What I don't really understand is how to implement it. I tried looking at the JavaScript code on the first link but I can't really tell what data I need to supply. The things involving the PVC, PVI, or PVT are the things I don't understand.
The example situation I'm going to set up is just both of the grades (vertical incline/decline) is just 5 and -5. Let's say point 1 is at 0, 0 and point 2 is 100, 100.
Can someone explain some of the obscure variables in the formula and how would I use the formula to draw the curve?
Generally, to draw a curve in 2D you vary one parameter, and then collect x,y point pairs, and plot the pairs. In your case it will work to just vary the horizontal distance (x), and then collect the corresponding y-values, and then you can plot these.
As for the formula, it is very unclear. Basically it's just a parabola with a bunch of (poorly defined) jargon around it. To graph this, you want to vary x from 0 to L (this isn't obvious, btw, I had to work out the math, i.e., how to vary x so that the slopes would be as they suggest in the figure, anyway, it's 0 to L, and they should have said so).
I don't have C# running now, but hopefully you can translate this Python code:
from matplotlib.pyplot import plot, show
from numpy import arange
G1 = .1 # an initial slope (grade) of 10% (note that one never uses percentages directly in calculations, it's always %/100)
G2 = -.02 # a final slope (grade) of 2%
c = 0 # elevation (value of curve when x=0, that is, y at PVC
L = 10. # the length of the curve in whatever unit you want to use (ft, m, mi, etc), but this basically sets your unit system
N = 1000 # I'm going to calculate and plot 100 points to illustrate this curve
x = arange(0, L, float(L)/N) # an array of N x values from 0 to (almost) L
# calculate the curve
a = (G2-G1)/(2*L)
b = G1
y = a*x*x + b*x + c # this is shorthand for a loop y[0]=a*x[0]*x[0] + b*...
plot(x, y)
show()
print (y[1]-y[0])/(x[1]-x[0]), (y[-1]-y[-2])/(x[-1]-x[-2])
The final line prints the initial and final slopes as a check (in Python neg indexing counts from the back of the array), and this match what I specified for G1 and G2. The plot looks like:
As for your requests: "The example situation I'm going to set up is just both of the grades (vertical incline/decline) is just 5 and -5. Let's say point 1 is at 0, 0 and point 2 is 100, 100.", in a parabola you basically get three free parameters (corresponding to a, b, and c), and here, I think, you over-specified it.
What are PVC, PVT, and PVI? PVC: the starting point, so Y_PVC is the height of the starting point. PVT: the ending point. PVI: if you draw a line from PVC at the initial slope G1 (ie the tangent to the curve on the left), and similarly from PVT, the point where they intersect is called PVI (though why someone would ever care about this point is beyond me).

Categories

Resources