I need to calculate a value based on a formula that I've checked there, as we can see in this screenshot:
I've tried to this equation in my C# app, but I don't get the expected values.
For example, I've created a basic console app:
public static void Calculate()
{
var values = new double[] { 1, 0.75, 0.5, 0.25, 0};
// y = - ((4/3) * x^3) + (3 * x^2) - ((2/3) * x)
foreach (var value in values)
{
var calcul1 = - ((4 / 3) * Math.Pow(value, 3))
+ (3 * Math.Pow(value, 2))
- ((2 / 3) * value);
var calcul2 = ((-4 / 3) * (value * value * value))
+ (3 * (value * value))
+ ((-2 / 3) * value);
Console.WriteLine($"value: {value} - calcul1: {calcul1} / calcul2: {calcul2}");
}
}
I get these results, that are not close to the expected results:
value: 1 - calcul1: 2 / calcul2: 2
value: 0.75 - calcul1: 1.265625 / calcul2: 1.265625
value: 0.5 - calcul1: 0.625 / calcul2: 0.625
value: 0.25 - calcul1: 0.171875 / calcul2: 0.171875
value: 0 - calcul1: 0 / calcul2: 0
What's wrong? Is it related to the use of double?
I refactored your code in order to obtain the correct values.
If you perform a division calculation without a explicit casting c# Implicitly cast to an integer, discarding the decimal part:
public static void Calculate()
{
var values = new double[] { 1, 0.75, 0.5, 0.25, 0};
// y = - ((4/3) * x^3) + (3 * x^2) - ((2/3) * x)
foreach (var value in values)
{
double firstFraction = (double)4/3;
double secondFraction = (double)2/3;
var calcul1 = - (firstFraction * Math.Pow(value, 3))
+ (3 * Math.Pow(value, 2))
- (secondFraction * value);
var calcul2 = ((firstFraction*-1) * (value * value * value))
+ (3 * (value * value))
+ ((secondFraction*-1) * value);
Console.WriteLine($"value: {value} - calcul1: {calcul1} / calcul2: {calcul2}");
}
}
You need to be more carefull with your data types.
as a test try to show the output for
var calc = (4 / 3) * 0.5;
Console.WriteLine(calc); //-> shows 0.5
because 4 and 3 are integers which is a data type without decimal point, 4/3 = 1
you can force 4 and 3 to be evaluated as doubles using literals floating point documentation
like this:
var calc = (4D / 3D) * 0.5;
Console.WriteLine(calc); //-> shows 0.666666666666667
see dotnetfiddle for an online example
Related
I'm going through "sololearn" and udemy courses to try to learn C#. I am doing the challenges but could not figure out how the below code resulted with 32 (as in 32 is the correct answer here and I am trying to find out why). Can someone explain this process to me, the method calling itself is throwing me I think.
static double Pow(double x, int y)
{
if (y == 0)
{
return 1.0;
}
else
{
return x * Pow(x, y - 1);
}
}
static void Main()
{
Console.Write(Pow(2, 5));
}
Please excuse my bad coding. I am trying to do it on mobile, which is difficult, the answer was 32. Can someone explain why?
Edit: Aplogies here is how I work through it. Pass 2 and 5 to Pow, check if y == 0 which is false, it is now y == 5 so x * pow(x, y-1) formula will be active. X is still 2, y is now 4 which means it fails the check again on whether it equals 0, this loop continues until it returns the 1.0, x has remained at 2 so 2 * 1.0 = 2 and not 32?
First thing to note is that this is NOT how you would normally implement a power function. It's done this way to demonstrate recursion.
With that out the way, let's look at what happens when you call Pow(2, 5):
Pow(x = 2, y = 5)
-> return 2 * Pow(2, 4)
<- 2 * 16 = 32
Pow(x = 2, y = 4)
-> return 2 * Pow(2, 3)
<- 2 * 8 = 16
Pow(x = 2, y = 3)
-> return 2 * Pow(2, 2)
<- 2 * 4 = 8
Pow(x = 2, y = 2)
-> return 2 * Pow(2, 1)
<- 2 * 2 = 4
Pow(x = 2, y = 1)
-> return 2 * Pow(2, 0)
<- 2 * 1 = 2
Pow(x = 2, y = 0)
-> return 1 (because y == 0)
<- 1
To read this representation of the recursive call stack, work your way from the top to the bottom looking at how the arguments change; then work your way back up from the bottom to the top looking at the return values (which I indicate with <-).
Ok so let's go through the whole thing.
First of all, a static function is one that can be called without need to instantiate an object. There is one signature that all objects of the same class share. The double is a type within C# and its appearing here to show what the final output type of the function will be. Pow is the name of the function, double x, int y are parameters described by their type (not very well named but we'll leave that for another day)
So x is a number and y is the power of that number. There is a conditional here to check for two outcomes. If y is 0 then the answer is always 1, simple maths. Otherwise, the function performs the arithmetic using recursion (it calls itself again until it meets a terminating condition). The reason we get 32 is because 2x2x2x2x2 = 32. It is 2 to the power of 5.
I'm presuming you know what main and console.write are.
That method basically computes "x raised to the power of y". It does this in a recursive manner.
First, it defines a base case: anything raised to the power of 0 is 1.
Then, it defines what to do in all other cases: x * Pow(x, y - 1). Assuming y is big, what's x * Pow(x, y - 1)? It's x * x * Pow(x, y - 2), which in turn is x * x * x * Pow(x, y - 3). See the pattern here? Eventually, you will reach the point where the second argument, y - N, is 0, which as we have established, is 1. At that point, how many x * have we got? Exactly y.
Let's see this in action for Pow(2, 5):
Pow(2, 5)
2 * Pow(2, 4)
2 * 2 * Pow(2, 3)
2 * 2 * 2 * Pow(2, 2)
2 * 2 * 2 * 2 * Pow(2, 1)
2 * 2 * 2 * 2 * 2 * Pow(2, 0)
2 * 2 * 2 * 2 * 2 * 1
Hence the result 32.
Hello its recursion and it repeat until y=1, then return 2,then return 4, 8, 16, 32 at then end. 2^5=32
To be able to understand each action in this recursive behavior log all the details to see what is actually going on. Such as :
using System;
namespace Tester
{
class test
{
// What Pow actually does:
static double logPow(double x, int y) {
var old = x; // Hold the x
for (var i = 0; i < y; i++){ // do it y times
x = old * x; // Multiply with it's first self
}
return x;
}
static int counter = 0;
static double Pow(double x, int y) {
counter++;
Console.Write("Recursive action[" + counter + "] Y status ["+ y +"] : ");
if (y == 0)
{
Console.Write("return 1.0 = " + logPow(x, y) + " \n");
return 1.0;
}
else
{
Console.Write("return " + x + " * Pow(" + x + ", " + y + " - 1) = " + logPow(x,y-1) + " \n");
return x * Pow(x, y - 1);
}
}
static void Main() {
Console.Write("Last Result : " + Pow(2, 5));
}
}
}
Which gives the result :
Recursive action[1] Y status [5] : return 2 * Pow(2, 5 - 1) = 32
Recursive action[2] Y status [4] : return 2 * Pow(2, 4 - 1) = 16
Recursive action[3] Y status [3] : return 2 * Pow(2, 3 - 1) = 8
Recursive action[4] Y status [2] : return 2 * Pow(2, 2 - 1) = 4
Recursive action[5] Y status [1] : return 2 * Pow(2, 1 - 1) = 2
Recursive action[6] Y status [0] : return 1.0 = 2
Last Result : 32
You can debug your code by looking at these details.
Also you can have fun with it using this link : https://onlinegdb.com/Bysbxat9H
I'm trying to find real roots for a cubic equation defined by a set of four coefficients by using Cardano method as described here. The problem is, the roots found by my implementation do not actually work - testing by inserting them in the equation give a significant error (more than the required 10^-6). Is the algorithm implemented wrong, or the error is caused by something else, like rounding accuracy?
static double CubicRoot(double n)
{
return Math.Pow(Math.Abs(n), 1d / 3d) * Math.Sign(n);
}
public static List<double> SolveCubic(double A, double B = 0, double C = 0, double D = 0)
{
List<double> output = new List<double>();
if (A != 0)
{
double A1 = B / A;
double A2 = C / A;
double A3 = D / A;
double P = -((A1 * A1) / 3) + A2;
double Q = ((2.0 * A1 * A1 * A1) / 27.0) - ((A1 * A2) / 3.0) + A3;
double cubeDiscr = Q * Q / 4.0 + P * P * P / 27.0;
if (cubeDiscr > 0)
{
double u = CubicRoot(-Q / 2.0 + Math.Sqrt(cubeDiscr));
double v = CubicRoot(-Q / 2.0 - Math.Sqrt(cubeDiscr));
output.Add(u + v - (A1 / 3.0));
return output;
}
else if (cubeDiscr == 0)
{
double u = CubicRoot(-Q / 2.0);
output.Add(2u - (A1 / 3.0));
output.Add(-u - (A1 / 3.0));
}
else if (cubeDiscr < 0)
{
double r = CubicRoot(Math.Sqrt(-(P * P * P / 27.0)));
double alpha = Math.Atan(Math.Sqrt(-cubeDiscr) / (-Q / 2.0));
output.Add(r * (Math.Cos(alpha / 3.0) + Math.Cos((6 * Math.PI - alpha) / 3.0)) - A1 / 3.0);
output.Add(r * (Math.Cos((2 * Math.PI + alpha) / 3.0) + Math.Cos((4 * Math.PI - alpha) / 3.0)) - A1 / 3.0);
output.Add(r * (Math.Cos((4 * Math.PI + alpha) / 3.0) + Math.Cos((2 * Math.PI - alpha) / 3.0)) - A1 / 3.0);
}
}
return output;
}
A few things
Math.Sign will return zero on zero, which happens to be what you want in this case, but perhaps you are not so lucky with code or algorithm change.
You will have rounding issues and not execute cubeDiscr == 0 branch when you should. You may have rounding issues and execute the wrong > 0 and < 0 branch for the same reason. Test within a delta of zero instead (see below).
But the cubeDiscr == 0 branch is wrong because 1) you didn't calculate v and 2) 2u is an UInt32 with a value of 2, not 2*u.
Calculating alpha is wrong (see below)
(there may be more, but that's all I saw at a quick glance)
On calculating alpha:
double alpha = Math.Atan(Math.Sqrt(-cubeDiscr) / (-Q / 2.0));
is not the same as
double alpha = Math.Atan(Math.Sqrt(-d) / q * 2.0);
if (q > 0) // if q > 0 the angle becomes PI + alpha
alpha = Math.PI + alpha;
What's wrong with using the code included from that page?
public double Xroot(double a, double x)
{
double i = 1;
if (a < 0)
i = -1;
return (i * Math.Exp( Math.Log(a*i)/x));
}
public int Calc_Cardano() // solve cubic equation according to cardano
{
double p, q, u, v;
double r, alpha;
int res;
res = 0;
if (a1 != 0)
{
a = b / a1;
b = c / a1;
c = d / a1;
p = -(a * a / 3.0) + b;
q = (2.0 / 27.0 * a * a * a) - (a * b / 3.0) + c;
d = q * q / 4.0 + p * p * p / 27.0;
if (Math.Abs(d) < Math.Pow(10.0, -11.0))
d = 0;
// 3 cases D > 0, D == 0 and D < 0
if (d > 1e-20)
{
u = Xroot(-q / 2.0 + Math.Sqrt(d), 3.0);
v = Xroot(-q / 2.0 - Math.Sqrt(d), 3.0);
x1.real = u + v - a / 3.0;
x2.real = -(u + v) / 2.0 - a / 3.0;
x2.imag = Math.Sqrt(3.0) / 2.0 * (u - v);
x3.real = x2.real;
x3.imag = -x2.imag;
res = 1;
}
if (Math.Abs(d) <= 1e-20)
{
u = Xroot(-q / 2.0, 3.0);
v = Xroot(-q / 2.0, 3.0);
x1.real = u + v - a / 3.0;
x2.real = -(u + v) / 2.0 - a / 3.0;
res = 2;
}
if (d < -1e-20)
{
r = Math.Sqrt(-p * p * p / 27.0);
alpha = Math.Atan(Math.Sqrt(-d) / q * 2.0);
if (q > 0) // if q > 0 the angle becomes PI + alpha
alpha = Math.PI + alpha;
x1.real = Xroot(r, 3.0) * (Math.Cos((6.0 * Math.PI - alpha) / 3.0) + Math.Cos(alpha / 3.0)) - a / 3.0;
x2.real = Xroot(r, 3.0) * (Math.Cos((2.0 * Math.PI + alpha) / 3.0) + Math.Cos((4.0 * Math.PI - alpha) / 3.0)) - a / 3.0;
x3.real = Xroot(r, 3.0) * (Math.Cos((4.0 * Math.PI + alpha) / 3.0) + Math.Cos((2.0 * Math.PI - alpha) / 3.0)) - a / 3.0;
res = 3;
}
}
else
res = 0;
return res;
}
I have this function:
private double getTotal(string str)
{
double total = 0;
byte[] asciiBytes = Encoding.ASCII.GetBytes(str);
foreach(int c in asciiBytes)
{
total = total + c;
total = total * (5 * (c ^ 2) / (c*6));
}
return Math.Round(total);
}
This is used to get a total of a strings ASCII values but does some math along the way rather than just adding. I need this to return the total, but is currently returning 0. How can I make it return the correct value? (PS: It needs to return an integer, but this can be in the datatype of a double for conversion later. Basically just need it to return a whole number.) (PSPS: I don't know what the string will be, it's up to the end user)
_
You probably misunderstood the ^ sign. It stands for a bitwise exclusive or, rather than an exponentiation. If you want to use the latter, use this:
total = total * (5 * (Math.Pow (c, 2) / (c * 6));
However, you could write it shorter/more beautiful/more efficient as well:
total *= (5 * (c * c) / (6 * c));
I replaced the Pow, as it is slower than a simple multiplication and used an assignment-operator.
Furthermore, the equation itself can be simplified:
total *= c * (5 / 6);
However, you should still mark the numbers as doubles, as 5/6 would result in 0 otherwise:
total *= c * (5.0 / 6.0)
For more information on exponentiation in C#, have a look at this.
By the way, the ^ sign takes every bit of the numbers and compares them. The new value will be 1 if the first bit or the second bit, but not both bits are 1.
So for example 0101 xor 1110 would result in 1011.
You have casting problem. The c variable is integer. Your problem is in the total = total * (5 * (c ^ 2) / (c*6)); expression.
Because the internal results (c ^ 2) and (c*6) aren't double, when the division result has floating point such as 0.nnnnn, the final result isn't double and you get only the 0 which is the real part of the number. And the result expression (5 * (c ^ 2) / (c*6)) as an Integer is 0. Finally the expression is as total=total * (0);
Use internal castings in your code
Replace your code with the following :
total = total * (5 * ((double)(c ^ 2)) / ((double)(c * 6)));
Please run the following code
static private double getTotal(string str)
{
double total = 0;
byte[] asciiBytes = Encoding.ASCII.GetBytes(str);
foreach (int c in asciiBytes)
{
double dC = c;
total = total + c;
double cXor2 = c ^ 2;
double c6 = c * 6;
double fiveCXor2 = 5 * cXor2;
double semiFinal = fiveCXor2 / c6;
double final = total * semiFinal;
Console.WriteLine("c = " + (c).ToString());
Console.WriteLine("c ^ 2 = " + (cXor2).ToString());
Console.WriteLine("c * 6 = " + (c6).ToString());
Console.WriteLine("5 * (c ^ 2) = " + (fiveCXor2).ToString());
Console.WriteLine("semi final = " + semiFinal);
Console.WriteLine("final = " + final);
Console.WriteLine("--------------------------------------------");
total = total * (5 * (c ^ 2) / (c * 6));
Console.WriteLine("TOTAL = " + total);
Console.WriteLine("--------------------------------------------");
}
return Math.Round(total);
}
Sample result is :
c = 97
c ^ 2 = 99
c * 6 = 582
5 * (c ^ 2) = 495
semi final = 0.850515463917526
final = 82.5
--------------------------------------------
TOTAL = 0
--------------------------------------------
c = 98
c ^ 2 = 96
c * 6 = 588
5 * (c ^ 2) = 480
semi final = 0.816326530612245
final = 80
--------------------------------------------
TOTAL = 0
--------------------------------------------
As you can see the problem is casting
Because the c variable is int the casting procedure is :
step 1
[double] = [double] * ([int] * ([int] ^ [int] ) / ([int] * [int] ))
total = total * (5 * (c ^ 2 ) / (c * 6 ));
step 2
[double] = [double] * ([int] * ([int]) / ([int] ))
total = total * (5 * (X) / (Y) );
step 3
[double] = [double] * ([int] * [int]))
total = total * (5 * XdivY );
**CASTING PROBLEM : In this step the XdivY is integer and when the result is 0.1234 the INT result is 0**
step 4
[double] = [double] * ([double]))
total = total * (5mulXdivY );
here c# casting the 5mulXdivY 0 to double but the result is zero
step 5
[double] = [double]
total = 0
Problem is with the this line in your code
total = total * (5 * (c ^ 2) / (c*6));
c ^ 2 returns a smaller value than c*6. Now the operator / is integer division so the result of a smallnumber/largenumber will always return zero. This will make the value of variable total zero in every iteration of the loop. Change the code like this and it will give you the result you expect.
private double getTotal(string str)
{
double total = 0;
byte[] asciiBytes = Encoding.ASCII.GetBytes(str);
foreach (int c in asciiBytes)
{
total = total + c;
total = total * (5 * (double)(c ^ 2) / (double)(c * 6));
}
return Math.Round(total);
}
Hope it helps.
Add double to one of the ints
private double getTotal(string str)
{
double total = 0;
byte[] asciiBytes = Encoding.ASCII.GetBytes(str);
foreach (int c in asciiBytes)
{
total = total + c;
total = total * ((double)5 * (c ^ 2) / (c * 6));
}
return Math.Round(total);
}
I have this recurring function and I need to write it using dynamic programming. The problem is that it returns double, not int and I can't change that. If it was returning integer, I could store returned value at corresponding index in array and later use it to find other values.
static double f(double n)
{
if(n > 1)
{
return f(n - 3) + (9 * (f(n / 5) * f(n / 5))) + (2 * f(n - 7))
+ ((n * n * n * n) / 2);
}
else
{
return 4;
}
}
For example if n=1 I know that result is 4 so I can store ir as data[1]=4; but when I geto to n=6 this doesn't work because 6/5 = 1.2 and I don't know what functions result of 1.2 is and I could not store it using array. I could use dictionary to store key-value pair, but then again, I wouldn't know what result is of 1.2.
I think you could use a Dictionary<double,double> to store the results:
private static Dictionary<double, double> results = new Dictionary<double, double>();
private static double f(double n)
{
if (results.ContainsKey(n)) return results[n];
double result = (n > 1)
? f(n - 3) + (9 * (f(n / 5) * f(n / 5))) +
(2 * f(n - 7)) + ((n * n * n * n) / 2)
: 4;
results.Add(n, result);
return result;
}
Trying to find functions that will assist us to draw a 3D line through a series of points.
For each point we know: Date&Time, Latitude, Longitude, Altitude, Speed and Heading.
Data might be recorded every 10 seconds and we would like to be able to guestimate the points in between and increase granularity to 1 second. Thus creating a virtual flight path in 3D space.
I have found a number of curve fitting algorithms that will approximate a line through a series of points but they do not guarantee that the points are intersected. They also do not take into account speed and heading to determine the most likely path taken by the object to reach the next point.
From a physics viewpoint:
You have to assume something about the acceleration in your intermediate points to get the interpolation.
If your physical system is relatively well-behaved (as a car or a plane), as opposed to for example a bouncing ball, you may go ahead supposing an acceleration varying linearly with time between your points.
The vector equation for a constant varying accelerated movement is:
x''[t] = a t + b
where all magnitudes except t are vectors.
For each segment you already know v(t=t0) x(t=t0) tfinal and x(tfinal) v(tfinal)
By solving the differential equation you get:
Eq 1:
x[t_] := (3 b t^2 Tf + a t^3 Tf - 3 b t Tf^2 - a t Tf^3 - 6 t X0 + 6 Tf X0 + 6 t Xf)/(6 Tf)
And imposing the initial and final contraints for position and velocity you get:
Eqs 2:
a -> (6 (Tf^2 V0 - 2 T0 Tf Vf + Tf^2 Vf - 2 T0 X0 + 2 Tf X0 +
2 T0 Xf - 2 Tf Xf))/(Tf^2 (3 T0^2 - 4 T0 Tf + Tf^2))
b -> (2 (-2 Tf^3 V0 + 3 T0^2 Tf Vf - Tf^3 Vf + 3 T0^2 X0 -
3 Tf^2 X0 - 3 T0^2 Xf + 3 Tf^2 Xf))/(Tf^2 (3 T0^2 - 4 T0 Tf + Tf^2))}}
So inserting the values for eqs 2 into eq 1 you get the temporal interpolation for your points, based on the initial and final position and velocities.
HTH!
Edit
A few examples with abrupt velocity change in two dimensions (in 3D is exactly the same). If the initial and final speeds are similar, you'll get "straighter" paths.
Suppose:
X0 = {0, 0}; Xf = {1, 1};
T0 = 0; Tf = 1;
If
V0 = {0, 1}; Vf = {-1, 3};
V0 = {0, 1}; Vf = {-1, 5};
V0 = {0, 1}; Vf = {1, 3};
Here is an animation where you may see the speed changing from V0 = {0, 1} to Vf = {1, 5}:
Here you may see an accelerating body in 3D with positions taken at equal intervals:
Edit
A full problem:
For convenience, I'll work in Cartesian coordinates. If you want to convert from lat/log/alt to Cartesian just do:
x = rho sin(theta) cos(phi)
y = rho sin(theta) sin(phi)
z = rho cos(theta)
Where phi is the longitude, theta is the latitude, and rho is your altitude plus the radius of the Earth.
So suppose we start our segment at:
t=0 with coordinates (0,0,0) and velocity (1,0,0)
and end at
t=10 with coordinates (10,10,10) and velocity (0,0,1)
I clearly made a change in the origin of coordinates to set the origin at my start point. That is just for getting nice round numbers ...
So we replace those numbers in the formulas for a and b and get:
a = {-(3/50), -(3/25), -(3/50)} b = {1/5, 3/5, 2/5}
With those we go to eq 1, and the position of the object is given by:
p[t] = {1/60 (60 t + 6 t^2 - (3 t^3)/5),
1/60 (18 t^2 - (6 t^3)/5),
1/60 (12 t^2 - (3 t^3)/5)}
And that is it. You get the position from 1 to 10 secs replacing t by its valus in the equation above.
The animation runs:
Edit 2
If you don't want to mess with the vertical acceleration (perhaps because your "speedometer" doesn't read it), you could just assign a constant speed to the z axis (there is a very minor error for considering it parallel to the Rho axis), equal to (Zfinal - Zinit)/(Tf-T0), and then solve the problem in the plane forgetting the altitude.
What you're asking is a general interpolation problem. My guess is your actual problem isn't due to the curve-fitting algorithm being used, but rather your application of it to all discrete values recorded by the system instead of the relevant set of values.
Let's decompose your problem. You're currently drawing a point in spherically-mapped 3D space, adjusting for linear and curved paths. If we discretize the operations performed by an object with six degrees of freedom (roll, pitch, and yaw), the only operations you're particularly interested in are linear paths and curved paths accounting for pitch and yaw in any direction. Accounting for acceleration and deceleration also possible given understanding of basic physics.
Dealing with the spherical mapping is easy. Simply unwrap your points relative to their position on a plane, adjusting for latitude, longitude, and altitude. This should allow you to flatten data that would otherwise exist along a curved path, though this may not strictly be necessary for the solutions to your problem (see below).
Linear interpolation is easy. Given an arbitrary number of points backwards in time that fit a line within n error as determined by your system,* construct the line and compute the distance in time between each point. From here, attempt to fit the time points to one of two cases: constant velocity or constant acceleration.
Curve interpolation is a little more difficult, but still plausible. For cases of pitch, yaw, or combined pitch+yaw, construct a plane containing an arbitrary number of points backwards in time, within m error for curved readouts from your system.* From these data, construct a planar curve and once again account for constant velocity or acceleration along the curve.
You can do better than this by attempting to predict the expected operations of a plane in flight as part of a decision tree or neural network relative to the flight path. I'll leave that as an exercise for the reader.
Best of luck designing your system.
--
* Both error readouts are expected to be from GPS data, given the description of the problem. Accounting and adjusting for errors in these data is a separate interesting problem.
What you need (instead of modeling the physics) is to fit a spline through the data. I used a numerical recipies book (http://www.nrbook.com/a has free C and FORTRAN algorithms. Look into F77 section 3.3 to get the math needed). If you want to be simple then just fit lines through the points, but that will not result in a smooth flight path at all. Time will be your x value, and each parameter loged will have it's own cublic spline parameters.
Since we like long postings for this question here is the full code:
//driver program
static void Main(string[] args)
{
double[][] flight_data = new double[][] {
new double[] { 0, 10, 20, 30 }, // time in seconds
new double[] { 14500, 14750, 15000, 15125 }, //altitude in ft
new double[] { 440, 425, 415, 410 }, // speed in knots
};
CubicSpline altitude = new CubicSpline(flight_data[0], flight_data[1]);
CubicSpline speed = new CubicSpline(flight_data[0], flight_data[2]);
double t = 22; //Find values at t
double h = altitude.GetY(t);
double v = speed.GetY(t);
double ascent = altitude.GetYp(t); // ascent rate in ft/s
}
// Cubic spline definition
using System.Linq;
/// <summary>
/// Cubic spline interpolation for tabular data
/// </summary>
/// <remarks>
/// Adapted from numerical recipies for FORTRAN 77
/// (ISBN 0-521-43064-X), page 110, section 3.3.
/// Function spline(x,y,yp1,ypn,y2) converted to
/// C# by jalexiou, 27 November 2007.
/// Spline integration added also Nov 2007.
/// </remarks>
public class CubicSpline
{
double[] xi;
double[] yi;
double[] yp;
double[] ypp;
double[] yppp;
double[] iy;
#region Constructors
public CubicSpline(double x_min, double x_max, double[] y)
: this(Sequence(x_min, x_max, y.Length), y)
{ }
public CubicSpline(double x_min, double x_max, double[] y, double yp1, double ypn)
: this(Sequence(x_min, x_max, y.Length), y, yp1, ypn)
{ }
public CubicSpline(double[] x, double[] y)
: this(x, y, double.NaN, double.NaN)
{ }
public CubicSpline(double[] x, double[] y, double yp1, double ypn)
{
if( x.Length == y.Length )
{
int N = x.Length;
xi = new double[N];
yi = new double[N];
x.CopyTo(xi, 0);
y.CopyTo(yi, 0);
if( N > 0 )
{
double p, qn, sig, un;
ypp = new double[N];
double[] u = new double[N];
if( double.IsNaN(yp1) )
{
ypp[0] = 0;
u[0] = 0;
}
else
{
ypp[0] = -0.5;
u[0] = (3 / (xi[1] - xi[0])) *
((yi[1] - yi[0]) / (x[1] - x[0]) - yp1);
}
for (int i = 1; i < N-1; i++)
{
double hp = x[i] - x[i - 1];
double hn = x[i + 1] - x[i];
sig = hp / hn;
p = sig * ypp[i - 1] + 2.0;
ypp[i] = (sig - 1.0) / p;
u[i] = (6 * ((y[i + 1] - y[i]) / hn) - (y[i] - y[i - 1]) / hp)
/ (hp + hn) - sig * u[i - 1] / p;
}
if( double.IsNaN(ypn) )
{
qn = 0;
un = 0;
}
else
{
qn = 0.5;
un = (3 / (x[N - 1] - x[N - 2])) *
(ypn - (y[N - 1] - y[N - 2]) / (x[N - 1] - x[N - 2]));
}
ypp[N - 1] = (un - qn * u[N - 2]) / (qn * ypp[N - 2] + 1.0);
for (int k = N-2; k > 0; k--)
{
ypp[k] = ypp[k] * ypp[k + 1] + u[k];
}
// Calculate 1st derivatives
yp = new double[N];
double h;
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
yp[i] = (yi[i + 1] - yi[i]) / h
- h / 6 * (ypp[i + 1] + 2 * ypp[i]);
}
h = xi[N - 1] - xi[N - 2];
yp[N - 1] = (yi[N - 1] - yi[N - 2]) / h
+ h / 6 * (2 * ypp[N - 1] + ypp[N - 2]);
// Calculate 3rd derivatives as average of dYpp/dx
yppp = new double[N];
double[] jerk_ij = new double[N - 1];
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
jerk_ij[i] = (ypp[i + 1] - ypp[i]) / h;
}
Yppp = new double[N];
yppp[0] = jerk_ij[0];
for( int i = 1; i < N - 1; i++ )
{
yppp[i] = 0.5 * (jerk_ij[i - 1] + jerk_ij[i]);
}
yppp[N - 1] = jerk_ij[N - 2];
// Calculate Integral over areas
iy = new double[N];
yi[0] = 0; //Integration constant
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
iy[i + 1] = h * (yi[i + 1] + yi[i]) / 2
- h * h * h / 24 * (ypp[i + 1] + ypp[i]);
}
}
else
{
yp = new double[0];
ypp = new double[0];
yppp = new double[0];
iy = new double[0];
}
}
else
throw new IndexOutOfRangeException();
}
#endregion
#region Actions/Functions
public int IndexOf(double x)
{
//Use bisection to find index
int i1 = -1;
int i2 = Xi.Length;
int im;
double x1 = Xi[0];
double xn = Xi[Xi.Length - 1];
bool ascending = (xn >= x1);
while( i2 - i1 > 1 )
{
im = (i1 + i2) / 2;
double xm = Xi[im];
if( ascending & (x >= Xi[im]) ) { i1 = im; } else { i2 = im; }
}
if( (ascending && (x <= x1)) || (!ascending & (x >= x1)) )
{
return 0;
}
else if( (ascending && (x >= xn)) || (!ascending && (x <= xn)) )
{
return Xi.Length - 1;
}
else
{
return i1;
}
}
public double GetIntY(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double h2 = h * h;
double a = (x-x1)/h;
double a2 = a*a;
return h / 6 * (3 * a * (2 - a) * y1
+ 3 * a2 * y2 - a2 * h2 * (a2 - 4 * a + 4) / 4 * y1pp
+ a2 * h2 * (a2 - 2) / 4 * y2pp);
}
public double GetY(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double h2 = h * h;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return A * y1 + B * y2 + h2 / 6 * (A * (A * A - 1) * y1pp
+ B * (B * B - 1) * y2pp);
}
public double GetYp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return (y2 - y1) / h + h / 6 * (y2pp * (3 * B * B - 1)
- y1pp * (3 * A * A - 1));
}
public double GetYpp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return A * y1pp + B * y2pp;
}
public double GetYppp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
return (y2pp - y1pp) / h;
}
public double Integrate(double from_x, double to_x)
{
if( to_x < from_x ) { return -Integrate(to_x, from_x); }
int i = IndexOf(from_x);
int j = IndexOf(to_x);
double x1 = xi[i];
double xn = xi[j];
double z = GetIntY(to_x) - GetIntY(from_x); // go to nearest nodes (k) (j)
for( int k = i + 1; k <= j; k++ )
{
z += iy[k]; // fill-in areas in-between
}
return z;
}
#endregion
#region Properties
public bool IsEmpty { get { return xi.Length == 0; } }
public double[] Xi { get { return xi; } set { xi = value; } }
public double[] Yi { get { return yi; } set { yi = value; } }
public double[] Yp { get { return yp; } set { yp = value; } }
public double[] Ypp { get { return ypp; } set { ypp = value; } }
public double[] Yppp { get { return yppp; } set { yppp = value; } }
public double[] IntY { get { return yp; } set { iy = value; } }
public int Count { get { return xi.Length; } }
public double X_min { get { return xi.Min(); } }
public double X_max { get { return xi.Max(); } }
public double Y_min { get { return yi.Min(); } }
public double Y_max { get { return yi.Max(); } }
#endregion
#region Helpers
static double[] Sequence(double x_min, double x_max, int double_of_points)
{
double[] res = new double[double_of_points];
for (int i = 0; i < double_of_points; i++)
{
res[i] = x_min + (double)i / (double)(double_of_points - 1) * (x_max - x_min);
}
return res;
}
#endregion
}
You can find an approximation of a line that intersects points in 3d and 2d space using a Hough Transformation algorithm. I am only familiar with it's uses in 2d however but it will still work for 3d spaces given that you know what kind of line you are looking for. There is a basic implementation description linked. You can Google for pre-mades and here is a link to a 2d C implementation CImg.
The algorithm process (roughly)... First you find equation of a line that you think will best approximate the shape of the line (in 2d parabolic, logarithmic, exponential, etc). You take that formula and solve for one of the parameters.
y = ax + b
becomes
b = y - ax
Next, for each point you are attempting to match, you plugin the points to the y and x values. With 3 points, you would have 3 separate functions of b with respect to a.
(2, 3) : b = 3 - 2a
(4, 1) : b = 1 - 4a
(10, -5): b = -5 - 10a
Next, the theory is that you find all possible lines which pass through each of the points, which is infinitely many for each individual point however when combined in an accumulator space only a few possible parameters best fit. In practice this is done by choosing a range space for the parameters (I chose -2 <= a <= 1, 1 <= b <= 6) and begin plugging in values for the variant parameter(s) and solving for the other. You tally up the number of intersections from each function in an accumulator. The points with the highest values give you your parameters.
Accumulator after processing b = 3 - 2a
a: -2 -1 0 1
b: 1
2
3 1
4
5 1
6
Accumulator after processing b = 1 - 4a
a: -2 -1 0 1
b: 1 1
2
3 1
4
4
5 2
6
Accumulator after processing b = -5 - 10a
a: -2 -1 0 1
b: 1 1
2
3 1
4
5 3
6
The parameter set with the highest accumulated value is (b a) = (5 -1) and the function best fit to the points given is y = 5 - x.
Best of luck.
My guess is that a serious application of this would use a http://en.wikipedia.org/wiki/Kalman_filter. By the way, that probably wouldn't guarantee that the reported points were intersected either, unless you fiddled with the parameters a bit. It would expect some degree of error in each data point given to it, so where it thinks the object is at time T would not necessarily be where it was at time T. Of course, you could set the error distribution to say that you were absolutely sure you knew where it was at time T.
Short of using a Kalman filter, I would try and turn it into an optimisation problem. Work at the 1s granularity and write down equations like
x_t' = x_t + (Vx_t + Vx_t')/2 + e,
Vx_t_reported = Vx_t + f,
Vx_t' = Vx_t + g
where e, f, and g represent the noise. Then create a penalty function such as e^2 + f^2 + g^2 +...
or some weighted version such as 1.5e^2 + 3f^2 + 2.6g^2 +... according to your idea of what the errors really are and how smooth you wnat the answer to be, and find the values that make the penalty function as small as possible - with least squares if the equations turn out nicely.