I found an example online which contains a method that back propagates the error and adjusts the weights. I was wondering how this exactly works and what weight update algorithm is used. Could it be gradient descent?
/**
* all output propagate back
*
* #param expectedOutput
* first calculate the partial derivative of the error with
* respect to each of the weight leading into the output neurons
* bias is also updated here
*/
public void applyBackpropagation(double expectedOutput[]) {
// error check, normalize value ]0;1[
for (int i = 0; i < expectedOutput.length; i++) {
double d = expectedOutput[i];
if (d < 0 || d > 1) {
if (d < 0)
expectedOutput[i] = 0 + epsilon;
else
expectedOutput[i] = 1 - epsilon;
}
}
int i = 0;
for (Neuron n : outputLayer) {
ArrayList<Connection> connections = n.getAllInConnections();
for (Connection con : connections) {
double ak = n.getOutput();
double ai = con.leftNeuron.getOutput();
double desiredOutput = expectedOutput[i];
double partialDerivative = -ak * (1 - ak) * ai
* (desiredOutput - ak);
double deltaWeight = -learningRate * partialDerivative;
double newWeight = con.getWeight() + deltaWeight;
con.setDeltaWeight(deltaWeight);
con.setWeight(newWeight + momentum * con.getPrevDeltaWeight());
}
i++;
}
// update weights for the hidden layer
for (Neuron n : hiddenLayer) {
ArrayList<Connection> connections = n.getAllInConnections();
for (Connection con : connections) {
double aj = n.getOutput();
double ai = con.leftNeuron.getOutput();
double sumKoutputs = 0;
int j = 0;
for (Neuron out_neu : outputLayer) {
double wjk = out_neu.getConnection(n.id).getWeight();
double desiredOutput = (double) expectedOutput[j];
double ak = out_neu.getOutput();
j++;
sumKoutputs = sumKoutputs
+ (-(desiredOutput - ak) * ak * (1 - ak) * wjk);
}
double partialDerivative = aj * (1 - aj) * ai * sumKoutputs;
double deltaWeight = -learningRate * partialDerivative;
double newWeight = con.getWeight() + deltaWeight;
con.setDeltaWeight(deltaWeight);
con.setWeight(newWeight + momentum * con.getPrevDeltaWeight());
}
}
}
It seems to me this solution uses stochastic gradient descent. The main difference between it and the regular gradient decent is that the gradient is approximated for each example instead of calculating it for all examples and then selecting the best direction. This is the usual approach to implementing backpropagtion and even has some advantages to gradient decent(can avoid some local minima). I believe the article also exaplains what is the idea and there are also a lot of other articles that explain the main idea behind back-propagation.
This ugly looking article seems to be describing exactly the same version of the algorithm: http://www.speech.sri.com/people/anand/771/html/node37.html. I have the same formulas in my university papers, but regretfully: a) they are not available online; b) they are in language you will not understand.
As for gradient descent, the algorithm resembles gradient descent, but is not guaranteed to reach optimal position. In each step change is done over the network edges changing their values so that the training example value's probability increases.
Related
I am trying to calculate sine of an angle without using the Math.sin(). I got stuck in it's equation as I keep getting the wrong results
note I have a method that changes the angle from degrees to radians
public static double sin(double x, int precision) {
//this method is simply the sine function
double answer = 1, power = 1;
int n = 2,factorial = 1;
while (n<=precision) {
power = (power * x * x *-1) +1 ;
factorial = (factorial * (n +1))* (n-1);
answer = answer + ((power/factorial ));
n = n + 2;
}
return answer;
}
It looks like you're attempting to calculate the sine of angle given in radians using the Maclaurin series, a special case of Taylor series.
sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
Your initial answer is 1 when it should be x. Your initial power is 1 when it should be x also.
double answer = x, power = x;
For some reason you're adding one to the power part of the result when you shouldn't be.
power = (power * x * x * -1);
You'll also need to fix your factorial calculation. Multiply by n + 1 and n, not n + 1 and n - 1.
factorial = (factorial * (n + 1)) * (n);
With these fixes, testing:
for (double angle = 0; angle <= Math.PI; angle += Math.PI / 4)
{
System.out.println("sin(" + angle + ") = " + sin(angle, 10));
}
The results are pretty good considering the limitations of precision for floating point arithmetic.
sin(0.0) = 0.0
sin(0.7853981633974483) = 0.7071067811796194
sin(1.5707963267948966) = 0.999999943741051
sin(2.356194490192345) = 0.7070959900908971
sin(3.141592653589793) = -4.4516023820965686E-4
Note that this will get more inaccurate as the values of x get larger, not just because of the inaccuracy to represent pi, but also because of the floating point calculations for adding and subtracting large values.
I currently have a PID algorithm to control my robots turns in an autonomous state. My robot has encoders, on each motor, which there are four of, and also a BNO055IMU. Furthermore each motor is a never rest 40 motor from Andymark, and unfortunately I am stuck with encoders that do 3 pulses. I would like to improve the accuracy of my turns either by using a different algorithm or improving my current one.
My Current Turning Code:
public void turn(int angle, Direction DIRECTION, double timeOut, int sleepTime, double kp, double ki, double kd) {
double targetAngle = imu.adjustAngle(imu.getHeading() + (DIRECTION.value * angle));
double acceptableError = 0.5;
double currentError = 1;
double prevError = 0;
double integral = 0;
double newPower;
double previousTime = 0;
timeoutClock.reset();
while (opModeIsActive() && (imu.adjustAngle(Math.abs(currentError)) > acceptableError)
&& !timeoutClock.elapsedTime(timeOut, MasqClock.Resolution.SECONDS)) {
double tChange = System.nanoTime() - previousTime;
previousTime = System.nanoTime();
tChange = tChange / 1e9;
double imuVAL = imu.getHeading();
currentError = imu.adjustAngle(targetAngle - imuVAL);
integral += currentError * ID;
double errorkp = currentError * kp;
double integralki = integral * ki * tChange;
double dervitive = (currentError - prevError) / tChange;
double dervitivekd = dervitive * kd;
newPower = (errorkp + integralki + dervitivekd);
newPower *= color;
if (Math.abs(newPower) > 1.0) {newPower /= newPower;}
driveTrain.setPower(newPower, -newPower);
prevError = currentError;
DashBoard.getDash().create("TargetAngle", targetAngle);
DashBoard.getDash().create("Heading", imuVAL);
DashBoard.getDash().create("AngleLeftToCover", currentError);
DashBoard.getDash().update();
}
driveTrain.setPower(0,0);
sleep(sleepTime);
}
NOTES:
when driveTrain.setPower(x,y); is called the left parameter is the power set to the left side and the right parameter sets the right side.
Direction is an enum that stores wither -1, or 1 to switch between left and right turns.
Dashboard.getDash.create is solely to keep a log on what is going on.
imu.adjustAngle does the following:
public double adjustAngle(double angle) {
while (angle > 180) angle -= 360;
while (angle <= -180) angle += 360;
return angle;
}
imu.getHeading() is self explanatory it gets the yaw of the robot.
My current values for pid constants. (They work pretty well.)
KP_TURN = 0.005,
KI_TURN = 0.0002,
KD_TURN = 0,
ID = 1;
He everyone!
I'm writing an Android app that uses the devices GPS to calculate a vehicles driving speed. This is supposed to be accurate to about 1-2 km/h, and I'm doing it by looking at the distance between two GPS locations and dividing it by the time these locations are apart, pretty straightforward, and then doing this for the last three recorded coordinates and evening it out.
I get the GPS data in a background service, that has a handler to it's own looper, so whenever I get a new location from the LocationListener, I call the Kalmans update() method and call the predict() in a handler in regular intervals by calling sendEmptyDelayedMessage to itself after the predict()
I have read Smooth GPS data and have actually also tried implementing the filter in the github that was provided by villoren in an answer to that topic, which also yielded fluctuating results.
I have then adapted the demo code from this tutorial http://www.codeproject.com/Articles/326657/KalmanDemo, which I am working with right now. I did all the maths by hand to better understand the filter, and I'm not sure if I understood his provided source code completely, but this is what I am working with right now:
The part where I commented out
/*// K = P * H^T *S^-1
double k = m_p0 / s;
// double LastGain = k;
// X = X + K*Y
m_x0 += y0 * k;
m_x1 += y1 * k;
// P = (I – K * H) * P
m_p0 = m_p0 - k* m_p0;
m_p1 = m_p1 - k* m_p1;
m_p2 = m_p2 - k* m_p2;
m_p3 = m_p3 - k* m_p3;
*/
is where I didn't agree with the maths of the code provided, but given (he states) he has implemented Kalman filters in rocket guidance systems I am inclined to believe his maths is right ;)
public class KalmanFilter {
/*
X = State
F = rolls X forward, typically be some time delta.
U = adds in values per unit time dt.
P = Covariance – how each thing varies compared to each other.
Y = Residual (delta of measured and last state).
M = Measurement
S = Residual of covariance.
R = Minimal innovative covariance, keeps filter from locking in to a solution.
K = Kalman gain
Q = minimal update covariance of P, keeps P from getting too small.
H = Rolls actual to predicted.
I = identity matrix.
*/
//State X[0] =position, X[1] = velocity.
private double m_x0, m_x1;
//P = a 2x2 matrix, uncertainty
private double m_p0, m_p1,m_p2, m_p3;
//Q = minimal covariance (2x2).
private double m_q0, m_q1, m_q2, m_q3;
//R = single value.
private double m_r;
//H = [1, 0], we measure only position so there is no update of state.
private final double m_h1 = 1, m_h2 = 0;
//F = 2x2 matrix: [1, dt], [0, 1].
public void update(double m, double dt){
// Predict to now, then update.
// Predict:
// X = F*X + H*U
// P = F*X*F^T + Q.
// Update:
// Y = M – H*X Called the innovation = measurement – state transformed by H.
// S = H*P*H^T + R S= Residual covariance = covariane transformed by H + R
// K = P * H^T *S^-1 K = Kalman gain = variance / residual covariance.
// X = X + K*Y Update with gain the new measurement
// P = (I – K * H) * P Update covariance to this time.
// X = F*X + H*U
double oldX = m_x0;
m_x0 = m_x0 + (dt * m_x1);
// P = F*X*F^T + Q
m_p0 = m_p0 + dt * (m_p2 + m_p1) + dt * dt * m_p3 + m_q0;
m_p1 = m_p1 + dt * m_p3 + m_q1;
m_p2 = m_p2 + dt * m_p3 + m_q2;
m_p3 = m_p3 + m_q3;
// Y = M – H*X
//To get the change in velocity, we pretend to be measuring velocity as well and
//use H as [1,1]
double y0 = m - m_x0;
double y1 = ((m - oldX) / dt) - m_x1;
// S = H*P*H^T + R
//because H is [1,0], s is only a single value
double s = m_p0 + m_r;
/*// K = P * H^T *S^-1
double k = m_p0 / s;
// double LastGain = k;
// X = X + K*Y
m_x0 += y0 * k;
m_x1 += y1 * k;
// P = (I – K * H) * P
m_p0 = m_p0 - k* m_p0;
m_p1 = m_p1 - k* m_p1;
m_p2 = m_p2 - k* m_p2;
m_p3 = m_p3 - k* m_p3;
*/
// K = P * H^T *S^-1
double k0 = m_p0 / s;
double k1 = m_p2 / s;
// double LastGain = k;
// X = X + K*Y
m_x0 += y0 * k0;
m_x1 += y1 * k1;
// P = (I – K * H) * P
m_p0 = m_p0 - k0* m_p0;
m_p1 = m_p1 - k0* m_p1;
m_p2 = m_p2 - k1* m_p2;
m_p3 = m_p3 - k1* m_p3;
}
public void predict(double dt){
//X = F * X + H * U Rolls state (X) forward to new time.
m_x0 = m_x0 + (dt * m_x1);
//P = F * P * F^T + Q Rolls the uncertainty forward in time.
m_p0 = m_p0 + dt * (m_p2 + m_p1) + dt * dt * m_p3 + m_q0;
/* m_p1 = m_p1+ dt * m_p3 + m_q1;
m_p2 = m_p2 + dt * m_p3 + m_q2;
m_p3 = m_p3 + m_q3;*/
}
/// <summary>
/// Reset the filter.
/// </summary>
/// <param name="qx">Measurement to position state minimal variance.</param>
/// <param name="qv">Measurement to velocity state minimal variance.</param>
/// <param name="r">Measurement covariance (sets minimal gain).</param>
/// <param name="pd">Initial variance.</param>
/// <param name="ix">Initial position.</param>
/**
*
* #param qx Measurement to position state minimal variance = accuracy of gps
* #param qv Measurement to velocity state minimal variance = accuracy of gps
* #param r Masurement covariance (sets minimal gain) = 0.accuracy
* #param pd Initial variance = accuracy of gps data 0.accuracy
* #param ix Initial position = position
*/
public void reset(double qx, double qv, double r, double pd, double ix){
m_q0 = qx; m_q1 = qv;
m_r = r;
m_p0 = m_p3 = pd;
m_p1 = m_p2 = 0;
m_x0 = ix;
m_x1 = 0;
}
public double getPosition(){
return m_x0;
}
public double getSpeed(){
return m_x1;
}
}
I'm using two 1D Filters, one for latitude and one for longitude and then construct a new location object out of that after each predict call.
My initialization is qx = gpsAccuracy, qv = gpsAccuracy, r = gpsAccuracy/10 , pd = gpsAccuracy/10, ix = initial position.
I use the values after the tutorial I got the code from, this is what he recommended in the comments.
Using this, I get speeds that are a) fluctuating a lot, and b) speeds that are WAY off, I get speeds from 50 - a few hundred km/h while walking, and then also the occasional 5-7, which is more accurate, but I need the speeds to be consistent and at least in a sensible range.
I see a few issues:
Your update() contains predict and update, but you also have a predict(), so you would be double-integrating velocity if you actually call predict() (you didn't include the outer loop).
There's some confusion as to whether your measurement is position or position and velocity. You can see comments claiming H=[1,0] and H=[1,1] (by which they probably meant H=[1,0;0,1]) Since the matrix math is hand-written, the assumption about the single measurement is baked into all of the matrix steps, but the code still tries to "measure" velocity as well.
For a KF which estimates velocity from positions, you do not want to inject synthetic velocity like that (as a first-order difference). Let that result occur naturally from the KF. For H=[1,0], you can see how K=PH'/S should have 2 rows, and both apply to y0. That will update both x0 and x1.
I didn't really check the matrix math other than to see what they had done with H. You should really develop this kind of algorithm with a nice matrix library (e.g. numpy, for Python, or Eigen for C++). That will save you a lot of code changes when you make trivial changes (e.g. if you want to experiment with a 2D filter) and avoid simple matrix math errors that will drive you mad. If you have to optimize to fully hand-written matrix operations, do it last so you can compare your results and verify your hand coding.
And finally, the other posts are entirely correct about your specific application: The GPS is already filtering the data, and one of the outputs is velocity.
Try this simple change:
float speed = location.getSpeed() x 4;
GPS location, delivered by the GPS receiver are already heavily Kalman filtered. If the locations are still jumping you cannot well solve that with a Kalman filter.
The cause is that moving with a low speed does not well give stable positions and speed (and direction)
Just remove all location under 10km/h and there will be no further need to any filtering.
Seeing as Valentine's Day is fast approaching, I decided to create a heart. So I found this heart from mathematica.se:
I played around in Mathematica (solved for z, switching some variables around) to get this equation for the z-value of the heart, given the x and y values (click for full-size):
I faithfully ported this equation to Java, dealing with a couple out-of-bounds cases:
import static java.lang.Math.cbrt;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
...
public static double heart(double xi, double yi) {
double x = xi;
double y = -yi;
double temp = 5739562800L * pow(y, 3) + 109051693200L * pow(x, 2) * pow(y, 3)
- 5739562800L * pow(y, 5);
double temp1 = -244019119519584000L * pow(y, 9) + pow(temp, 2);
//
if (temp1 < 0) {
return -1; // this is one possible out of bounds location
// this spot is the location of the problem
}
//
double temp2 = sqrt(temp1);
double temp3 = cbrt(temp + temp2);
if (temp3 != 0) {
double part1 = (36 * cbrt(2) * pow(y, 3)) / temp3;
double part2 = 1 / (10935 * cbrt(2)) * temp3;
double looseparts = 4.0 / 9 - 4.0 / 9 * pow(x, 2) - 4.0 / 9 * pow(y, 2);
double sqrt_body = looseparts + part1 + part2;
if (sqrt_body >= 0) {
return sqrt(sqrt_body);
} else {
return -1; // this works; returns -1 if we are outside the heart
}
} else {
// through trial and error, I discovered that this should
// be an ellipse (or that it is close enough)
return Math.sqrt(Math.pow(2.0 / 3, 2) * (1 - Math.pow(x, 2)));
}
}
The only problem is that when temp1 < 0, I cannot simply return -1, like I do:
if (temp1 < 0) {
return -1; // this is one possible out of bounds location
// this spot is the location of the problem
}
That's not the behavior of the heart at that point. As it is, when I try to make my image:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import static java.lang.Math.cbrt;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
public class Heart {
public static double scale(int x, int range, double l, double r) {
double width = r - l;
return (double) x / (range - 1) * width + l;
}
public static void main(String[] args) throws IOException {
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_RGB);
// this is actually larger than the max heart value
final double max_heart = 0.679;
double max = 0.0;
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
double xv = scale(x, img.getWidth(), -1.2, 1.2);
double yv = scale(y, img.getHeight(), -1.3, 1);
double heart = heart(xv, yv); //this isn't an accident
// yes I don't check for the return of -1, but still
// the -1 values return a nice shade of pink: 0xFFADAD
// None of the other values should be negative, as I did
// step through from -1000 to 1000 in python, and there
// were no negatives that were not -1
int r = 0xFF;
int gb = (int) (0xFF * (max_heart - heart));
int rgb = (r << 16) | (gb << 8) | gb;
img.setRGB(x, y, rgb);
}
}
ImageIO.write(img, "png", new File("location"));
}
// heart function clipped; it belongs here
}
I get this:
Look at that dip at the top! I tried changing that problematic -1 to a .5, resulting in this:
Now the heart has horns. But it becomes clear where that problematic if's condition is met.
How can I fix this problem? I don't want a hole in my heart at the top, and I don't want a horned heart. If I could clip the horns to the shape of a heart, and color the rest appropriately, that would be perfectly fine. Ideally, the two sides of the heart would come together as a point (hearts have a little point at the join), but if they curve together like shown in the horns, that would be fine too. How can I achieve this?
The problem is simple. If we look at that horseshoe region, we get imaginary numbers. For part of it, it should belong to our heart. In that region, if we were to evaluate our function (by math, not by programming), the imaginary parts of the function cancel. So it should look like this (generated in Mathematica):
Basically, the function for that part is almost identical; we just have to do arithmetic with complex numbers instead of real numbers. Here's a function that does exactly that:
private static double topOfHeart(double x, double y, double temp, double temp1) {
//complex arithmetic; each double[] is a single number
double[] temp3 = cbrt_complex(temp, sqrt(-temp1));
double[] part1 = polar_reciprocal(temp3);
part1[0] *= 36 * cbrt(2) * pow(y, 3);
double[] part2 = temp3;
part2[0] /= (10935 * cbrt(2));
toRect(part1, part2);
double looseparts = 4.0 / 9 - 4.0 / 9 * pow(x, 2) - 4.0 / 9 * pow(y, 2);
double real_part = looseparts + part1[0] + part2[0];
double imag_part = part1[1] + part2[1];
double[] result = sqrt_complex(real_part, imag_part);
toRect(result);
// theoretically, result[1] == 0 should work, but floating point says otherwise
if (Math.abs(result[1]) < 1e-5) {
return result[0];
}
return -1;
}
/**
* returns a specific cuberoot of this complex number, in polar form
*/
public static double[] cbrt_complex(double a, double b) {
double r = Math.hypot(a, b);
double theta = Math.atan2(b, a);
double cbrt_r = cbrt(r);
double cbrt_theta = 1.0 / 3 * (2 * PI * Math.floor((PI - theta) / (2 * PI)) + theta);
return new double[]{cbrt_r, cbrt_theta};
}
/**
* returns a specific squareroot of this complex number, in polar form
*/
public static double[] sqrt_complex(double a, double b) {
double r = Math.hypot(a, b);
double theta = Math.atan2(b, a);
double sqrt_r = Math.sqrt(r);
double sqrt_theta = 1.0 / 2 * (2 * PI * Math.floor((PI - theta) / (2 * PI)) + theta);
return new double[]{sqrt_r, sqrt_theta};
}
public static double[] polar_reciprocal(double[] polar) {
return new double[]{1 / polar[0], -polar[1]};
}
public static void toRect(double[]... polars) {
for (double[] polar: polars) {
double a = Math.cos(polar[1]) * polar[0];
double b = Math.sin(polar[1]) * polar[0];
polar[0] = a;
polar[1] = b;
}
}
To join this with your program, simply change your function to reflect this:
if (temp1 < 0) {
return topOfHeart(x, y, temp, temp1);
}
And running it, we get the desired result:
It should be pretty clear that this new function implements exactly the same formula. But how does each part work?
double[] temp3 = cbrt_complex(temp, sqrt(-temp1));
cbrt_complex takes a complex number in the form of a + b i. That's why the second argument is simply sqrt(-temp1) (notice that temp1 < 0, so I use - instead of Math.abs; Math.abs is probably a better idea). cbrt_complex returns the cube root of the complex number, in polar form: r eiθ. We can see from wolframalpha that with positive r and θ, we can write an n-th root of a complex numbers as follows:
And that's exactly how the code for the cbrt_complex and sqrt_complex work. Note that both take a complex number in rectangular coordinates (a + b i) and return a complex number in polar coordinates (r eiθ)
double[] part1 = polar_reciprocal(temp3);
It is easier to take the reciprocal of a polar complex number than a rectangular complex number. If we have r eiθ, its reciprocal (this follows standard power rules, luckily) is simply 1/r e-iθ. This is actually why we are staying in polar form; polar form makes multiplication-type operations easier, and addition type operations harder, while rectangular form does the opposite.
Notice that if we have a polar complex number r eiθ and we want to multiply by a real number d, the answer is as simple as d r eiθ.
The toRect function does exactly what it seems like it does: it converts polar coordinate complex numbers to rectangular coordinate complex numbers.
You may have noticed that the if statement doesn't check that there is no imaginary part, but only if the imaginary part is really small. This is because we are using floating point numbers, so checking result[1] == 0 will likely fail.
And there you are! Notice that we could actually implement the entire heart function with this complex number arithmetic, but it's probably faster to avoid this.
I am working on the problem of dividing an ellipse into equal sized segments. This question has been asked but the answers suggested numerical integration so that I what I'm attempting. This code short-circuits the sectors so the integration itself should never cover more than 90 degrees. The integration itself is being done by totaling the area of intermediate triangles. Below is the code I have tried, but it is sweeping more than 90 degrees in some cases.
public class EllipseModel {
protected double r_x;
protected double r_y;
private double a,a2;
private double b,b2;
boolean flip;
double area;
double sector_area;
double radstep;
double rot;
int xp,yp;
double deviation;
public EllipseModel(double r_x, double r_y, double deviation)
{
this.r_x = r_x;
this.r_y = r_y;
this.deviation = deviation;
if (r_x < r_y) {
flip = true;
a = r_y;
b = r_x;
xp = 1;
yp = 0;
rot = Math.PI/2d;
} else {
flip = false;
xp = 0;
yp = 1;
a = r_x;
b = r_y;
rot = 0d;
}
a2 = a * a;
b2 = b * b;
area = Math.PI * r_x * r_y;
sector_area = area / 4d;
radstep = (2d * deviation) / a;
}
public double getArea() {
return area;
}
public double[] getSweep(double sweep_area)
{
System.out.println(String.format("getSweep(%f) a = %f b = %f deviation = %f",sweep_area,a,b,deviation));
double[] ret = new double[2];
double[] next = new double[2];
double t_base, t_height, swept,x_mid,y_mid;
double t_area;
sweep_area = sweep_area % area;
if (sweep_area < 0d) {
sweep_area = area + sweep_area;
}
if (sweep_area == 0d) {
ret[0] = r_x;
ret[1] = 0d;
return ret;
}
double sector = Math.floor(sweep_area/sector_area);
double theta = Math.PI * sector/2d;
double theta_last = theta;
System.out.println(String.format("- Theta start = %f",Math.toDegrees(theta)));
ret[xp] = a * Math.cos(theta + rot);
ret[yp] = (1 + (((theta / Math.PI) % 2d) * -2d)) * Math.sqrt((1 - ( (ret[xp] * ret[xp])/a2)) * b2);
next[0] = ret[0];
next[1] = ret[1];
swept = sector * sector_area;
System.out.println(String.format("- Sweeping for %f sector_area=%f",sweep_area-swept,sector_area));
int c = 0;
while(swept < sweep_area) {
c++;
ret[0] = next[0];
ret[1] = next[1];
theta_last = theta;
theta += radstep;
// calculate next point
next[xp] = a * Math.cos(theta + rot);
next[yp] = (1 + (((theta / Math.PI) % 2d) * -2d)) * // selects +/- sqrt
Math.sqrt((1 - ( (ret[xp] * ret[xp])/a2)) * b2);
// calculate midpoint
x_mid = (ret[xp] + next[xp]) / 2d;
y_mid = (ret[yp] + next[yp]) / 2d;
// calculate triangle metrics
t_base = Math.sqrt( ( (ret[0] - next[0]) * (ret[0] - next[0]) ) + ( (ret[1] - next[1]) * (ret[1] - next[1])));
t_height = Math.sqrt((x_mid * x_mid) + (y_mid * y_mid));
// add triangle area to swept
t_area = 0.5d * t_base * t_height;
swept += t_area;
}
System.out.println(String.format("- Theta end = %f (%d)",Math.toDegrees(theta_last),c));
return ret;
}
}
In the output I see the following case where it sweeps over 116 degrees.
getSweep(40840.704497) a = 325.000000 b = 200.000000 deviation = 0.166667
- Theta start = 0.000000
- Sweeping for 40840.704497 sector_area=51050.880621
- Theta end = 116.354506 (1981)
Is there any way to fix the integration formula to create a function that returns the point on an ellipse that has swept a given area? The application that is using this code divides the total area by the number of segments needed, and then uses this code to determine the angle where each segment starts and ends. Unfortunately it doesn't work as intended.
* edit *
I believe the above integration failed because the base and height formula's aren't correct.
No transformation needed use parametric equations for ellipse ...
x=x0+rx*cos(a)
y=y0+ry*sin(a)
where a = < 0 , 2.0*M_PI >
if you divide ellipse by lines from center to x,y from above equation
and angle a is evenly encreased
then the segments will have the same size
btw. if you apply affine transform you will get the same result (even the same equation)
This code will divide ellipse to evenly sized chunks:
double a,da,x,y,x0=0,y0=0,rx=50,ry=20; // ellipse x0,y0,rx,ry
int i,N=32; // divided to N = segments
da=2.0*M_PI/double(N);
for (a=0.0,i=0;i<N;i++,a+=da)
{
x=x0+(rx*cos(a));
y=y0+(ry*sin(a));
// draw_line(x0,y0,x,y);
}
This is what it looks like for N=5
[edit1]
I do not understood from your comment what exactly you want to achieve now
sorry but my English skills are horrible
ok I assume these two possibilities (if you need something different please specify closer)
0.but first some global or member stuff needed
double x0,y0,rx,ry; // ellipse parameters
// [Edit2] sorry forgot to add these constants but they are I thin straight forward
const double pi=M_PI;
const double pi2=2.0*M_PI;
// [/Edit2]
double atanxy(double x,double y) // atan2 return < 0 , 2.0*M_PI >
{
int sx,sy;
double a;
const double _zero=1.0e-30;
sx=0; if (x<-_zero) sx=-1; if (x>+_zero) sx=+1;
sy=0; if (y<-_zero) sy=-1; if (y>+_zero) sy=+1;
if ((sy==0)&&(sx==0)) return 0;
if ((sx==0)&&(sy> 0)) return 0.5*pi;
if ((sx==0)&&(sy< 0)) return 1.5*pi;
if ((sy==0)&&(sx> 0)) return 0;
if ((sy==0)&&(sx< 0)) return pi;
a=y/x; if (a<0) a=-a;
a=atan(a);
if ((x>0)&&(y>0)) a=a;
if ((x<0)&&(y>0)) a=pi-a;
if ((x<0)&&(y<0)) a=pi+a;
if ((x>0)&&(y<0)) a=pi2-a;
return a;
}
1.is point inside segment ?
bool is_pnt_in_segment(double x,double y,int segment,int segments)
{
double a;
a=atanxy(x-x0,y-y0); // get sweep angle
a/=2.0*M_PI; // convert angle to a = <0,1>
if (a>=1.0) a=0.0; // handle extreme case where a was = 2 Pi
a*=segments; // convert to segment index a = <0,segments)
a-=double(segment );
// return floor(a); // this is how to change this function to return points segment id
// of course header should be slightly different: int get_pnt_segment_id(double x,double y,int segments)
if (a< 0.0) return false; // is lower then segment
if (a>=1.0) return false; // is higher then segment
return true;
}
2.get edge point of segment area
void get_edge_pnt(double &x,double &y,int segment,int segments)
{
double a;
a=2.0*M_PI/double(segments);
a*=double(segment); // this is segments start edge point
//a*=double(segment+1); // this is segments end edge point
x=x0+(rx*cos(a));
y=y0+(ry*sin(a));
}
for booth:
x,y is point
segments number of division segments.
segment is sweep-ed area < 0,segments )
Apply an affine transformation to turn your ellipse into a circle, preferrably the unit circle. Then split that into equal sized segments, before you apply the inverse transform. The transformation will scale all areas (as opposed to lengths) by the same factor, so equal area translates to equal area.