Add your own alternative version
Stats
202.7K views 3.7K downloads 156 bookmarked
Posted
22 Jun 2007

Comments and Discussions



Hey,
First of all, excellent article and exactly what I was hoping to find when I started researching how to do this for a project I'm working on, so thankyou!
However, your comment about the equation d = (1/2)At^2 (for determining distance after t secs of acceleration at A) was hard to explain and having a mysterious 1/2 in there worried me a bit, so I tried testing it out and I think you might have made an error.
Oh, Secondly, this is my first (ever) visit to codeproject, I don't know its markup, and I couldn't immediately see how to superscript/subscript things, so please bear with the horrible ascii version.
Supposing an acceleration of 3 meters per second per second:
At time t0, velocity is 0, distance is 0
At time t1, velocity is 3, distance is t0+3=3
At time t2, velocity is 6, distance is t1+6=9
At time t3, velocity is 9, distance is t2+9=18
At time t4, velocity is 12, distance is t3+12=30
Trying your Guidance System UI, I configured the following:
Target acceleration (0,0,0)
Target velocity (0,0,0)
Target position (30,0,0)
Source velocity (0,0,0)
Source position (0,0,0)
Projectile acceleration 3
Projectile velocity 0
Projectile pos 0 (not sure what this is?)
Projectile burn time 999
This gives me a stage 1 intersection at 4.47214, surely the correct answer is 5?
Try this instead:
at time t, we know that d = A * (1+2+..+t)
to calculate (1+2+..+t), break the set of additives into pairs:
highest number (t) + lowest number (1) = t+1
next highest (t1) + next lowest (2) = t+1
... and so on
if t is an even number, then we have t/2 pairs of (t+1), so sum is (t+1)*t/2
if t is an odd number, then we have (t1)/2 pairs of (t+1), and a "middle number"
middle number = (t+1)/2
Sum of pairs = (t+1)*(t1)/2
Sum of pairs = (t^2  t + t  1)/2 (expanding)
Sum of pairs = (t^2  1)/2 (simplifying)
now adding sum of pairs and middle number together:
total = (t^2  1)/2 + (t+1)/2
total = (t^2 + t)/2
total = t*(t+1)/2
So for both even and odd values of t, we have:
d = A*t*(t+1)/2 (my equation)
d = A*(t+t^2)/2 (my equation, expanded, reordering for clarity)
d = A*(0+t^2)/2 (your equation, reordering for clarity)
thoughts?





I am investigating whether or not your algorithms with work for our application. Our munition simulator uses 6DOF models (done in Simulink outputted as C++ code) created by a vendor but right now they do not guide so well. So I have asked for more generic (kinematic) models that could hit the target (unrealistically if necessary) every time.
Your algorithms look like the ticket. We need models for high flying guided bomb units (aka, smart bombs) and Hellfire missiles. The main difference between both is the hellfires have initial thrust. After the thrust period it falls with gravity (and drag but we assume its 0 since the models are simpler than 6DOF).
Can your algorithm be modified for the gravity only GBUs? There is initial velocity for both. Targets can be fixed or moving.
Steve
modified 9Oct13 11:20am.





Should it not be
( Pam * Rbt + Pvm ) * t + ( (1/2) * Pam * Rbt^2 + Pvm * Rbt + Ppm )
?





It has been so long since I first wrote this that I have stopped frequently checking for replies. My apologies there.
I presume you are referencing the lines
double ssC = tC  pam * pam * rbt * rbt  2.0 * pam * pvm * rbt  pvm * pvm;
double ssD = tD + pam * pam * rbt * rbt * rbt + pam * pvm * rbt * rbt  2.0 * (pam * rbt + pvm) * ppm;
double ssE = tE  0.25 * pam * pam * rbt * rbt * rbt * rbt + pam * ppm * rbt * rbt  ppm * ppm;
in conjunction with
List<double> ssroots = rootsOf(tA, tB, ssC, ssD, ssE);
as roots correspond to times.
This project was undertaken some years ago, but let's see if I can't still throw down some numbers.
Abstractly, we wish to compute T(t) = P(t), that is, the target and projectile are at the same point in space (the functions' output, T and P) at the same time (the functions' input, t), the point being that if our target and projectile are at the same location at the same time, we've "won."
So, on with the showP(t) for postrbt times is derived as follows:
In plain English, we are the distance that we go while burning all of our fuel, plus our output speed after that burn times the remaining time afterwords, away from where we started.
Or:
P =
(0.5*pam*rbt*rbt + pvm*rbt + ppm)
+
((pam*rbt + pvm) * (trbt))
the first piece is the entire distance covered by the first stage, and the second piece is how far one drifts during the second stage. Technically speaking, over in math world, it should be noted that this function's domain is limited for times of t >= rbt, but we already kinda said that when we described what it is used forthe second stage, and thus why this equation is not shown on the left side of that vertical gray line in the time graph gui.
expanding everything out we get P = 0.5*pam*rbt*rbt + pvm*rbt + ppm + pam*rbt*t  pam*rbt*rbt + pvm*t  pvm*rbt and that can be condensed to P = 0.5*pam*rbt*rbt + ppm + pam*rbt*t + pvm*t by combining like terms
Since the T(t) equation is the square root of a sum of squares (a la Pythagoras), we square both sides of our original T(t) = P(t) to eliminate the radical that appears in T(t), and that leaves us with
P(t)^2 = (0.5*pam*rbt*rbt + ppm + pam*rbt*t + pvm*t) * (0.5*pam*rbt*rbt + ppm + pam*rbt*t + pvm*t)
Now it's just a matter of elbow grease. The proof is *not* trivial, so it won't be left as an exercise to the reader. Multiplying each term by each other term, and using the shortcut that any term multiplied by itself will be itself squared, and any A term multiplied by an B term will appear as both A*B and B*A so for the sake of simplicity 2*A*B can be used insteadI've done a bit of coefficient math in my head, but nothing too fancycertainly nothing beyond 1 = 2*(0.5) or (+)0.25 = (0.5)*(0.5)
P(t)^2 =
0.25*pam*pam*rbt*rbt*rbt*rbt  pam*rbt*rbt*ppm  pam*rbt*rbt*pam*rbt*t  pam*rbt*rbt*pvm*t
+
ppm*ppm + 2*ppm*pam*rbt*t + 2*ppm*pvm*t
+
pam*rbt*t*pam*rbt*t + 2*pam*rbt*t*pvm*t
+
pvm*t*pvm*t
collecting all degrees of t together...
P(t)^2 =
(pam*pam*rbt*rbt + 2*pam*pvm + pvm*pvm)*t*t
+
(2*pam*ppm*rbt + 2*pvm*ppm  pam*pam*rbt*rbt*rbt  pam*pvm*rbt*rbt)*t
+
(0.25*pam*pam*rbt*rbt*rbt*rbt  pam*ppm*rbt*rbt + ppm*ppm)
It's a miracleI check my work years later and I don't make a math error on my first try. When you flip all of the signs (since this function is being subtracted from T(t)^2), you will clearly see that this corresponds to the projectilerelevant parts of ssC, ssD, and ssE, as ultimately we are solving for 0 = T(t)^2 + P(t)^2, in the most verbose terms.
And my math is vindicated in the little minigame I provided; missiles shot without enough fuel to impact in stage one, but which will gain enough speed to hit in stage two, do in fact hit.
If you'd like to share how you arrived at your equation perhaps I can shed some light on what is going on. And again sorry for not getting to this soonerI am, after all, so busy with college these days. It is still possible that there may be an error in the article itself, even if the code is not flawed, so if you're picking up on something there, be specific about it and I'll see if it corresponds to my code as it should. If any error exists in the text I will have it corrected as soon as possible.
Gatsby
modified on Wednesday, September 1, 2010 6:53 AM





http://www.flickr.com/photos/27513972@N06/2564214779/





I ported both your code and the code from the UnReal Wiki (http://wiki.beyondunreal.com/Legacy:Projectile_Aiming ) to c++ and ran a comparison. The test is exactly this:
Shooter is a CIWIS on a Iowa class battleship moving at about 10 knots.
Target is a Silkworm missile moving at roughly 500 knots.
At ranges less than 1000 yards both solutions are almost identical. However as the range increases the Unreal Wiki solution consistently gets closer to the target. At > 10000 yards I can't even see your solutions projectiles they're so far away. I can do a webex with you if you want or send you screen shots.
I'm not a mathematician so I don't understand the difference but is your solution algabraic and the other another type(geometric?). The other is using a lot of Dot and Cross products is the only difference I can see.
Any way your solution is much more stable, the UnrealWiki solution produces a lot of erroneous trajectories (but the valid one always hit smack on target). It's very strange and I'd really like to figure it out because your solution is much more stable and generates fewer errors.
John





I most certainly do wish to troubleshoot this with you, but I feel I need a little more information. Any sort of code you can share with me? I'm particularly interested in what you're passing in to my functions, and what sort of environmental factors may be at work (is there air resistance, is there any sort of gravity, etc)
Please reply back and I'll be very happy to help.
EDIT: ah yes, Also, I ported my code to C++ myself recently, allow me to provide that:
MGS.h
#include <cmath> #include <vector>
struct Point3D { double x; double y; double z;
Point3D(); Point3D(double X, double Y, double Z); };
struct Projectile { double a; double v; double p;
Projectile(); Projectile(double A, double V, double P); };
struct Shooter { Point3D v; Point3D p;
Shooter(); Shooter(Point3D V, Point3D P); };
struct Target { Point3D a; Point3D v; Point3D p;
Target(); Target(Point3D A, Point3D V, Point3D P); };
Point3D CalculateAcceleration(Point3D PAtTMinus2, Point3D PAtTMinus1, Point3D PAtTMinus0); Point3D CalculateVelocity(Point3D PAtTMinus2, Point3D PAtTMinus1, Point3D PAtTMinus0);
bool Intercept(Target T, Shooter S, Projectile P, int rbt, double tolerance, std::vector<Point3D>& vectors);
MGS.cpp
#include <algorithm> #include <limits> #include "MGS.h" #define EPSILON 0.00000000001 using namespace std;
static inline bool isnan(double value) { return value != value; }
static inline bool isinf(double value) { return value == std::numeric_limits<double>::infinity(); }
Point3D::Point3D() { x = 0; y = 0; z = 0; }
Point3D::Point3D(double X, double Y, double Z) { x = X; y = Y; z = Z; }
Projectile::Projectile() { a = 0; v = 0; p = 0; }
Projectile::Projectile(double A, double V, double P) { a = A; v = V; p = P; }
Shooter::Shooter() { v = Point3D(); p = Point3D(); }
Shooter::Shooter(Point3D V, Point3D P) { v = V; p = P; }
Target::Target() { a = Point3D(); v = Point3D(); p = Point3D(); }
Target::Target(Point3D A, Point3D V, Point3D P) { a = A; v = V; p = P; }
Point3D CalculateAcceleration(Point3D PAtTMinus2, Point3D PAtTMinus1, Point3D PAtTMinus0) { return Point3D(PAtTMinus2.x  2.0 * PAtTMinus1.x + PAtTMinus0.x, PAtTMinus2.y  2.0 * PAtTMinus1.y + PAtTMinus0.y, PAtTMinus2.z  2.0 * PAtTMinus1.z + PAtTMinus0.z); }
Point3D CalculateVelocity(Point3D PAtTMinus2, Point3D PAtTMinus1, Point3D PAtTMinus0) { return Point3D(PAtTMinus2.x / 2.0  2.0 * PAtTMinus1.x + 3.0 * PAtTMinus0.x / 2.0, PAtTMinus2.y / 2.0  2.0 * PAtTMinus1.y + 3.0 * PAtTMinus0.y / 2.0, PAtTMinus2.z / 2.0  2.0 * PAtTMinus1.z + 3.0 * PAtTMinus0.z / 2.0); }
static vector<double> rootsOf(double A, double B, double C, double D, double E) { vector<double> roots = vector<double>(); if (A == 0.0) { if (B == 0.0) { if (C == 0.0) { if (D == 0.0) { if (E == 0.0) roots.push_back(0.0); } else roots.push_back(D / E); } else { roots.push_back((D + sqrt(D * D  4 * C * E)) / (2.0 * C)); roots.push_back((D  sqrt(D * D  4 * C * E)) / (2.0 * C)); } } else { C /= B; D /= B; E /= B; double F = (3.0 * D  C * C) / 3.0; double G = (2.0 * C * C * C  9.0 * C * D + 27.0 * E) / 27.0; double H = (G * G) / 4.0 + (F * F * F) / 27.0; if (H > 0) { double intermediate = G / 2.0 + sqrt(H); double m = intermediate < 0.0 ? pow(intermediate, 1.0 / 3.0) : pow(intermediate, 1.0 / 3.0); intermediate = 2.0 * sqrt(H); double n = intermediate < 0.0 ? pow(intermediate, 1.0 / 3.0) : pow(intermediate, 1.0 / 3.0); roots.push_back(m + n  C / 3.0); } else { double intermediate = sqrt(G * G / 4.0  H); double rc = intermediate < 0.0 ? pow(intermediate, 1.0 / 3.0) : pow(intermediate, 1.0 / 3.0); double theta = acos(G / (2.0 * intermediate)) / 3.0; roots.push_back(2.0 * rc * cos(theta)  C / 3.0); roots.push_back(rc * (cos(theta) + sqrt(3.0) * sin(theta))  C / 3.0); roots.push_back(rc * (cos(theta)  sqrt(3.0) * sin(theta))  C / 3.0); } if (F + G + H == 0.0) { double intermediate = E < 0.0 ? pow(E, 1.0 / 3.0) : pow(E, 1.0 / 3.0); roots.clear(); roots.push_back(intermediate); roots.push_back(intermediate); roots.push_back(intermediate); } } } else { B /= A; C /= A; D /= A; E /= A; double F = C  (3.0 * B * B) / 8.0; double G = D + B * B * B / 8.0  (B * C) / 2.0; double H = E  3.0 * B * B * B * B / 256.0 + B * B * C / 16.0  B * D / 4.0; double b = F / 2.0; double c = (F * F  4.0 * H) / 16.0; double d = (G * G) / 64.0; double f = (3.0 * c  b * b) / 3.0; double g = (2.0 * b * b * b  9.0 * b * c + 27.0 * d) / 27.0; double h = (g * g) / 4.0 + (f * f * f) / 27.0; double y1; double y2r; double y2i; double y3r; double y3i; if (h > 0.0) { double intermediate = g / 2.0 + sqrt(h); double m = intermediate < 0.0 ? pow(intermediate, 1.0 / 3.0) : pow(intermediate, 1.0 / 3.0); intermediate = 2.0 * sqrt(h); double n = intermediate < 0.0 ? pow(intermediate, 1.0 / 3.0) : pow(intermediate, 1.0 / 3.0); y1 = m + n  b / 3.0; y2r = (m + n) / 2.0  b / 3.0; y2i = ((m  n) / 2.0) * sqrt(3.0); y3r = (m + n) / 2.0  b / 3.0; y3i = ((m  n) / 2.0) * sqrt(3.0); } else { double intermediate = sqrt((g * g / 4.0  h)); double rc = intermediate < 0.0 ? pow(intermediate, 1.0 / 3.0) : pow(intermediate, 1.0 / 3.0); double theta = acos((g / (2.0 * intermediate))) / 3.0; y1 = 2.0 * rc * cos(theta)  b / 3.0; y2r = rc * (cos(theta) + sqrt(3.0) * sin(theta))  b / 3.0; y2i = 0.0; y3r = rc * (cos(theta)  sqrt(3.0) * sin(theta))  b / 3.0; y3i = 0.0; } if (f + g + h == 0.0) { double intermediate = d < 0.0 ? pow(d, 1.0 / 3.0) : pow(d, 1.0 / 3.0); y1 = intermediate; y2r = intermediate; y2i = 0.0; y3r = intermediate; y3i = 0.0; } double p; double q; if (h <= 0.0) { int zeroCheck = 0; vector<double> cubicRoots(3); cubicRoots[0] = y1; cubicRoots[1] = y2r; cubicRoots[2] = y3r; sort(cubicRoots.begin(), cubicRoots.begin() + 2);
p = sqrt(cubicRoots[1]); q = sqrt(cubicRoots[2]);
if (abs(y1) < EPSILON) { p = sqrt(y2r); q = sqrt(y3r); zeroCheck = 1; } if (abs(y2r) < EPSILON) { p = sqrt(y1); q = sqrt(y3r); zeroCheck += 2; } if (abs(y3r) < EPSILON) { p = sqrt(y1); q = sqrt(y2r); zeroCheck += 4; } switch (zeroCheck) { case (3): p = sqrt(y3r); break; case (5): p = sqrt(y2r); break; case (6): p = sqrt(y1); break; } if (y1  EPSILON < 0.0  y2r  EPSILON < 0.0  y3r  EPSILON < 0.0) { if (E == 0.0) roots.push_back(0.0); } else { double r; if (zeroCheck < 5) r = G / (8.0 * p * q); else r = 0.0; double s = B / 4.0; roots.push_back(p + q + r  s); roots.push_back(p  q  r  s); roots.push_back(p + q  r  s); roots.push_back(p  q + r  s); } } else { double r2mod = sqrt(y2r * y2r + y2i * y2i); double y2mod = sqrt((r2mod  y2r) / 2.0); double x2mod = y2i / (2.0 * y2mod); p = x2mod + y2mod; double r3mod = sqrt(y3r * y3r + y3i * y3i); double y3mod = sqrt((r3mod  y3r) / 2.0); double x3mod = y3i / (2.0 * y3mod); q = x3mod + y3mod; double r = G / (8.0 * (x2mod * x3mod + y2mod * y3mod)); double s = B / 4.0; roots.push_back(x2mod + x3mod + r  s); roots.push_back(x2mod  x3mod + r  s); } } for (int i = 0; i != roots.size(); ++i) if (isinf(roots[i])  isnan(roots[i])) roots.erase(roots.begin() + i); sort(roots.begin(), roots.end()); return roots; }
bool does_not_contain(vector<double> vector, double value) { for(int i = 0; i != vector.size(); ++i) if(vector[i] == value) return false; return true; }
void keysort(vector<double>& keys, vector<double>& items) { for(int i = 0; i != keys.size(); ++i) for(int j = keys.size()  1; j != i; j) if(keys[j  1] > keys[j]) { double temp = keys[j]; keys[j] = keys[j  1]; keys[j  1] = temp;
temp = items[j]; items[j] = items[j  1]; items[j  1] = temp; } }
bool Intercept(Target T, Shooter S, Projectile P, int rbt, double tolerance, vector<Point3D>& vectors) { T.v.x = S.v.x; T.v.y = S.v.y; T.v.z = S.v.z; T.p.x = S.p.x; T.p.y = S.p.y; T.p.z = S.p.z;
if (tolerance < 1.0) tolerance = 1.0; if (rbt < 0) rbt = 0; if (rbt == 0) P.a = 0.0;
double tA = 0.25 * (T.a.x * T.a.x + T.a.y * T.a.y + T.a.z * T.a.z); double tB = T.a.x * T.v.x + T.a.y * T.v.y + T.a.z * T.v.z; double tC = T.v.x * T.v.x + T.a.x * T.p.x + T.v.y * T.v.y + T.a.y * T.p.y + T.v.z * T.v.z + T.a.z * T.p.z; double tD = 2.0 * (T.v.x * T.p.x + T.v.y * T.p.y + T.v.z * T.p.z); double tE = T.p.x * T.p.x + T.p.y * T.p.y + T.p.z * T.p.z;
double fsA = tA  0.25 * P.a * P.a; double fsB = tB  P.a * P.v; double fsC = tC  P.a * P.p  P.v * P.v; double fsD = tD  2.0 * P.v * P.p; double fsE = tE  P.p * P.p;
double ssC = tC  P.a * P.a * rbt * rbt  2.0 * P.a * P.v * rbt  P.v * P.v; double ssD = tD + P.a * P.a * rbt * rbt * rbt + P.a * P.v * rbt * rbt  2.0 * (P.a * rbt + P.v) * P.p; double ssE = tE  0.25 * P.a * P.a * rbt * rbt * rbt * rbt + P.a * P.p * rbt * rbt  P.p * P.p;
vector<double> roots = vector<double>(); vector<double> fsroots = rootsOf(fsA, fsB, fsC, fsD, fsE); vector<double> fsrootsCA = rootsOf(0.0, 4.0 * fsA, 3.0 * fsB, 2.0 * fsC, fsD); vector<double> ssroots = rootsOf(tA, tB, ssC, ssD, ssE); vector<double> ssrootsCA = rootsOf(0.0, 4.0 * tA, 3.0 * tB, 2.0 * ssC, ssD);
for(int i = 0; i != fsroots.size(); ++i) { double root = fsroots[i]; if(root >= 0.0 && root <= rbt && does_not_contain(roots, root)) roots.push_back(root); }
for(int i = 0; i != ssroots.size(); ++i) { double root = ssroots[i]; if(root > rbt && does_not_contain(roots, root)) roots.push_back(root); }
for(int i = 0; i != fsrootsCA.size(); ++i) { double root = fsrootsCA[i]; if (tolerance >= abs(fsA * root * root * root * root + fsB * root * root * root + fsC * root * root + fsD * root + fsE) && root >= 0.0 && root <= rbt && does_not_contain(roots, root)) roots.push_back(root); }
for(int i = 0; i != ssrootsCA.size(); ++i) { double root = ssrootsCA[i]; if (tolerance >= abs(tA * root * root * root * root + tB * root * root * root + ssC * root * root + ssD * root + ssE) && root > rbt && does_not_contain(roots, root)) roots.push_back(root); }
sort(roots.begin(), roots.end());
bool able = roots.size() != 0;
if(!able) { vector<double> fsattempts = vector<double>(); vector<double> ssattempts = vector<double>();
for(int i = 0; i != fsrootsCA.size(); ++i) { double root = fsrootsCA[i]; if (root >= 0.0 && root <= rbt && does_not_contain(fsattempts, root)) fsattempts.push_back(root); } fsattempts.push_back(0);
for(int i = 0; i != ssrootsCA.size(); ++i) { double root = ssrootsCA[i]; if(root > rbt && does_not_contain(ssattempts, root)) ssattempts.push_back(root); }
vector<double> keys = vector<double>(fsattempts.size() + ssattempts.size()); vector<double> items = vector<double>(fsattempts.size() + ssattempts.size());
for (int i = 0; i != fsattempts.size(); ++i) { keys[i] = abs(fsA * fsattempts[i] * fsattempts[i] * fsattempts[i] * fsattempts[i] + fsB * fsattempts[i] * fsattempts[i] * fsattempts[i] + fsC * fsattempts[i] * fsattempts[i] + tD * fsattempts[i] + tE); items[i] = fsattempts[i]; }
for (int i = 0; i != ssattempts.size(); ++i) { keys[fsattempts.size() + i] = abs(tA * ssattempts[i] * ssattempts[i] * ssattempts[i] * ssattempts[i] + tB * ssattempts[i] * ssattempts[i] * ssattempts[i] + ssC * ssattempts[i] * ssattempts[i] + ssD * ssattempts[i] + ssE); items[fsattempts.size() + i] = ssattempts[i]; }
keysort(keys, items);
for(int i = 0; i != items.size(); ++i) roots.push_back(items[i]); }
vectors = vector<Point3D>(roots.size()); for(int i = 0; i != roots.size(); ++i) { Point3D v; if(P.a == 0.0 && P.v == 0.0) { v.x = S.v.x; v.y = S.v.y; v.z = S.v.z; } else { v.x = 0.5 * T.a.x * roots[i] * roots[i] + T.v.x * roots[i] + T.p.x; v.y = 0.5 * T.a.y * roots[i] * roots[i] + T.v.y * roots[i] + T.p.y; v.z = 0.5 * T.a.z * roots[i] * roots[i] + T.v.z * roots[i] + T.p.z; }
double m = sqrt(v.x * v.x + v.y * v.y + v.z * v.z); if(m < EPSILON) m = 1.0;
vectors[i].x = v.x / m; vectors[i].y = v.y / m; vectors[i].z = v.z / m; }
return able; }
Testable then by including MGS.h and making some shooter, target, and projectile structs and passing them in.





I'm not using air resistence, I am using gravity. I'm passing that in via the Target's Acceleration which is only downward towards the earth.
Here's my actual code:
std::vector Targeting::GetShootVect(
Vector3 StartLoc,
Vector3 EndLoc,
float ProjSpeed,
Vector3 Gravity,
Vector3 launcherVelocity,
Vector3 targetVelocity)
{
double ROT = 400;
std::vector vectors;
Intercept(
Gravity.x,Gravity.y,Gravity.z,
targetVelocity.x, targetVelocity.y, targetVelocity.z,
EndLoc.x, EndLoc.y, EndLoc.z,
launcherVelocity.x, launcherVelocity.y, launcherVelocity.z,
StartLoc.x, StartLoc.y, StartLoc.z,
0, ProjSpeed, 0,
500, ROT, vectors);
return vectors;
}





One other thing that you should know about gravity.
The Target is flying at a constant height (it isn't falling). Every time step I'm fixing that so it technically has no acceleration. You would think gravity should be 0 in this case but I find it I set gravity to zero the projectiles pass under the Target at the same height that the Target would be if it were falling. I saw this and then passed in gravity for the Target acceleration and everything worked (except for sometimes the projectiles miss the target which is the reason I think there's some sort of error).
I sort of lumped everything into the same bucket (target and projectile acceleration wise). This may be wrong but I couldn't find anywhere to define the acceleration of the projectile using your code.





One thing I can answer right away is
"I couldn't find anywhere to define the acceleration of the projectile using your code"
 the var "pam" is the one you're looking for. This is the projectile's acceleration vector's magnitude, just as "pvm" is it's initial or "muzzle" velocity, and "ppm" the position offset (were this a person firing a gun, you might think of this as the length of their arm). Just be sure that when you use the pam var that you provide as much Remaining Burn Time as you want  passing in infinity should work if you really don't want the thing to be running out of fuel.
It's difficult for me to find the error give the code I've got, if you'd be so obliged you can email me directly with more of the context in which the code appears and I will be more able to help you [email removed], because as it stands right now I can't figure out where the problem is. I've tested things similar to what you're describing in my own demo apps and everything seems to be working perfectly, so I suspect that it's how the code is being implemented that's where the error is coming in to play (largely my fault, as I didn't give as much code documentation as I probably should have when I released this article  my apologies). If I'm able to see how you're updating the positions of things and where exactly in the updating that the intercept is being calculated, etc etc etc.
Please do continue to reply, as I'm glad you've found my code helpful, and I really would like to get this to work for you. As stated above, I've checked and rechecked my stuff using scenarios such as the ones you've described and everything works fine for me, so it really should just be an implementation bug, which I'd be happy to help track down with you.
[issue resolved]
Gatsby
modified on Friday, June 13, 2008 4:30 PM





I was trying to solve a similar problem but couldn't quite handle the math so I downloaded an example from the UnReal Wiki which did all the work for me. I like your solution better though.
http://wiki.beyondunreal.com/Legacy:Projectile_Aiming
I'm curious what you think of their solution.





First, could you comment your code? Thanks.
Second, I've been trying off and on to modify the intercept code for a matching intercept  ie., one in which, at the end of the intercept, the projectile is going in the same direction, with the same speed, as the target. (Once that is matched, acceleration can be matched outside of the formula and would probably be better matched outside of the formula anyway).
It would be a little too much to ask you to solve it for me, but any help you would want to give would be appreciated.
Thanks.





Hello Jay Gatsby,
First of all, i will say that you wrote a interesting article.
Unfortunately, i do not understand the vector in this line:
Targeting.Intercept(Tracking.aX, Tracking.aY, 0.0, Tracking.vX, Tracking.vY, 0.0, Tracking.pX, Tracking.pY, 0.0, this.vX, this.vY, 0.0, this.pX, this.pY, 0.0, this.aM, 0.0, 0.0, rbt, ROT, out vectors, out tui);
Is that the aiming(target) point (where the missile will go to)?
If not is there a calculation in your system, that can give me these point in level coordinates?
thx hulk





There is no aiming(target) point, as you have worded it, but there is a static Tracking class which monitors the position of the target every timestep, and, given this history, calculates what acceleration, velocity, and position the target must have to produce the last three locations it was given. I'm careful to avoid calling these computations "estimates," as in my system they are not (due to the fact that objects do in fact behave in a second derivative fashion), but if the target behaved in some unexpected manor, these would be only a best guess (as in times when the target is evading, or in scenarios where the target does not behave in a .5At^2 + Vt + P way).
In a nutshell, We're passing in what appears to be the target's acceleration, velocity, and position, along with all the other things we know. If the target behaves in a constant acceleration fashion, these will be spot on. The reason I did this was to demonstrate that the guidance system does not need the target to be faxing it's movement parameters (like it's current acceleration vector) to the missile in order for the system to function. Rather, I aimed to prove that the missile could figure out what the target is doing if the target isn't so nice as to tell it directly. This is far more realistic (and ergo, not trivial), as my algorithm does not assume that the target related information is directly known. though it is perfectly capable of mathematically solving for what it needs, as it would need to in a practical application.
Gatsby





Hallo Jay Gatsby,
thanks for replying, I work on a small space shooter game similarly yours (but with DX9).My intention was to combine your guidance system with a pathfinding system like A*. But if there is no point wich i can give the pathfinding system this does not work i together.
Hulk





After some thought, you may be able to modify it to give you what you're looking for.
you may recall this block of code from the bottom of the intercept function in Targeting.cs
for (int i = 0; i != roots.Count; i++)
{
double x;
double y;
double z;
if (pam == 0.0 && pvm == 0.0)
{
x = svx;
y = svy;
z = svz;
}
else
{
x = 0.5 * tax * roots[i] * roots[i] + tvx * roots[i] + tpx;
y = 0.5 * tay * roots[i] * roots[i] + tvy * roots[i] + tpy;
z = 0.5 * taz * roots[i] * roots[i] + tvz * roots[i] + tpz;
}
double m = Math.Sqrt((x * x + y * y + z * z));
if (m < double.Epsilon)
m = 1.0;
vectors[i, 0] = x / m;
vectors[i, 1] = y / m;
vectors[i, 2] = z / m;
}
What that's doing is finding out where the point of impact will be, and giving a unit vector in that direction (always do the else code in your case, the if is there merely to point the missile prograde when out of fuel). Note that x, y, and z are *offsets* from the shooter, so you'd have to add those back in if you want global coords. What you'd need to do is pass those offset, ununormalized raw coordinates. I threw them out in the stock intercept method because a unit vector giving direction is far more useful to someone scaling the initial launch vectors higher on the call stack. But yea, the x, y, and z as they come raw from the else block here, added to the spx, spy, and spz values respectively, should be what you're looking for, if I understood your question correctly.
Gatsby







Could you please provide some documentation as to what the arguments your expecting for the functions are? For example, the code you posted in the WW2 message:
Calculate(double Sx, double Sy, double Sh, double Sv, double Tx, double Ty, double Th, double Tv,double Pv, bool InDegrees)
I have no ideal what I'm suppose to pass for Sx, Sy, Sh ...etc.
/// <summary>
///
/// </summary>
/// <param name="Sx"></param>
/// <param name="Sy"></param>
/// <param name="Sh"></param>
/// <param name="Sv"></param>
/// <param name="Tx"></param>
/// <param name="Ty"></param>
/// <param name="Th"></param>
/// <param name="Tv"></param>
/// <param name="Pv"></param>
/// <param name="InDegrees"></param>
/// <returns></returns>
public static double Calculate(double Sx, double Sy, double Sh, double Sv, double Tx, double Ty, double Th, double Tv, double Pv, bool InDegrees)
What I'm trying to accomplish is given two points with angle and speed, what's the equation to calculate at which point the two points will intersect. I need to make a boolean function that will calculate this and return true if they will intersect, and false if not. Then handle false by adjusting the direction in which point two travels to accommodate an interception with point one.





Good news, I can definitely help you!
I will start by identifying the intent of the parameters you have listed, but bear in mind that they are for firing on a target, not what you have explained what you need to do. Once I've done that I'll detail what you should do in your case.
Sx: the x coordinate of the shooter
Sy: the y coordinate of the shooter
Sh: the heading angle of the shooter
Sv: the speed of the shooter (along the bearing provided by Sh)
Tx, Ty, Th, and Tv are the same as the above four, but for the target, not the shooter
Pv: the speed of the projectile (we don't know it's heading, that's what we'll solve for)
InDegrees: true indicates that Sh and Th (and the returned Ph value) will be in degrees (i.e. 180), while false indicates that these values should be interpreted as radians (i.e. 3.14159...etc.).
What you need to do is pass in obj1.x for Sx, obj1.y for Sy, 0 for Sh, 0 for Sv, obj2.x for Tx, obj2.y for Ty, obj2.h for Th, obj2.v for Tv and obj1.v for Pv (and true or false for InDegrees, depending on weather you're using degrees or not for your angle measures). If an exception is thrown it means that not only will an intercept never occur, there's no way that you can adjust the heading of obj1 ot make an intercept occur. If, however, no exception is thrown, the return value you get will indicate the heading that the first object would need to have in order to intercept, and if the first object's heading is very close to this it will hit second object (i.e. the difference in heading is less than some predefined small constant, 0.000000001 being a good choice. Use AbsoluteValue(h1h2) < smallConstant for this determination, true == headings are really close, false == they're not. Do NOT use zero, rounding errors will plague youthe result will always be false!) You said that you wanted to know the heading that would be needed to intercept if no intercept would occur, well look no further, that Ph return value is what you are looking for. (Please remember to credit me with coming up with this algorithm.)
Let me know if that helps. If you are still having difficulties, please let me know, and provide what you've got so farI'll be glad to help!
Thanks for writing!
Gatsby





Thanks alot, worked like a charm , what I'm working on is a homing missle in 2D for a video game I'm trying to make. Heres what I got for the homing missle so far. Keep in mind that this is sloppy coding and my goal right now was just to get it working. My next step will be to go through and get the rest working then fine tune it. Plus, this only works for the 1st and 2nd quadrant right now. The missle will actually curve towards the target on a fixed radius until the point of intercept is true, so you get more of a realistic effect as the missle travels. This is using the TorqueX game engine and XNA.
//
public float Intercept(float Sx, float Sy, float Sh, float Sv, float Tx, float Ty,
float Th, float Tv, float Pv, bool InDegrees)
{
if(InDegrees)
{
Sh = Sh * (float)(Math.PI / 180.0);
Th = Th * (float)(Math.PI / 180.0);
}
float theta = (float)Math.Atan2(Tx  Sx, Ty  Sy);
float shOff = Sh  theta;
float thOff = Th  theta;
float svxOff = (float)(Sv * Math.Sin(shOff));
float svyOff = (float)(Sv * Math.Cos(shOff));
float tvxOff = (float)(Tv * Math.Sin(thOff));
float tvyOff = (float)(Tv * Math.Cos(thOff));
float phOff = (float)Math.Asin((tvxOff  svxOff) / Pv);
float crosscheck = (float)Math.Cos(phOff) * Pv;
if(float.IsNaN(phOff)  tvyOff  svyOff >= crosscheck)
return 1;
return InDegrees ? (float)((phOff + theta) * 180.0 / Math.PI) : phOff + theta;
}
// In a seperate function (Rendering objects. i.e. per tick)
if((Game.Instance.Missile.Position.X + 2.5f >= Game.Instance.Enemy.Position.X) &&
(Game.Instance.Missile.Position.X  2.5f <= Game.Instance.Enemy.Position.X) &&
(Game.Instance.Missile.Position.Y + 2.5f >= Game.Instance.Enemy.Position.Y) &&
(Game.Instance.Missile.Position.Y  2.5f <= Game.Instance.Enemy.Position.Y))
{
Vector2 vPos = new Vector2(0.0f, 0.0f);
Game.Instance.Missile.SetPosition(vPos, false);
Game.Instance.Missile.SetRotation(180.0f, false);
Globals.setOrigin = true;
}
float fIntr = Intercept(Game.Instance.Missile.Position.X, Game.Instance.Missile.Position.Y,
Game.Instance.Missile.Rotation, 0.25f, Game.Instance.Enemy.Position.X,
Game.Instance.Enemy.Position.Y, Game.Instance.Enemy.Rotation, 0.1f, 0.25f, true);
float angle = T2DVectorUtil.AngleFromTarget(Game.Instance.Enemy.Position,
Game.Instance.Missile.Position);
if((angle > 180.0f) && (angle < 275.0f)) // 1st quadrant
{
if((Globals.fAdjAngle > 275.0f)  (Globals.fAdjAngle < 180.0f))
Globals.fAdjAngle = 275.0f;
if(Globals.setOrigin)
{
Globals.fOrigin = Game.Instance.Missile.Position.X  15.0f;
Globals.setOrigin = false;
}
if(fIntr > angle + 3.5f)
{
Vector2 vPos = new Vector2(Globals.fOrigin * (float)Math.Sin(Globals.DegreesToRadians(Globals.fAdjAngle)),
Globals.fOrigin * (float)Math.Cos(Globals.DegreesToRadians(Globals.fAdjAngle)));
Game.Instance.Missile.SetPosition(vPos, false);
Game.Instance.Missile.SetRotation(angle + 180.0f, false);
}
else
{
Vector2 vPos = new Vector2(Game.Instance.Missile.Position.X + (0.25f * (float)Math.Sin(Globals.DegreesToRadians(Game.Instance.Missile.Rotation))),
Game.Instance.Missile.Position.Y  (0.25f * (float)Math.Cos(Globals.DegreesToRadians(Game.Instance.Missile.Rotation))));
Game.Instance.Missile.SetPosition(vPos, false);
Game.Instance.Missile.SetRotation(angle + 180.0f, false);
}
Globals.fAdjAngle = 0.25f;
}
else if((angle > 90.0f) && (angle < 180.0f)) // 2nd quadrant
{
if((Globals.fAdjAngle > 180.0f)  (Globals.fAdjAngle < 90.0f))
Globals.fAdjAngle = 90.0f;
if(Globals.setOrigin)
{
Globals.fOrigin = Game.Instance.Missile.Position.X + 15.0f;
Globals.setOrigin = false;
}
if(fIntr > 0)
{
Vector2 vPos = new Vector2(Globals.fOrigin * (float)Math.Sin(Globals.DegreesToRadians(Globals.fAdjAngle)),
Globals.fOrigin * (float)Math.Cos(Globals.DegreesToRadians(Globals.fAdjAngle)));
Game.Instance.Missile.SetPosition(vPos, false);
Game.Instance.Missile.SetRotation(angle + 180.0f, false);
}
else
{
Vector2 vPos = new Vector2(Game.Instance.Missile.Position.X + (0.25f * (float)Math.Sin(Globals.DegreesToRadians(Game.Instance.Missile.Rotation))),
Game.Instance.Missile.Position.Y  (0.25f * (float)Math.Cos(Globals.DegreesToRadians(Game.Instance.Missile.Rotation))));
Game.Instance.Missile.SetPosition(vPos, false);
Game.Instance.Missile.SetRotation(angle + 180.0f, false);
}
Globals.fAdjAngle += 0.25f;
}code>
 modified at 20:02 Monday 27th August, 2007





YES! *does a victory dance* I helped somebody! Glad to know it worked for you!
<whisper>You wouldn't mind putting "//Intercept algorithm developed by Christopher Kampas, © 2007, all rights reserved" above "public float Intercept(float Sx, float Sy, float Sh, float Sv, float Tx, float Ty, float Th, float Tv, float Pv, bool InDegrees)" would you? *blush* It would be an honor to "see my name in lights," so to speak... you know what I mean?</whisper>
Gatsby





Lol, I can do that, thanks again!





I appreciate it, and thank you!
Over and out.
Gatsby





Jay,
You are missing a point here. Especially, if you ignore impossible cases.
Try solving the missile 'torpedo' problem (in two dimensions) for all possible vessel and weapon speeds using quadratitics or trig. It won't work.
There is a far simpler logical solution, that was sorted out in WWII to produce the mechanical torpedo aiming calculator known as the 'fuit machine'.
No 1GHz processors in those days.
Roland





First of all, thank you for your interest and the time you gave to comment.
Ivertheengine wrote: Try solving the missile 'torpedo' problem (in two dimensions) for all possible vessel and weapon speeds using quadratitics or trig. It won't work.
Really? I seemed to have figured out that one a while back. (these acronyms are referring to x position, y position, heading, and velocity (along that provided heading), where we want to solve for the projectile's heading, given everything else about this problem) Here's my original code, it's actually my very first analytical solution for this problem that I came up with:
public static class InterceptCourse
{
public static double Calculate(double Sx, double Sy, double Sh, double Sv, double Tx, double Ty, double Th, double Tv,
double Pv, bool InDegrees)
{
if (InDegrees)
{
Sh = Sh * Math.PI / 180.0;
Th = Th * Math.PI / 180.0;
}
double theta = Math.Atan2(Tx  Sx, Ty  Sy);
double shOff = Sh  theta;
double thOff = Th  theta;
double svxOff = Sv * Math.Sin(shOff);
double svyOff = Sv * Math.Cos(shOff);
double tvxOff = Tv * Math.Sin(thOff);
double tvyOff = Tv * Math.Cos(thOff);
double phOff = Math.Asin((tvxOff  svxOff) / Pv);
double crosscheck = Math.Cos(phOff) * Pv;
if (double.IsNaN(phOff)  tvyOff  svyOff >= crosscheck)
throw new UnableToInterceptException();
return InDegrees ? (phOff + theta) * 180.0 / Math.PI : phOff + theta;
}
}
public class UnableToInterceptException : Exception
{
public UnableToInterceptException() : base("Unable To Intercept") { }
}
Ivertheengine wrote: There is a far simpler logical solution, that was sorted out in WWII to produce the mechanical torpedo aiming calculator known as the 'fuit machine'.
I'm still looking at this, but, just to make sure we're on the same page, did you mean "fruit machine?" The Google query "fuit machine" torpedo yields a dead end, while "fruit machine" torpedo yields some really promising references, like this[^] for example.
Gatsby







Did you win the comp with this, or did the color one slip in there.
Either way, great job.."I shall be watching your future most carefully" (starwars quote, but the guy he was referring to turned out to be the badest dude (Darth Vader) in the galaxy, so perhaps not quite such an honour. mmmmm)
Sacha Barber
A Modern Geek  I cook, I clean, I drink, I Program. Modern or what?
My Blog : sachabarber.net





It seems I lost by three votes, meh, It was fun while it lasted anyway.
That's what the poll says anyway (http://www.codeproject.com/script/survey/detail.asp?survey=695[^]), it doesn't seem that they've made it official yet(http://www.codeproject.com/script/competitions/monthly/[^] still lists May winners at the bottom), but that'll come any time soon. I'm O.K. with it at any rate, nice to know I got selected for the "editor's choice" on the homepage, even if the byline is blankWho cares at that point anyway?
I'm still humored that I got more votes in the monthly competition than I have received for this article directly...
I'm nothing but encouraged! I never thought I could write an article that could go anywhereblood is in the water now! I can't wait to do this again!
Gatsby





You did great. I voted for you at any rate.
Jay Gatsby wrote: I'm nothing but encouraged! I never thought I could write an article that could go anywhereblood is in the water now! I can't wait to do this again!
Yeah that happens. It happened to me, I have been a CP member 3 1/2 year, but only started to write articles about 9 months ago, and now look im addicted.
I think we both have many more good ones to come
Sacha Barber
A Modern Geek  I cook, I clean, I drink, I Program. Modern or what?
My Blog : sachabarber.net





You took the honored path for learning this craft: take a problem that keeps pestering you, spend a lot of time thinking with a pen and paper interface, then spend a lot of time programming. Yes, the code could be cleaner, and the comments more focused. Don't worry, that'll come. What's already there is the ability to stay focused and get the results. After 25 yrs on programming you learn to recognize the signs: you'll do great!





Jay,
This article is very very interesting.
I salute you sir.
Sacha Barber
A Modern Geek  I cook, I clean, I drink, I Program. Modern or what?
My Blog : sachabarber.net





Sacha! good to hear from you again.
Wow... It's an honor that you like it, thank you! Good luck on the monthly competition! your entry is outstanding!
you salute me? I'm honored, but it should be the other way around! (salutes Sacha)
Gatsby





Jay,
To be honest I think my entry this month, is fairly tame. However, the one im writing at the moment is very cool. taking a very long time to do, but its good I hope.
I love your article, its very very impressive for your 1st one. Hopefully plenty more to come from you.
Keep it up
Sacha Barber
A Modern Geek  I cook, I clean, I drink, I Program. Modern or what?
My Blog : sachabarber.net





Well I can't wait to read your next one!
Thanks.
Gatsby





The new one is WPF also, but i am also using WCF, as I am interested in seeing how all this new stuff works together.
Ive tried Winforms / LINQ, and also WPF/ XLINQ, So I thought Id try WPF/WCF combo.
Its nearly done. It takes me longer these days, as I work full time now. Where as before I had loads of spare time, as I was doing an MSc.
Sacha Barber
A Modern Geek  I cook, I clean, I drink, I Program. Modern or what?
My Blog : sachabarber.net





Hi,
I am sorry I didn't read the whole article.. I will read this later, but from the information gathered by reading couple of paragraph and also looking at the animation it seems that your concept is wrong, you expect the target to move in the predicted path, you shoot the missile in a way so that it meet the target if it move in the predicted path. In real world case the moving target always change it's direction, target will definitely change it’s direction after you shoot the missile, in that case your system will fail, isn’t that so.. in order to solve the issue you have to dynamically adjust the missile direction regularly to increase the accuracy.
The latest missile guidance systems do dynamically adjust their direction according to the moving direction and speed of it's target..
Let me see your thoughts..
L.W.C. Nirosh.
Colombo,
Sri Lanka.





well yes, of course you have to adjust for evasion. That's what the checkbox in the Simple UI download demonstrates. the concept is not wrong at all: if you don't evade I should be able to hit you in a straight line, this means that if you do evade there is a new straight line I should follow, and I adjust my flightpath to account for this new vector, if no evasion occurs, I will continue to fly in a straight line towards the intercept. The way it works is the missile "intercepts" the target at EVERY timestep (when onboard guidance is enabled, of course). By performing the calculation each timestep, the instant the target changes it's motion the missile reacts to it and then proceeds on that straight line until interception or until it needs to change again to account for evasion (in which case it rides that line until impact, unless another evasion occurs... etc.). The real trick is calculating those straight lines, and that is what my guidance system does.
Play around with the Simple UI with onboard guidance turned on (put a check in the box to activate it) to improve understanding. Note that when things wrap around the screen it messes with the guidance system, because it's tracking using three points in space that the target is at relative to it and isn't anticipating a warping movement like wrapping around, but You'll get the picture when you see what goes on. you move, the missile makes one turn and then keeps on coming in a straight line (unless you move again, then it makes another small course correction and heads in a straight line etc.).
The graphs etc' are for the calculation of these straight lines. The line will not necessarily play out this way (evasion etc.) but it is the fastest way to the target, and as such, if they want to evade, they will have to work the hardest to get out of the way if the missile attempts to lead the target in this manner.
Thanks for inquiring.
Gatsby





I am sorry for not checking the demo before commenting..
If you do consider the direction and also the *relative* *speed* for these calculations.. this should be a complete one..
L.W.C. Nirosh.
Colombo,
Sri Lanka.





Actually, that's step one of the algorithm. the shooter's paramerters are nullified to produce the scenario in terms of relitive position and relitive velocity.
Thanks for writing
Gatsby





Gatsby, you should consider some limitations when changing trajectory and / or speed of your missile while is moving in "guided" mode. You can never hit a target in straight line if it has no constant speed and direction, or its speed / acceleration is greater than you missile. What I'm trying to say is that your missile can't fly like a fly (the insect) or a mosquito... in zigzag.





I must admit I'm a little confused by this, but I do love taking suggestions.
If you were talking about constraints on maneuverability... those are already present, are you suggesting that the limitations be even greater? if so, you can just adjust a constant in my application's source for this effect... I think I called it MAXDELTATHETA or something.
If you were talking about zigzagging as a result of evasion, this is actually the optimum response, because while the missile is wasting energy by repeatedly performing this elaborate twostep, bear in mind that the target is losing just as much by jinking around to invoke such highG maneuvers. It takes two to tango. The moment the target consolidates and proceeds by accelerating straight, the missile's maneuvering will have it right on course, and advantaged by the target's evasioninduced slowdown, but if the target never consolidates and chooses to push it's evasion all the way to the wall the missile will likely make a glancing blow because it cannot maneuver fast enough when it gets really close to the target to put it right down the middle, but the target will have so little energy by now that it might as well be standing stillAt any rate, energy is the key to success; as the relative speed between the missile and the target increases, the effectiveness of an evasive action increases, and as the distance between missile and target decreases the same is true, but only up to a pointit's bad news if evasion is too late because there simply isn't enough time to get clear of the missile as it flies past.
...But I think I may have missed what you were getting at altogether...
Gatsby






Very nice reply... very informative, experienced and certainly well documented. Thank you!
I'd like to see an article on this subject written like this.
I'm not so well informed on the advanced military technology... and your reply was correct to contradict; my point was different, though: do you see anything in the above article about the mass / centrifuge force of both target and missile, so how is the "zigzag" motion handled? How about other more complicated corrections that need to be applied when handling motion? No matter how advanced technology might become, it will remain bound to phisycs rules. The math (modelling) presented here is far from any realtime / reallife example. But hey, as I've struggled for long already to make everyone understand... it's a great start, and I'm merely trying to motivate the author to go further in detail... who knows, maybe even "patent" something... making a great future in research; I think he might like it, 'cause it's one hell of an interesting life.
Best regards,





Recall that the same rules that apply to the warplane attempting to 'seduce' the incoming missile  the laws of physics aren't 'particular' about who or what they apply to. WHat you do to one side of the equation must be done to the other. In this case, the absence is balanced.
And I'd venture to say that the absence of newtonian and other physical equations dealing with force vectoring (weight, drag, lift, densityaltitude, gyroscopic drift, counterangular and countercentrifugal mathematic calculations fed against consequential and intended flight pathing adjustments) is likely the result that the young gentleman doesn't have access to a lab where these things can be modeled more effectively.
Afterall, it took the resources of the US Government and the best brains in the engineering business fifty years to produce the kind of weapons and weapon technology employed today. A visit to a few web sites will give you the rather interesting history of the AIM9 air to air missile  which was first run by vacuum tubes fed by a spinning cassagrain mirror back in the 1950's. It was able to make small adjustments in the flight path and strike a moving target. As you might appreciate, the missile's 'brain' was strictly analog  the seeker caused the rocket to constantly oscillate in its flight path.
The gap in generations and deployment of further developments in the AIM9 family basically follow the halfcentury long march toward the kind of weapon platform I described earlier; one that can so rapidly calculate the movement of the target and analyze the consequential flight path, that no matter what amount of jinking and evasion technique employed, the missile's Pk (probability of Kill) will be so high that the pilot might as well eject before he lifts off.
The young man who wrote this code and figured out the foundational aspects of the missile tracking problem just graduated high school. I too want to encourage him to keep pushing, explore the boundaries and break through them. Let's not burden him with attempting to be perfect  rather, let's celebrate that he's on our side.;P
The madman is not the man who has lost his reason; the madman is the man who has lost everything except his reason.
G.K. Chesterton





Redgum wrote: let's celebrate that he's on our side.
And rather proud of it.
Jeez you know alot!
A word on the unincluded factors, if I may: I have come to the conclusion that the missile can lead a target with the understanding of any number of external forces beyond plain old constant acceleration that behave in any way imaginable (logarithmic for air resistance, trigonometric for orbits, etc., rather than the pure polynomial stuff I've been using), with a massive rewrite of the equations; however, I have come to the conclusion (and can prove, if need be) that my underlying approach to the problem will work in any environment in which time ticks by at a constant rate (please don't make me drag in general relativity... it seems trivial to do so on things not even remotely close to the speed of light). The underlying truth is the Tt = Pt conclusion. That is to say that, once I have negated the shooter's influence on the problem, the missile can hit the target if/when the missile's distance from the origin is the same as the target's distance from the origin (the origin, again, is the missile's launch point with the shooter parameters negated, and therefore subsequently subtracted from the target), if and only if the missile's behavior relative to the origin is the same no matter which way I point it. But that's still quite an obstacle.
My current research is in the area of these socalled "dynamic" trajectories, i.e. situations where the output of the Pt equation depends on the direction the missile is fired. The problem here is that I can no longer calculate how long it will take without knowing which way I am going to need to aim, instead of vice versa, as I do now.
Anyway, your comments got me thinking on the matter, expect a sequel someday in the semidistant future.
Gatsby





>Anyway, your comments got me thinking on the matter, expect a sequel someday in the semidistant future.
I'm looking forward to it. Just be mindful  as crazy as it might at first seem  that such algorithms and programmatic representations of them can be classified as 'munitions' and subject to strict exportation laws.
Don't be surprised if you get a personal visit requesting that you cease and desist by a nice man in a suit with a National Security Agency credential after posting the sequel. The good news is that the guy who visits after him will likely have a quaint little job offer.
In the meantime, there are some challenges ahead of you. Keep up the good work!
Mike
p.s. And if you'd like someone to betatest, I'm usually available
The madman is not the man who has lost his reason; the madman is the man who has lost everything except his reason.
G.K. Chesterton





Thank you for your kind words and your informative reply, I will bear all of this in mind.
Redgum wrote: And if you'd like someone to betatest, I'm usually available
You're really too kind; I might just take you up on that when I get my next version to that stage, as it will doubtlessly be much more complicated.
Gatsby





Hi,
i´m not a good programmer, but as i took classes of econometrics, to dynamicaly adjust equations before we get new values for the parameters we use the Kalman Filter... i really don´t know if this will work, but is a good try when you need to make adjusts.
Fernando Pavani







General News Suggestion Question Bug Answer Joke Praise Rant Admin Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

