Better Enumerable.Range for both ascending and descending ranges? - c#

Suppose I have two points, int x1, x2, where x1 can be larger, smaller or equal to x2. I want to generate all integer numbers between those two points inclusive (starting with x1 and ending with x2), or just value of x1 if both two points are equal. Is there any elegant way to generate IEnumerable<int> with those values?

You can use this iterator block:
IEnumerable<int> CreateRange(int x1, int x2) {
var increment = x2 > x1 ? 1 : -1;
for (var i = x1; i != x2; i += increment)
yield return i;
yield return x2;
}
It's efficient and creating a range is just as clean as using Enumerable.Range:
CreateRange(10, 5).Select( ... )

If you want to stick with single LINQ statement -
Enumerable.Range(0, Math.Abs(x2 - x1) + 1).Select(i => x1 + i * Math.Sign(x2 - x1))

You can do something like this:
//normal order works
int x1 = 5;
int x2 = 10;
int len = Math.Abs(x2 - x1) + 1;
var range = x1 < x2 ? Enumerable.Range(x1, len) : Enumerable.Range(x2, len).Reverse();
//reverse order works (the same code for range)
x1 = 10;
x2 = 5;
len = Math.Abs(x2 - x1) + 1;
range = x1 < x2 ? Enumerable.Range(x1, len) : Enumerable.Range(x2, len).Reverse();

Related

Find the possible values for two equations

2x + 4y + 6z = 1200
x + y + z = 300
how can I find the possible x, y, z integer values in a c# method?, I am trying to find a better solution instead of using brute force nested for loops since it is not a good solution.
public List<Tuple<int, int, int>> Calculate()
{
var result = new List<Tuple<int, int, int>>();
int maxValue = 300;
for(int i = 0; i< maxValue; i++)
for (int j = 0; j < maxValue; j++)
for (int k = 0; k < maxValue; k++)
if (i + j + k == maxValue && 2 * i + 4 * j + 6 * k == 1200)
result.Add(new Tuple<int, int, int>(i, j, k));
return result;
}
Thank you in advance.
Well, having
2x + 4y + 6z = 1200
x + y + z = 300
you can put it as
x + 2y + 3z = 600
x + y + z = 300
subtract 2nd from the 1st and you get
y + 2z = 300
or
y = 300 - 2z
Since x = 300 - y - z we can put it as
x = 300 - y - z =
= 300 - (300 - 2z) - z =
= 300 - 300 + 2z - z =
= z
Finally, for the arbitrary z (which is free variable)
x = z
y = 300 - 2 * z;
Possible c# code:
private static (int x, int y, int z) Solution(int x) => (x, 300 - 2 * x, x);
Demo:
string solutions = string.Join(Environment.NewLine, Enumerable
.Range(0, 10)
.Select(x => Solution(x)));
...
// 10 solutions for x = 0..9
string solutions = string.Join(Environment.NewLine, Enumerable
.Range(0, 10)
.Select(x => Solution(x)));
Console.Write(solutions);
Outcome:
(0, 300, 0)
(1, 298, 1)
(2, 296, 2)
(3, 294, 3)
(4, 292, 4)
(5, 290, 5)
(6, 288, 6)
(7, 286, 7)
(8, 284, 8)
(9, 282, 9)
If you are looking for non-negative solutions only (you've mentioned probabilities in the comments for the code), then use x in [0..150] range:
(0, 300, 0)
(1, 298, 1)
(2, 296, 2)
...
(148, 4, 148)
(149, 2, 149)
(150, 0, 150)
Edit: your Calculate() method improved:
public static List<Tuple<int, int, int>> Calculate() {
var result = new List<Tuple<int, int, int>>();
const int maxValue = 300;
int start = Math.Max(150 - maxValue / 2, 0);
for (int x = start; ; ++x) {
int y = 300 - 2 * x;
int z = x;
if (y < 0 || x > maxValue)
break;
result.Add(new Tuple<int, int, int>(x, y, z));
}
return result;
}
Math Theory
If you want a general method you should use some Linear Algebra theory.
Let's rewrite the equations in matrix form as A(x,y) + bz = c,
where:
A: is the matrix that contains the coefficents of the x,y coordinates
A = (2,4,1,1)
b = (6,1) (transposed) is the vector containing the z coefficents.
c = (1200, 300) (transposed) is the vector containing the constant terms.
then (x,y) = AInverse * (c - bz). That is a function of z (Let's say f(z)). So for every z you obtain a valid solution: (f(z),z). f(z) is a vector of 2 components.
Note
If A is not invertible because the equations (rstricted to x and y) are linearly dependent (i.e. the 2 equations are the "same" equation in x and y), this method fails.
Code
We can code that like that:
Step1
We must code the Matrix2x2. I do it from scratch now, but you maybe want to use some framework if you really need in production:
public record struct Matrix2x2 (float A00, float A01, float A10, float A11)
{
public float Determinant => A00 * A11 - A01 * A10;
public Matrix2x2 Invert() => Determinant != 0
? 1 / Determinant * new Matrix2x2() { A11 = A00, A00 = A11, A01 = -A01, A10 = -A10 }
: throw new InvalidOperationException($"Cannot Invert this matrix");
public static Matrix2x2 operator *(Matrix2x2 a, float number) => new()
{
A00 = a.A00 * number,
A01 = a.A01 * number,
A10 = a.A10 * number,
A11 = a.A11 * number,
};
public static Matrix2x2 operator *(float number, Matrix2x2 a) => a * number;
public static Vector2 operator *(Matrix2x2 a, Vector2 vector)
{
var x = a.A00 * vector.X + a.A01 * vector.Y;
var y = a.A10 * vector.X + a.A11 * vector.Y;
return new(x, y);
}
}
Step2
We must encode the equation. We need the Matrix A, the z coefficents and b, and the vector c of constant terms:
public delegate Vector3 SolutionSpace(float z);
public static class EquationHelper
{
public static SolutionSpace SolveEquation(Matrix2x2 equationMatrix, Vector2 b, Vector2 c) => z =>
{
var v = equationMatrix.Invert() * (c - z * b);
return new Vector3(v.X, v.Y, z);
};
}
Note: The object returned from this function is the solution space, that depends from 1 parameter (the z value). So we could see it as a function that maps (float z) => (x(z), y(z), z) that in c# is a delegate that returns a Vector3 and takes in input a float.
Usage
var A = new Matrix2x2(2, 4, 1, 1);
var b = new Vector2(6, 1);
var c = new Vector2(1200, 300);
var solution = EquationHelper.SolveEquation(A, b, c);
foreach(var z in Enumerable.Range(-10, 21))
Console.WriteLine(solution(z));
Output

How can I get the final result using MathNet.Symbolics?

I am trying to make a method that will calculate a determinant. For that I am using the MathNet.Symbolics library. All good until I run into a little problem. I was trying to get the final result from the formula of a determinant and after I used Infix.Format, I don't know why, but it does not give ma a satisfying result. Instead of the final result It gives me an equation somewhere in between. I think is has something to do with the fact that part of the equation is between 2 parentheses. What should I do to get the final Result?
Here is my code:
using System;
using InputMath;
using MathNet.Symbolics;
using mns = MathNet.Symbolics.Expression;
namespace MathWizard
{
class Determinants
{
//The final result
public static string fnalResult;
public static void BasicDeterminant()
{
//The inputs before assigning them to theyr specific variable
string[] inputs;
inputs = Console.ReadLine().Split(new char[] { ' ' },StringSplitOptions.RemoveEmptyEntries);
Double x1 = Convert.ToDouble(inputs[0]);
Double y1 = Convert.ToDouble(inputs[1]);
Double x2 = Convert.ToDouble(inputs[2]);
Double y2 = Convert.ToDouble(inputs[3]);
var x = mns.Symbol("x");
var y = mns.Symbol("y");
var firstResult = Infix.Format(x * x1 * 1 + x1 * y2 * 1 + x2 * y * 1 - (x1 * x2 * 1 + 1 * y2 * x + 1 * y * x1));
Console.WriteLine(firstResult);
Console.ReadKey();
}
}
}
So this is an example input:
1 3 6 4
After input the numbers will be assigned like this:
x1 = 1;
y1 = 3;
x2 = 6;
y2 = 4;
After running all the code the output is:
4 + x + 6*y - (6 + 4*x + y)
After solving this output, the actual expected result should be:
-2-3*x+7*y
Math.NET Symbolics does apply automatic simplification, but only according strict rules. That's why some of the terms are simplified and reordered, but the parenthesis is not automatically expanded.
You can use the symbolic routine Algebraic.Expand to enforce the expansion:
var expression = x * x1 * 1 + x1 * y2 * 1 + x2 * y * 1 - (x1 * x2 * 1 + 1 * y2 * x + 1 * y * x1);
var expanded = Algebraic.Expand(expression);
var firstResult = Infix.Format(expanded);
Where firstResult now has the expected value (-2) + (-3)*x + 5*y.
NB: I notice it would be nicer if this would have been formatted as -2 - 3*x + 5*y. I'll try to improve this in the next release.

How should i search through a string for a sequence of characters such as "x*y"?

I am trying to make a determinat calculator using mathematical Cramer's theorem, as you can see I translated the theorem into code convertedString = Convert.ToString (x * y1 * 1 + x1 * y2 * 1 + x2 * x * y - (1 * y1 * x2 + 1 * y2 * y + 1 * y * x1));All good until I am at the point where I need to compute 2 unknown numbers, I don't know how to "tell" in code to the computer that x + x = 2x or 3y-y = 2y, so I tought that if I convert the Crammer's equation into a string I can find all the matches like x + x or y + 2y or y * y and begin from that a solution that can solve my initial problem, like if I find an x * x pattern I will tell the pc through an if statement or something that the pattern x * x is x^2.
So that being said, I want to find out the number of specific sequences like X * y or y + x that are present in a string, I did try some foreach loops and for loops but I can't get it to work and I don't know how should I approach the problem next, plase help.
Here is my code:
using System;
using InputMath;
namespace MathWizard
{
class Determinants
{
//Determinant of a first point and a second graphical point on the xoy axis.
public static void BasicDeterminant()
{
float x;
float y;
float x1 = Input.x1;
float y1 = Input.y1;
float x2 = Input.x2;
float y2 = Input.y2;
float result;
string convertedString;
string pointsValue;
string[] point;
Console.WriteLine("Please introduce the 2 graphical points ( A and B) \n in the order x1 y1 x2 y2, separated by a space ");
pointsValue = Console.ReadLine();
point = pointsValue.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
x1 = Convert.ToInt32(point[0]);
y1 = Convert.ToInt32(point[1]);
x2 = Convert.ToInt32(point[2]);
y2 = Convert.ToInt32(point[3]);
//The Cramer's Rule for solving a 2 points determinant ( P1(x1,y1) and P2(x2,y2)
convertedString = Convert.ToString (x * y1 * 1 + x1 * y2 * 1 + x2 * x * y - (1 * y1 * x2 + 1 * y2 * y + 1 * y * x1));
}
}
}
You could also use the following regex which will find x*y with case insensitivity for each operator:
string pattern = /(x(\*|\+|\-|\/|\^)y)/gi;
then you could do some string.Contains(pattern); to check. Let me know if this helps.
Edit: Updated Pattern
Updated the pattern so that it will also allow variables such as y9 or X10. Any single character (x or y) followed by any amount of numbers.
string pattern =/(x\d*(\*|\+|\-|\/|\^)y\d*)/gi; // could match X1*y9
This doesn't account for whitespaces so you could use some .replace() to get rid of whitespace or use .split(/\s/) and get a string array without whitespace before using this pattern.
bool found = false;
int xyCount = 0;
if(convertedString.Contains("X*Y")){
found = true;
xyCount++;
//makes a substring without the first case of the "X*Y"
string s = convertedString.SubString(convertedString.IndexOf("X*Y"))
if(s.Contains("X*Y")){
xyCount++;
}
Its probably not the best way to do it, but you can probably make a better method doing something like this

math.sqrt returns 0

I have a c# function that contains formula to calculate euclidean distance of some points. I got the point's position defined by R(rx,ry) and L(lx,ly).
at first, I tried to write the code like this:
double dRightLeft = Math.Sqrt((Math.Pow(rx - lx, 2) + Math.Pow(ry - ly, 2)));
it returns 0.0.
then I tried to split the variable to check where did I do wrong, like this:
double rl = (Math.Pow(rx - lx, 2) + Math.Pow(ry - ly, 2));
double dRightLeft = Math.Sqrt(rl);
the rl variable returns a valid value of its operation. but then when I tried to get the square root out of it, the dRighLeft variable still returns 0.0.
I tried both assigned and unassigned dRightLeft like this:
//assigned
dRightLeft = 0;
//unassigned
dRightLeft;
they both still returns 0.0 value.
here's my short but complete program where I get the rx, ry, lx, and ly value:
public Bitmap getDetectedImage()
{
int rx, rx, lx, ly, ...;
double dRightLeft = 0;
...
//righteyeloop
for (int x = fo.rightEye.X; x < (fo.rightEye.X + fo.rightEye.Width); x++)
{
for (int y = fo.rightEye.Y; y < (fo.rightEye.Y + fo.rightEye.Height); y++)
{ //segmentation...//
rPixel++;
result.byteImage[x, y].R = 0;
result.byteImage[x, y].G = 255;
result.byteImage[x, y].B = 0;
//to get the the first pixel detected//
if (rPixel == 1)
{
result.byteImage[x, y].R = 255;
result.byteImage[x, y].G = 0;
result.byteImage[x, y].B = 0;
rx = x + (fo.rightEye.Width / setting.featureWidth * setting.eyeHeight / setting.eyeWidth);
ry = y + (fo.rightEye.Height / setting.featureWidth * setting.eyeHeight / setting.eyeWidth);
}
}
}
//lefteyeloop basically the same type as righteyeloop//
.....
//this to count the distance of righteye and lefteye
double rl = ((rx - lx) * (rx - lx) + (ry - ly) * (ry - ly));
double dRightLeft = Math.Pow(rl, 0.5);
}
I suspect the problem is that Math.Pow deals with doubles, which have low precision (see this SO question for more discussion). The immediate instinct is to just replace Math.Pow by writing out the multiplication:
double rl = ((rx - lx) * (rx - lx) + (ry - ly) * (ry - ly));
double dRightLeft = Math.Sqrt(rl);
From the Math.Pow reference, it seems that, with an exponent of two, the only way to return 0 is if your base (i.e. rx - lx or ry - ly) is also 0.

Curve fitting points in 3D space

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.

Categories

Resources