showing wrong value from equation - android

i am trying to implement following equation but not showing exact value.
Suppose the value of data1 to data9 are:5,1,1,1,2,1,3,1,1 and the value of y will be 2.
but showing null.original equation link:https://www.researchgate.net/publication/303232034_Mathematical_Model_Development_to_Detect_Breast_Cancer_Using_Multigene_Genetic_Programming
double term3 =Math.cos(Math.log10(data7))/(data6+data7-6.419);
double y=0.05321*Math.log10(Math.exp(data2-1.0*Math.sin(Math.cos(data8))+Math.cos(data6)-(1.0*data6)/(data1*data3*data9*Math.sin(data8)*Math.tanh(data8))))-1.573*Math.sin(Math.sqrt(data4+data6+term3))
-0.07468*Math.sin(Math.exp(data2*data9))
-0.9181*Math.log10(2.0*data4+data6+Math.sin(Math.tanh(data7)+5.626*data4*data9)+Math.sin(Math.sin(Math.sin(data8)))
+Math.sin(Math.sin(2.0*data6-7.128))+(Math.cos(data4)/(data6+data7-6.649))+(Math.cos(data4)/(data6+data7-6.634))+(Math.cos(data4)/(data4*(2.0*data6-1.479))))
+0.2919*Math.sin(Math.sin(Math.cos(data2+data5+data8)/data2+data7-6.76))
-0.07468*Math.sin(Math.sqrt(2.0*data4+data7-1.0*Math.sqrt(data6)))
-0.07468*Math.sin(data6)-((5.381*Math.pow(10, 15)*Math.cos(Math.sqrt(data2*Math.pow(data3, 2))))/(7.206*Math.pow(10, 16)*data3+7.206*Math.pow(10, 16)*data5-4.934*Math.pow(10, 17)))
-((5.381*Math.pow(10, 15)*Math.cos(Math.sqrt(data1*data3*data4)))/(7.206*Math.pow(10, 16)*data5+Math.sqrt(Math.tanh(data7))*(data7-1.0*data4+7.206*Math.pow(10, 16)*Math.cos(data6))-4.836*Math.pow(10, 17)))
+((5.258*Math.pow(10, 15)*Math.cos(data4))/(1.801*Math.pow(10, 16)*data2+1.801*Math.pow(10, 16)*data7-1.2*Math.pow(10, 17)))
+(0.4014*Math.cos(data6+data7)+Math.sqrt(data7+5.446))/((data5+Math.log10(data1)-6.585)*(Math.log10(data7)-1.0*Math.tanh(data5)-5.646*data4*data9)
+Math.sqrt(Math.tanh(data8))*(data7-1.0*data4+Math.cos(data6))+data2*Math.pow(data4, 2)*Math.cos(data2)*Math.cos(data6))-0.003903*data1*Math.cos(Math.sqrt(data2+data4+data6-1.0*Math.sqrt(data4)))*(
3.057*data1+2.0*data2-1.0*data4+data6+data7+data9+Math.cos(6.478*data6)+Math.cos(data6)-1.0*Math.sqrt(data1*data3*data6)-6.419)+((0.2919*Math.cos(Math.sqrt(data1*data3*data6)))/(2.0*data6-7.218)*(data5+data7-6.76))+5.235;
the value of y must be either 2 or 4 .but it is not intering in the if else condition
int x= (int) y;
if(x==2 )
{
condition="B";
Toast.makeText(getApplicationContext(),"value of x is "+x,Toast.LENGTH_LONG).show();
}
else if(x==4)
{
condition="M";
Toast.makeText(getApplicationContext(),"value of x is "+x,Toast.LENGTH_LONG).show();
}
cann't understand where is the problem....help please...

Since y is a double, calculations are extremely unlikely to give exactly 2 or 4. What's probably happening is that y is a tiny bit smaller than 2 or 4 when the first condition fails.
Instead of casting y directly to an int, you could try using long x = Math.round(y);. Alternatively (and perhaps better), just check that Math.abs(y - 2) or Math.abs(y - 4) is smaller than some small threshold (e.g., .0001), so as to allow for possible rounding error.

Related

Add Toast in public class corresponding to any event

There all, i'm a newbie in android programming and i've a school task to analysis some project. So, i choose a Guitar Tuner project from github called pTune (link: here).
I've read the code and analyze it, from what i read and see there are a needle with an arc meter to see if the input sound (guitar voice) was fit.
In that project i want to display Toast if the tuning process are fit when the dial in 90 degree. So, i've add this Toast but its not displayed..
if (relativeFrequency == targetFrequency){
Toast.makeText(PTuneActivity.this, "FIT", Toast.LENGTH_SHORT).show();
}
That code placed in updateDisplay class, i've placed it in other class but still not work as i want.
public void updateDisplay(float frequency) {
// Calculate difference between target and measured frequency,
// given that the measured frequency can be a factor of target.
float difference = 0;
if (frequency > targetFrequency) {
int divisions = (int) (frequency / targetFrequency);
float modified = targetFrequency * (float) divisions;
if (frequency - modified > targetFrequency / 2) {
modified += targetFrequency;
divisions++;
}
difference = (frequency - modified) / (float) divisions;
} else {
// If target is greater than measured, just use difference.
difference = frequency - targetFrequency;
}
float relativeFrequency = targetFrequency + difference;
// Update TextView
if (relativeFrequency < 1000f)
t.setText(String.format("%.1f Hz", relativeFrequency));
else
t.setText(String.format("%.2f kHz", relativeFrequency/1000));
//My code
if (relativeFrequency == targetFrequency){
Toast.makeText(PTuneActivity.this, "FIT", Toast.LENGTH_SHORT).show();
}
// Update DialView
float value = difference / (targetFrequency / 2) * 90;
dial.update(value);
}
I know this is useless in real implementation but i want to learn android programming.
You're testing equality between 2 floats, one comes from an input ? It might never be exactly equal. You should add some log and an "else" statement to see if it goes inside the "if" because the Toast may not be the real problem
i've just try it by my self by digging and its worked for me, though its not good at all but i thinks ok, just add this line of code upper dial.update(value);
if (frequency >= targetFrequency) {
Toast.makeText(PTuneActivity.this, "FIT", Toast.LENGTH_SHORT).show();
}

Detect whether a polygon is well formed or not (Google Map Android) [duplicate]

From the man page for XFillPolygon:
If shape is Complex, the path may self-intersect. Note that contiguous coincident points in the path are not treated as self-intersection.
If shape is Convex, for every pair of points inside the polygon, the line segment connecting them does not intersect the path. If known by the client, specifying Convex can improve performance. If you specify Convex for a path that is not convex, the graphics results are undefined.
If shape is Nonconvex, the path does not self-intersect, but the shape is not wholly convex. If known by the client, specifying Nonconvex instead of Complex may improve performance. If you specify Nonconvex for a self-intersecting path, the graphics results are undefined.
I am having performance problems with fill XFillPolygon and, as the man page suggests, the first step I want to take is to specify the correct shape of the polygon. I am currently using Complex to be on the safe side.
Is there an efficient algorithm to determine if a polygon (defined by a series of coordinates) is convex, non-convex or complex?
You can make things a lot easier than the Gift-Wrapping Algorithm... that's a good answer when you have a set of points w/o any particular boundary and need to find the convex hull.
In contrast, consider the case where the polygon is not self-intersecting, and it consists of a set of points in a list where the consecutive points form the boundary. In this case it is much easier to figure out whether a polygon is convex or not (and you don't have to calculate any angles, either):
For each consecutive pair of edges of the polygon (each triplet of points), compute the z-component of the cross product of the vectors defined by the edges pointing towards the points in increasing order. Take the cross product of these vectors:
given p[k], p[k+1], p[k+2] each with coordinates x, y:
dx1 = x[k+1]-x[k]
dy1 = y[k+1]-y[k]
dx2 = x[k+2]-x[k+1]
dy2 = y[k+2]-y[k+1]
zcrossproduct = dx1*dy2 - dy1*dx2
The polygon is convex if the z-components of the cross products are either all positive or all negative. Otherwise the polygon is nonconvex.
If there are N points, make sure you calculate N cross products, e.g. be sure to use the triplets (p[N-2],p[N-1],p[0]) and (p[N-1],p[0],p[1]).
If the polygon is self-intersecting, then it fails the technical definition of convexity even if its directed angles are all in the same direction, in which case the above approach would not produce the correct result.
This question is now the first item in either Bing or Google when you search for "determine convex polygon." However, none of the answers are good enough.
The (now deleted) answer by #EugeneYokota works by checking whether an unordered set of points can be made into a convex polygon, but that's not what the OP asked for. He asked for a method to check whether a given polygon is convex or not. (A "polygon" in computer science is usually defined [as in the XFillPolygon documentation] as an ordered array of 2D points, with consecutive points joined with a side as well as the last point to the first.) Also, the gift wrapping algorithm in this case would have the time-complexity of O(n^2) for n points - which is much larger than actually needed to solve this problem, while the question asks for an efficient algorithm.
#JasonS's answer, along with the other answers that follow his idea, accepts star polygons such as a pentagram or the one in #zenna's comment, but star polygons are not considered to be convex. As
#plasmacel notes in a comment, this is a good approach to use if you have prior knowledge that the polygon is not self-intersecting, but it can fail if you do not have that knowledge.
#Sekhat's answer is correct but it also has the time-complexity of O(n^2) and thus is inefficient.
#LorenPechtel's added answer after her edit is the best one here but it is vague.
A correct algorithm with optimal complexity
The algorithm I present here has the time-complexity of O(n), correctly tests whether a polygon is convex or not, and passes all the tests I have thrown at it. The idea is to traverse the sides of the polygon, noting the direction of each side and the signed change of direction between consecutive sides. "Signed" here means left-ward is positive and right-ward is negative (or the reverse) and straight-ahead is zero. Those angles are normalized to be between minus-pi (exclusive) and pi (inclusive). Summing all these direction-change angles (a.k.a the deflection angles) together will result in plus-or-minus one turn (i.e. 360 degrees) for a convex polygon, while a star-like polygon (or a self-intersecting loop) will have a different sum ( n * 360 degrees, for n turns overall, for polygons where all the deflection angles are of the same sign). So we must check that the sum of the direction-change angles is plus-or-minus one turn. We also check that the direction-change angles are all positive or all negative and not reverses (pi radians), all points are actual 2D points, and that no consecutive vertices are identical. (That last point is debatable--you may want to allow repeated vertices but I prefer to prohibit them.) The combination of those checks catches all convex and non-convex polygons.
Here is code for Python 3 that implements the algorithm and includes some minor efficiencies. The code looks longer than it really is due to the the comment lines and the bookkeeping involved in avoiding repeated point accesses.
TWO_PI = 2 * pi
def is_convex_polygon(polygon):
"""Return True if the polynomial defined by the sequence of 2D
points is 'strictly convex': points are valid, side lengths non-
zero, interior angles are strictly between zero and a straight
angle, and the polygon does not intersect itself.
NOTES: 1. Algorithm: the signed changes of the direction angles
from one side to the next side must be all positive or
all negative, and their sum must equal plus-or-minus
one full turn (2 pi radians). Also check for too few,
invalid, or repeated points.
2. No check is explicitly done for zero internal angles
(180 degree direction-change angle) as this is covered
in other ways, including the `n < 3` check.
"""
try: # needed for any bad points or direction changes
# Check for too few points
if len(polygon) < 3:
return False
# Get starting information
old_x, old_y = polygon[-2]
new_x, new_y = polygon[-1]
new_direction = atan2(new_y - old_y, new_x - old_x)
angle_sum = 0.0
# Check each point (the side ending there, its angle) and accum. angles
for ndx, newpoint in enumerate(polygon):
# Update point coordinates and side directions, check side length
old_x, old_y, old_direction = new_x, new_y, new_direction
new_x, new_y = newpoint
new_direction = atan2(new_y - old_y, new_x - old_x)
if old_x == new_x and old_y == new_y:
return False # repeated consecutive points
# Calculate & check the normalized direction-change angle
angle = new_direction - old_direction
if angle <= -pi:
angle += TWO_PI # make it in half-open interval (-Pi, Pi]
elif angle > pi:
angle -= TWO_PI
if ndx == 0: # if first time through loop, initialize orientation
if angle == 0.0:
return False
orientation = 1.0 if angle > 0.0 else -1.0
else: # if other time through loop, check orientation is stable
if orientation * angle <= 0.0: # not both pos. or both neg.
return False
# Accumulate the direction-change angle
angle_sum += angle
# Check that the total number of full turns is plus-or-minus 1
return abs(round(angle_sum / TWO_PI)) == 1
except (ArithmeticError, TypeError, ValueError):
return False # any exception means not a proper convex polygon
The following Java function/method is an implementation of the algorithm described in this answer.
public boolean isConvex()
{
if (_vertices.size() < 4)
return true;
boolean sign = false;
int n = _vertices.size();
for(int i = 0; i < n; i++)
{
double dx1 = _vertices.get((i + 2) % n).X - _vertices.get((i + 1) % n).X;
double dy1 = _vertices.get((i + 2) % n).Y - _vertices.get((i + 1) % n).Y;
double dx2 = _vertices.get(i).X - _vertices.get((i + 1) % n).X;
double dy2 = _vertices.get(i).Y - _vertices.get((i + 1) % n).Y;
double zcrossproduct = dx1 * dy2 - dy1 * dx2;
if (i == 0)
sign = zcrossproduct > 0;
else if (sign != (zcrossproduct > 0))
return false;
}
return true;
}
The algorithm is guaranteed to work as long as the vertices are ordered (either clockwise or counter-clockwise), and you don't have self-intersecting edges (i.e. it only works for simple polygons).
Here's a test to check if a polygon is convex.
Consider each set of three points along the polygon--a vertex, the vertex before, the vertex after. If every angle is 180 degrees or less you have a convex polygon. When you figure out each angle, also keep a running total of (180 - angle). For a convex polygon, this will total 360.
This test runs in O(n) time.
Note, also, that in most cases this calculation is something you can do once and save — most of the time you have a set of polygons to work with that don't go changing all the time.
To test if a polygon is convex, every point of the polygon should be level with or behind each line.
Here's an example picture:
The answer by #RoryDaulton
seems the best to me, but what if one of the angles is exactly 0?
Some may want such an edge case to return True, in which case, change "<=" to "<" in the line :
if orientation * angle < 0.0: # not both pos. or both neg.
Here are my test cases which highlight the issue :
# A square
assert is_convex_polygon( ((0,0), (1,0), (1,1), (0,1)) )
# This LOOKS like a square, but it has an extra point on one of the edges.
assert is_convex_polygon( ((0,0), (0.5,0), (1,0), (1,1), (0,1)) )
The 2nd assert fails in the original answer. Should it?
For my use case, I would prefer it didn't.
This method would work on simple polygons (no self intersecting edges) assuming that the vertices are ordered (either clockwise or counter)
For an array of vertices:
vertices = [(0,0),(1,0),(1,1),(0,1)]
The following python implementation checks whether the z component of all the cross products have the same sign
def zCrossProduct(a,b,c):
return (a[0]-b[0])*(b[1]-c[1])-(a[1]-b[1])*(b[0]-c[0])
def isConvex(vertices):
if len(vertices)<4:
return True
signs= [zCrossProduct(a,b,c)>0 for a,b,c in zip(vertices[2:],vertices[1:],vertices)]
return all(signs) or not any(signs)
I implemented both algorithms: the one posted by #UriGoren (with a small improvement - only integer math) and the one from #RoryDaulton, in Java. I had some problems because my polygon is closed, so both algorithms were considering the second as concave, when it was convex. So i changed it to prevent such situation. My methods also uses a base index (which can be or not 0).
These are my test vertices:
// concave
int []x = {0,100,200,200,100,0,0};
int []y = {50,0,50,200,50,200,50};
// convex
int []x = {0,100,200,100,0,0};
int []y = {50,0,50,200,200,50};
And now the algorithms:
private boolean isConvex1(int[] x, int[] y, int base, int n) // Rory Daulton
{
final double TWO_PI = 2 * Math.PI;
// points is 'strictly convex': points are valid, side lengths non-zero, interior angles are strictly between zero and a straight
// angle, and the polygon does not intersect itself.
// NOTES: 1. Algorithm: the signed changes of the direction angles from one side to the next side must be all positive or
// all negative, and their sum must equal plus-or-minus one full turn (2 pi radians). Also check for too few,
// invalid, or repeated points.
// 2. No check is explicitly done for zero internal angles(180 degree direction-change angle) as this is covered
// in other ways, including the `n < 3` check.
// needed for any bad points or direction changes
// Check for too few points
if (n <= 3) return true;
if (x[base] == x[n-1] && y[base] == y[n-1]) // if its a closed polygon, ignore last vertex
n--;
// Get starting information
int old_x = x[n-2], old_y = y[n-2];
int new_x = x[n-1], new_y = y[n-1];
double new_direction = Math.atan2(new_y - old_y, new_x - old_x), old_direction;
double angle_sum = 0.0, orientation=0;
// Check each point (the side ending there, its angle) and accum. angles for ndx, newpoint in enumerate(polygon):
for (int i = 0; i < n; i++)
{
// Update point coordinates and side directions, check side length
old_x = new_x; old_y = new_y; old_direction = new_direction;
int p = base++;
new_x = x[p]; new_y = y[p];
new_direction = Math.atan2(new_y - old_y, new_x - old_x);
if (old_x == new_x && old_y == new_y)
return false; // repeated consecutive points
// Calculate & check the normalized direction-change angle
double angle = new_direction - old_direction;
if (angle <= -Math.PI)
angle += TWO_PI; // make it in half-open interval (-Pi, Pi]
else if (angle > Math.PI)
angle -= TWO_PI;
if (i == 0) // if first time through loop, initialize orientation
{
if (angle == 0.0) return false;
orientation = angle > 0 ? 1 : -1;
}
else // if other time through loop, check orientation is stable
if (orientation * angle <= 0) // not both pos. or both neg.
return false;
// Accumulate the direction-change angle
angle_sum += angle;
// Check that the total number of full turns is plus-or-minus 1
}
return Math.abs(Math.round(angle_sum / TWO_PI)) == 1;
}
And now from Uri Goren
private boolean isConvex2(int[] x, int[] y, int base, int n)
{
if (n < 4)
return true;
boolean sign = false;
if (x[base] == x[n-1] && y[base] == y[n-1]) // if its a closed polygon, ignore last vertex
n--;
for(int p=0; p < n; p++)
{
int i = base++;
int i1 = i+1; if (i1 >= n) i1 = base + i1-n;
int i2 = i+2; if (i2 >= n) i2 = base + i2-n;
int dx1 = x[i1] - x[i];
int dy1 = y[i1] - y[i];
int dx2 = x[i2] - x[i1];
int dy2 = y[i2] - y[i1];
int crossproduct = dx1*dy2 - dy1*dx2;
if (i == base)
sign = crossproduct > 0;
else
if (sign != (crossproduct > 0))
return false;
}
return true;
}
For a non complex (intersecting) polygon to be convex, vector frames obtained from any two connected linearly independent lines a,b must be point-convex otherwise the polygon is concave.
For example the lines a,b are convex to the point p and concave to it below for each case i.e. above: p exists inside a,b and below: p exists outside a,b
Similarly for each polygon below, if each line pair making up a sharp edge is point-convex to the centroid c then the polygon is convex otherwise it’s concave.
blunt edges (wronged green) are to be ignored
N.B
This approach would require you compute the centroid of your polygon beforehand since it doesn’t employ angles but vector algebra/transformations
Adapted Uri's code into matlab. Hope this may help.
Be aware that Uri's algorithm only works for simple polygons! So, be sure to test if the polygon is simple first!
% M [ x1 x2 x3 ...
% y1 y2 y3 ...]
% test if a polygon is convex
function ret = isConvex(M)
N = size(M,2);
if (N<4)
ret = 1;
return;
end
x0 = M(1, 1:end);
x1 = [x0(2:end), x0(1)];
x2 = [x0(3:end), x0(1:2)];
y0 = M(2, 1:end);
y1 = [y0(2:end), y0(1)];
y2 = [y0(3:end), y0(1:2)];
dx1 = x2 - x1;
dy1 = y2 - y1;
dx2 = x0 - x1;
dy2 = y0 - y1;
zcrossproduct = dx1 .* dy2 - dy1 .* dx2;
% equality allows two consecutive edges to be parallel
t1 = sum(zcrossproduct >= 0);
t2 = sum(zcrossproduct <= 0);
ret = t1 == N || t2 == N;
end

2D Rectangle Collision detection in Android

I have many images that I need to place on a canvas over a long period of time so that they look random. However, I don't want any of the images to overlap with each other. My solution so far is to randomly place the image somewhere on the canvas. If it overlaps I'll generate a new random location to try.
Now the tricky part is to see if where I am about to place the image is going to overlap with another image.
I was going to make a large array of 1's and 0's and manually mark off where I put the images. However, I was wondering if anyone knew of a way to "auto detect" using a method if where I am about to place an image will overlap with an existing image? Or if there is a way to do collision detection using some Android function?
Checking to see if two rectangles overlap is really simple, just use Rect.intersect()
Check out the Rect docs for more information:
http://developer.android.com/reference/android/graphics/Rect.html
Although I would recommend you try something different than what you have described above. In the beginning the probability of a collision will be very low. However as the screen fills up the probability of a collision will rise. This result in a lot of collisions and wasted computational power.
You should use something more efficient, off the top of my head you could try something like this:
Split the screen into a grid of size MxN
Keep a list of all unpopulated grid locations
Pick a random grid location for a new image i
Pick a random width and height for image i
If i intersects a grid location that is already populated or it if goes off the screen shrink it
Draw i
If all grid locations are taken quit, else go to 3
A simple 2D isinbox function could be:
bool IsInBox(int x1, int y1, int width1, int height1, int x2, int y2, int width2, int height2) {
int right1 = x1 + width1;
int right2 = x2 + width2;
int bottom1 = y1 + height1;
int bottom2 = y2 + height2;
// Check if top-left point is in box
if (x2 >= x1 && x2 <= right1 && y2 >= y2 && y2 <= bottom1) return true;
// Check if bottom-right point is in box
if (right2 >= x1 && right2 <= right1 && bottom2 >= y2 && bottom2 <= bottom1) return true;
return false;
}
Not sure if works though xd
Or you could use Rect.Intersect()

how to use a double value in power function

i am trying to find the power of a value.But the problem is my exponent is a fractional value.power function does not suppporting any datatype other than int.
BigDecimal fd_returns_at_time_of_replace=(BigDecimal.valueOf(capitalDiff).multiply((BigDecimal.valueOf((long)constant1+.09)).pow(temp)));
here temp is a fractional value.given below is the eror message i am getting.
The method pow(int) in the type BigDecimal is not applicable for the arguments (double)
please anybody help me to do this.
BigDecimal.pow() only takes an int. To see a cool example of writing BigDecimal.pow() that accepts a double, see this question How to do a fractional power on BigDecimal in Java?
Common Sense
Consider you want to raise the number x to the power y
If both are integers:
for(int i=0 ; i<y ; i++)
answer = answer * x;
Problems are only when y is a decimal!
So we first change y to the form of y = n + 1/d
How to do that:
n = floor of y
d = 1 / (y - n) << integer
Now x^y = x^n * x^1/d
x to the power n is simple using the usual method
x to the power 1/d is simply the d th root of x
Note: You can increase the precision of your function by reducing the error factor induced by makind d an integer. How! 1/d can be multiplied by powers of 10.

Android Compass orientation on unreliable (Low pass filter)

Im creating an application where i need to position a ImageView depending on the Orientation of the device.
I use the values from a MagneticField and Accelerometer Sensors to calculate the device orientation with
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerValues, magneticFieldValues)
SensorManager.getOrientation(rotationMatrix, values);
double degrees = Math.toDegrees(values[0]);
My problem is that the positioning of the ImageView is very sensitive to changes in the orientation. Making the imageview constantly jumping around the screen. (because the degrees change)
I read that this can be because my device is close to things that can affect the magneticfield readings. But this is not the only reason it seems.
I tried downloading some applications and found that the "3D compass" and "Compass" remains extremely steady in its readings (when setting the noise filter up), i would like the same behavior in my application.
I read that i can tweak the "noise" of my readings by adding a "Low pass filter", but i have no idea how to implement this (because of my lack of Math).
Im hoping someone can help me creating a more steady reading on my device, Where a little movement to the device wont affect the current orientation.
Right now i do a small
if (Math.abs(lastReadingDegrees - newReadingDegrees) > 1) { updatePosition() }
To filter abit of the noise. But its not working very well :)
Though I havn't used the compass on Android, the basic processing shown below (in JavaScript) will probably work for you.
It's based on the low pass filter on the accelerometer that's recommended by the Windows Phone team with modifications to suit a compass (the cyclic behavior every 360").
I assume the compass reading is in degrees, a float between 0-360, and the output should be similar.
You want to accomplish 2 things in the filter:
If the change is small, to prevent gitter, gradually turn to that direction.
If the change is big, to prevent lag, turn to that direction immediatly (and it can be canceled if you want the compass to move only in a smooth way).
For that we will have 2 constants:
The easing float that defines how smooth the movement will be (1 is no smoothing and 0 is never updating, my default is 0.5). We will call it SmoothFactorCompass.
The threshold in which the distance is big enough to turn immediatly (0 is jump always, 360 is never jumping, my default is 30). We will call it SmoothThresholdCompass.
We have one variable saved across the calls, a float called oldCompass and it is the result of the algorithm.
So the variable defenition is:
var SmoothFactorCompass = 0.5;
var SmoothThresholdCompass = 30.0;
var oldCompass = 0.0;
and the function recieves newCompass, and returns oldCompass as the result.
if (Math.abs(newCompass - oldCompass) < 180) {
if (Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
oldCompass = newCompass;
}
else {
oldCompass = oldCompass + SmoothFactorCompass * (newCompass - oldCompass);
}
}
else {
if (360.0 - Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
oldCompass = newCompass;
}
else {
if (oldCompass > newCompass) {
oldCompass = (oldCompass + SmoothFactorCompass * ((360 + newCompass - oldCompass) % 360) + 360) % 360;
}
else {
oldCompass = (oldCompass - SmoothFactorCompass * ((360 - newCompass + oldCompass) % 360) + 360) % 360;
}
}
}
I see that the issue was opened 5 months ago and probably isn't relevant anymore, but I'm sure other programmers might find it useful.
Oded Elyada.
This lowpass filter works for angles in radians. Use the add function for each compass reading, then call average to get the average.
public class AngleLowpassFilter {
private final int LENGTH = 10;
private float sumSin, sumCos;
private ArrayDeque<Float> queue = new ArrayDeque<Float>();
public void add(float radians){
sumSin += (float) Math.sin(radians);
sumCos += (float) Math.cos(radians);
queue.add(radians);
if(queue.size() > LENGTH){
float old = queue.poll();
sumSin -= Math.sin(old);
sumCos -= Math.cos(old);
}
}
public float average(){
int size = queue.size();
return (float) Math.atan2(sumSin / size, sumCos / size);
}
}
Use Math.toDegrees() or Math.toRadians() to convert.
Keep in mind that, for example the average of 350 and 10 is not 180. My solution:
int difference = 0;
for(int i= 1;i <numberOfAngles;i++){
difference += ( (angles[i]- angles[0] + 180 + 360 ) % 360 ) - 180;
}
averageAngle = (360 + angles[0] + ( difference / numberOfAngles ) ) % 360;
A low pass filter (LPF) blocks fast changing signals and
allows only slow changes in the signals. This means any small
sudden changes will be ignored.
The standard way to implement this in software is to take a running average
of the last N samples and report that value. Start with N as small as 3 and
keep increasing N until you find sufficient smoothed out response in your app.
Do keep in mind that the higher you make N, slower the response of the system.
See my answer to this related question: Smoothing data from a sensor
A software low pass filter is basically a modified version of that. Indeed, in that answer I even provided this link to another related question: Low pass filter software?

Categories

Resources