How to solve the numerical instability to a solution of a system of ordinary differential equations - numerical-methods

I have been trying to get the numerical solution to the following system of ordinary differential equations:
Equations for the movement of a body through air in a inclined lunch:
(apparently LaTeX doesn't work on stack overflow)
u'= -F(u, theta, t)*cos(theta)
v'= -F(v, theta, t)*sin(theta)-mg
by the Runge-Kutta-Fehlberg Algorithm, but in the middle of the computation i have to calculate theta, that is calculated by
arccos(u/sqrt(u^2+v^2)) or arcsin(v/sqrt(u^2+v^2)),
but eventually theta gets too small and I need it to solve the function F( v, theta, t) and to find the value V = sqrt(v^2 + u^2) I use V = (v/sin(theta)), but as theta gets small so does sin(theta) and I get a numerical error from a given iteration forward -1.IND00, It is problably because theta is too small, i tried to make theta go from a small positive angle like 0.00001 to a small negative angle like -0.00001 (if(fabs(theta)<0.00001) theta = -0.00001) but it seems that theta gets trapped into this negative value, does anyone have an indication on what to do to resolve this numerical instability ?

It is a bad idea to use the inverse cosine or sine functions to determine the angle of a point. To get
theta = arg ( u + i*v)
use
theta = atan2(v,u).
This still has the problem that it jumps on the negative half axis, that is for v=0, u<0. That can be solved by making theta a third dynamical variable, so that
theta' = Im( (u'+i*v')/(u+i*v) ) = (u*v' - u'*v) / (u^2+v^2)
But really, the equation for the free fall with air friction is easiest implemented as
def friction(vx, vy):
v = hypot(vx, vy)
return k*v
def freefall_ode(t, u):
rx, ry, vx, vy = u
f=friction(vx, vy)
ax = -f*vx
ay = -f*vy - g
return array([ vx, vy, ax, ay ])
so that you do not need any angle or to try to weaken the coupling of the velocity components by reducing it to the angle of the velocity vector. This you can now plug into the integration method of your choice, applied as a method for vector-valued systems.

Related

Why that I have written for Andrew Ng's course not accepted?

Andrew Ng's course in Coursera, which Stanford's Machine Learning course, features programming assignments that deal with implementing the algorithms taught in class. The goal of this assignment is to implement linear regression through gradient descent with an input set of X, y, theta, alpha (learning rate), and number of iterations.
I implemented this solution in Octave, the prescribed language in the course.
function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)
m = length(y);
J_history = zeros(num_iters, 1);
numJ = size(theta, 1);
for iter = 1:num_iters
for i = 1:m
for j = 1:numJ
temp = theta(j) - alpha /m * X(i, j) * (((X * theta)(i, 1)) - y(i, 1));
theta(j) = temp
end
prediction = X * theta;
J_history(iter, 1) = computeCost(X,y,theta)
end
end
On the other hand, here is the cost function:
function J = computeCost(X, y, theta)
m = length(y);
J = 0;
prediction = X * theta;
error = (prediction - y).^2;
J = 1/(2 * m) .* sum(error);
end
This does not pass the submit() function. The submit() function simply validates the data through passing an unknown test case.
I have checked other questions on StackOverflow but I really don't get it. :)
Thank you very much!
Your gradient seems to be correct and as already pointed out in the answer given by #Kasinath P, it is likely that the problem is that the code is too slow. You just need to vectorize it. In Matlab/Octave, you usually need to avoid for loops (note that although you have parfor in Matlab, it is not yet available in octave). So it is always better, performance-wise, to write something like A*x instead of iterating over each row of A with a for loop. You can read about vectorization here.
If I understand correctly, X is a matrix of size m*numJ where m is the number of examples, and numJ is the number of features (or the dimension of the space where each point lies. In that case, you can rewrite your cost function as
(1/(2*m)) * (X*theta-y)'*(X*theta-y);%since ||v||_2^2=v'*v for any vector v in Euclidean space
Now, we know from basic matrix calculus that for any two vectors s and v that are functions from R^{num_J} to R^m, the Jacobian of s^{t}v is given by
s^{t}Jacobian(v)+v^{t}*Jacobian(s) %this Jacobian will have size 1*num_J.
Applying that to your cost function, we obtain
jacobian=(1/m)*(theta'*X'-y')*X;
So if you just replace
for i = 1:m
for j = 1:numJ
%%% theta(j) updates
end
end
with
%note that the gradient is the transpose of the Jacobian we've computed
theta-=alpha*(1/m)*X'*(X*theta-y)
you should see a great increase in performance.
your computecost code is correct
and Better follow the vectorized implementation of Gradient Descent.
You are just iterating and it is slow and may have error.
That course aims you to do vectorized implementation as it is simple and handy at the same time.
I knew this because I did that after sweating a lot.
Vectorization is good:)

Explanation of a Hough accumulator that does not match image

I was having fun with image processing and hough transforms on Octave but the results are not the expected ones.
Here is my edges image:
and here is my hough accumulator (x-axis is angle in deg, y-axis is radius):
I feel like I am missing the horizontal streaks but there is no local maximum in the accumulator for the 0/180 angle values.
Also, for the vertical streaks, the value of the radius should be equal to the x value of the edge's image, but instead the values of r are very high:
exp: the first vertical line on the left of the image has an equation of x=20(approx) -> r.r = x.x + y.y -> r=x -> r=20
The overall resulting lines detected do not match the edges at all:
Acculmulator with detected maxima:
Resulting lines:
As you can see the maximas of the accumulator are satisfyingly detected but the resulting lines' radius values are too high and theta values are missing.
It almost looks like the hough transform accumulator does not correspond to the image...
Can someone help me figure out why and how to correct it?
Here is my code:
function [r, theta] = findScratches (img, edge)
hough = houghtf(edge,"line", pi*[0:360]/180);
threshHough = hough>.5*max(hough(:));
[r, theta] = find(threshHough>0);
%deg to rad for the trig functions
theta = theta/180*pi;
%according to octave doc r range is 2*diagonal
%-> bring it down to 1*diagonal or all lines are out of the picture
r = r/2;
%coefficients of the line y=ax+b
a = -cos(theta)./sin(theta);
b = r./sin(theta);
x = 1:size(img,2);
y = a * x + b;
figure(1)
imagesc(edge);
colormap gray;
hold on;
for i=1:size(y,1)
axis ij;
plot(y(i,:),x,'r','linewidth',1);
end
hold off;
endfunction
Thank you in advance.
You're definitely on the right track. Blurring the accumulator image would help before looking for the hotspots. Also, why not do a quick erode and dilate before doing the hough transform?
I had the same issue - detected lines had the correct slope but were shifted. The problem is that the r returned by the find(threshHough>0) function call is in the interval of [0,2*diag] while the Hough transform operates with values of r from the interval of [-diag,diag]. Therefore if you change the line
r=r/2
to
r=r-size(hough,1)/2
you will get the correct offset.
Lets define a vector of angles (in radians):
angles=pi*[0:360]/180
You should not take this operation: theta = theta/180*pi.
Replace it by: theta = angles(theta), where theta are indices
Some one commented above suggesting adjusting r to -diag to +diag range by
r=r-size(hough,1)/2
This worked well for me. However another difference was that I used the default angle to compute Hough Transform with angles -90 to +90. The theta range in the vector is +1 to +181. So It needs to be adjusted by -91, then convert to radian.
theta = (theta-91)*pi/180;
With above 2 changes, rest of the code works ok.

Correct solution for this tensor

I'm implementing the system in this paper and I've come a little unstuck correctly implementing the radial tensor field.
All tensors in this system are of the form given on page 3, section 4
R [ cos(2t), sin(2t); sin(2t), -cos(2t) ]
The radial tensor field is defined as:
R [ yy - xx, -2xy; -2xy, -(yy-xx) ]
In my system I'm only storing R and Theta, since I can calculate the tensor based off just that information. This means I need to calculate R and Theta for the radial tensor. Unfortunately, my attempts at this have failed. Although it looks correct, my solution fails in the top left and bottom right quadrants.
Addendum: Following on from discussion in the comments about the image of the system not working, I'll put some hard numbers here too.
The entire tensor field is 800x480, the center point is at { 400, 240 }, and we're using the standard graphics coordinate system with a negative y axis (ie. origin in the top left).
At { 400, 240 }, the tensor is R = 0, T = 0
At { 200, 120 }, the tensor is R = 2.95936E+9, T = 2.111216
At { 600, 120 }, the tensor is R = 2.95936E+9, T = 1.03037679
I can easily sample any more points which you think may help.
The code I'm using to calculate values is:
float x = i - center.X;
float xSqr = x * x;
float y = j - center.Y;
float ySqr = y * y;
float r = (float)Math.Pow(xSqr + ySqr, 2);
float theta = (float)Math.Atan2((-2 * x * y), (ySqr - xSqr)) / 2;
if (theta < 0)
theta += MathHelper.Pi;
Evidently you are comparing formulas (1) and (2) of the paper. Note the scalar multiple l = || (u_x,u_y) || in formula (1), and identify that with R early in the section. This factor is implicit in formula (2), so to make them match we have to factor R out.
Formula (2) works with an offset from the "center" (x0,y0) of the radial map:
x = xp - x0
y = yp - y0
to form the given 2x2 matrix:
y^2 - x^2 -2xy
-2xy -(y^2 - x^2)
We need to factor out a scalar R from this matrix to get a traceless orthogonal 2x2 matrix as in formula (1):
cos(2t) sin(2t)
sin(2t) -cos(2t)
Since cos^2(2t) + sin^2(2t) = 1 the factor R can be identified as:
R = (y^2 - x^2)^2 + (-2xy)^2 = (x^2 + y^2)^2
leaving a traceless orthogonal 2x2 matrix:
C S
S -C
from which the angle 'tan(2t) = S/C` can be extracted by an inverse trig function.
Well, almost. As belisarius warns, we need to check that angle t is in the correct quadrant. The authors of the paper write at the beginning of Sec. 4 that their "t" (which refers to the tensor) depends on R >= 0 and theta (your t) lying in [0,2pi) according to the formula R [ cos(2t), sin(2t); sin(2t) -cos(2t) ].
Since sine and cosine have period 2pi, t (theta) is only uniquely determined up to an interval of length pi. I suspect the authors meant to write either that 2t lies in [0,2pi) or more simply that t lies in [0,pi). belisarius suggestion to use "the atan2 equivalent" will avoid any division by zero. We may (if the function returns a negative value) need to add pi so that t >= 0. This amounts to adding 2pi to 2t, so it doesn't affect the signs of the entries in the traceless orthogonal matrix (since 'R >= 0` the pattern of signs should agree in formulas (1) and (2) ).

Using GNU Octave FFT functions

I'm playing with octave's fft functions, and I can't really figure out how to scale their output: I use the following (very short) code to approximate a function:
function y = f(x)
y = x .^ 2;
endfunction;
X=[-4096:4095]/64;
Y = f(X);
# plot(X, Y);
F = fft(Y);
S = [0:2047]/2048;
function points = approximate(input, count)
size = size(input)(2);
fourier = [fft(input)(1:count) zeros(1, size-count)];
points = ifft(fourier);
endfunction;
Y = f(X); plot(X, Y, X, approximate(Y, 10));
Basically, what it does is take a function, compute the image of an interval, fft-it, then keep a few harmonics, and ifft the result. Yet I get a plot that is vertically compressed (the vertical scale of the output is wrong). Any ideas?
You are throwing out the second half of the transform. The transform is Hermitian symmetric for real-valued inputs and you have to keep those lines. Try this:
function points = approximate(inp, count)
fourier = fft(inp);
fourier((count+1):(length(fourier)-count+1)) = 0;
points = real(ifft(fourier)); %# max(imag(ifft(fourier))) should be around eps(real(...))
endfunction;
The inverse transform will invariably have some tiny imaginary part due to numerical computation error, hence the real extraction.
Note that input and size are keywords in Octave; clobbering them with your own variables is a good way to get really weird bugs down the road!
You are probably doing it wrong. You remove all the "negative" frequencies in your code. You should keep both positive and negative low frequencies. Here is a code in python and the result. The plot has the right scale.
alt text http://files.droplr.com/files/35740123/XUl90.fft.png
The code:
from __future__ import division
from scipy.signal import fft, ifft
import numpy as np
def approximate(signal, cutoff):
fourier = fft(signal)
size = len(signal)
# remove all frequencies except ground + offset positive, and offset negative:
fourier[1+cutoff:-cutoff] = 0
return ifft(fourier)
def quad(x):
return x**2
from pylab import plot
X = np.arange(-4096,4096)/64
Y = quad(X)
plot(X,Y)
plot(X,approximate(Y,3))

Finding points on a line with a given distance

I have a question i know a line i just know its slope(m) and a point on it A(x,y) How can i calculate the points(actually two of them) on this line with a distance(d) from point A ???
I m asking this for finding intensity of pixels on a line that pass through A(x,y) with a distance .Distance in this case will be number of pixels.
I would suggest converting the line to a parametric format instead of point-slope. That is, a parametric function for the line returns points along that line for the value of some parameter t. You can represent the line as a reference point, and a vector representing the direction of the line going through that point. That way, you just travel d units forward and backward from point A to get your other points.
Since your line has slope m, its direction vector is <1, m>. Since it moves m pixels in y for every 1 pixel in x. You want to normalize that direction vector to be unit length so you divide by the magnitude of the vector.
magnitude = (1^2 + m^2)^(1/2)
N = <1, m> / magnitude = <1 / magnitude, m / magnitude>
The normalized direction vector is N. Now you are almost done. You just need to write the equation for your line in parameterized format:
f(t) = A + t*N
This uses vector math. Specifically, scalar vector multiplication (of your parameter t and the vector N) and vector addition (of A and t*N). The result of the function f is a point along the line. The 2 points you are looking for are f(d) and f(-d). Implement that in the language of your choosing.
The advantage to using this method, as opposed to all the other answers so far, is that you can easily extend this method to support a line with "infinite" slope. That is, a vertical line like x = 3. You don't really need the slope, all you need is the normalized direction vector. For a vertical line, it is <0, 1>. This is why graphics operations often use vector math, because the calculations are more straight-forward and less prone to singularities.
It may seem a little complicated at first, but once you get the hang of vector operations, a lot of computer graphics tasks get a lot easier.
Let me explain the answer in a simple way.
Start point - (x0, y0)
End point - (x1, y1)
We need to find a point (xt, yt) at a distance dt from start point towards end point.
The distance between Start and End point is given by d = sqrt((x1 - x0)^2 + (y1 - y0)^2)
Let the ratio of distances, t = dt / d
Then the point (xt, yt) = (((1 - t) * x0 + t * x1), ((1 - t) * y0 + t * y1))
When 0 < t < 1, the point is on the line.
When t < 0, the point is outside the line near to (x0, y0).
When t > 1, the point is outside the line near to (x1, y1).
Here's a Python implementation to find a point on a line segment at a given distance from the initial point:
import numpy as np
def get_point_on_vector(initial_pt, terminal_pt, distance):
v = np.array(initial_pt, dtype=float)
u = np.array(terminal_pt, dtype=float)
n = v - u
n /= np.linalg.norm(n, 2)
point = v - distance * n
return tuple(point)
Based on the excellent answer from #Theophile here on math stackexchange.
Let's call the point you are trying to find P, with coordinates px, py, and your starting point A's coordinates ax and ay. Slope m is just the ratio of the change in Y over the change in X, so if your point P is distance s from A, then its coordinates are px = ax + s, and py = ay + m * s. Now using Pythagoras, the distance d from A to P will be d = sqrt(s * s + (m * s) * (m * s)). To make P be a specific D units away from A, find s as s = D/sqrt(1 + m * m).
I thought this was an awesome and easy to understand solution:
http://www.physicsforums.com/showpost.php?s=f04d131386fbd83b7b5df27f8da84fa1&p=2822353&postcount=4