Average-Function of Sensor-Data in Android - android

I'm trying to build the weighted-average from the sensor-data I get by the SensorManager.
My problem is, that bearing, pitch and roll have a maximum value and when I'm exactly at this point, the values swap from 0 to 359 or backwards.
My average is at the moment simply an addition of all values and one division by the number of values.
Let's say I get the values: 1, 359, 350, 10
In this case, I want to have an average of 0. How do I have to change my equation to get this functionality?
Do I have to check for the "nearest" distance to 0/360 and using this value instead of the real value?
This would also make some troubles if I have values around 180:
160, 200 -> the average has to be 180, but with my nearest-distance idea, it would be 160, because 200 + 160 = 360.
How can I solve this?
Edit: This are the values I get from the SensorManager.
0 <= azimuth<360
180<=pitch<=180
90<=roll<=90
Edit2: Sorry, I forgot to mention that I'm using a weighted average:
double sum = 0;
for int i = 0; i < max; i++
sum += value[i] * (i / (triangular_number(max))
return sum

To calculate average of angle use the following
public static final float averageAngle(float[] terms, int totalTerm)
{
float sumSin = 0;
float sumCos = 0;
for (int i = 0; i < totalTerm; i++)
{
sumSin += Math.sin(terms[i]);
sumCos += Math.cos(terms[i]);
}
return (float) Math.atan2(sumSin / totalTerm, sumCos / totalTerm);
}

I found a blog post about this.
To summarize it shortly: You have to calculate the average of the sines of all your aizmuth values and the average of the cosines of the aizmuth values and then put these average values in the atan2 function, then if necessary make the result positive by adding 2 * PI. Don't forget to convert degrees values to radians and vice versa.

Related

Incorrect frequency on manually drawn graph

I am currently writting a a spectrum analyzer for android for university and part of this involves plotting the FFT of sound. However, I am having an issue with plotting the frequencies. The freq values start off correct, but as i move to higher frequencies the error is becoming greater and greater (at 3000Hz, the graph will show ~3750). I feel as though there is an error in the way I am calculating the x-axis or freq values. This is a manually drawn graph for speed purposes.
If more info/code is needed just let me know, but my guess is that it is something simple that I have overlooked. Thanks
xVal is the frequency value. and the scale value is to scale it according to the real graph dimensions.
int length = currentWaveDataDouble.length;
int pow2 = Integer.highestOneBit(length) << 1;
int sampleRate = 44100;
...
//actual plot part
for(int i =0; i<p2.length; i++) {
float xVal = (float)(i * scaleX.ScaleValue(((double) sampleRate / (pow2 >> 1))));
if (xVal < maxFreqPlus1) {
xVal += axisWidth + yAxisMargin;
float yVal = (float) scaleY.ScaleValue(p2[i]);
yVal += axisWidth + xAxisMargin;
canvas.drawPoint(xVal,yVal, marker);
if(yVal > yMax)
{
yMax = yVal;
xMax = xVal;
}
}
}
Freq generator set to 4000 Hz
Freq generator set to 1000 Hz (value is 1250Hz)
Found the issue. it was in the scaler.
ValueScaler scaleY = new ValueScaler(0,maxAmpPlus1 - yAxisMargin,0,baseY);
ValueScaler scaleX = new ValueScaler(0,maxFreqPlus1 - xAxisMargin,0,baseX);
i wasn't taking into account the x and y margin when scaling the numbers.

Get amplitude from MediaPlayer using Visualizer

i've been reading another posts about calculate the amplitude in real time from a Mediaplayer, but i have no clear how to get a value useful for me. What i need is a linear amplitude value normalize between 0-100, but as i've watched in another posts they are performing a db calculation which has not much sense, cause they are not normalized to max 0dB value (from How to calculate the audio amplitude in real time (android)):
double amplitude = 0;
for (int i = 0; i < audioData.length/2; i++) {
double y = (audioData[i*2] | audioData[i*2+1] << 8) / 32768.0
// depending on your endianness:
// double y = (audioData[i*2]<<8 | audioData[i*2+1]) / 32768.0
amplitude += Math.abs(y);
}
amplitude = amplitude / audioData.length / 2;
I've watched that for calculate de dB, i should do as below (from How to compute decibel (dB) of Amplitude from Media Player?
)
double sum=0;
for (int i = 0; i < audioData.length/2; i++) {
double y = (audioData[i*2] | audioData[i*2+1] << 8) / 32768.0;
sum += y * y;
}
double rms = Math.sqrt(sum / audioData.length/2);
dbAmp = 20.0*Math.log10(rms);
I've tried for that solution but the real time values are near to 0 but sometimes are over than 0, i mean, something between -Inifinit (no sound) to 1.2 (if i avoid 20.0* multiply) or anything else from than order. Anyway, i'd like to obtain a normalized value [0-100], not a dB value.

I cannot draw negative y-values and positive y-values in one barchart using MPAndroidChart

Please help.. as I wrote in the issue title, I cannot draw negative y-values and positive y-values in one barchart. I use your code and only change a few line of it.
the original source is: https://raw.githubusercontent.com/PhilJay/MPAndroidChart/master/MPChartExample/src/com/xxmassdeveloper/mpchartexample/BarChartActivity.java.
the edited source is: https://db.tt/FWGvAZOZ
I only edited line 266-273.
The snippet (original):
for (int i = 0; i < count; i++) {
float mult = (range + 1);
float val = (float) (Math.random() * mult);
yVals1.add(new BarEntry(val, i));
}
The snippet (edited):
for (int i = 0; i < count; i++) {
float val = (float) ((double)1.0 * (float)i) -5;
yVals1.add(new BarEntry(val, i));
}
I already open an issue in the author github (issue #183), and I post here in stackoverflow, hoping here I can have faster response.
Thanks, folks
Update for v3.0.0+:
startAtZero(...) is deprecated, you can make use of:
axis.setAxisMinimum(0f); // start axis zero (min value 0f)
axis.setAxisMaximum(100f); // set axis max value to 100f
To modify or "lock" the range you want your axis to display. Additionally, have a look at the documentation:
AxisBase
YAxis
XAxis
// For setting negative axis for y
BarChart chart = (BarChart) findViewById(R.id.chart);
chart.getAxisLeft().setStartAtZero(false);
chart.getAxisRight().setStartAtZero(false);

android Dividing circle into N equal parts and know the coordinates of each dividing point

I have requirement that a circle should be divided into N equal parts based on number(2,3...n. But I want the coordinates of dividing points.
I have a circle whose centre(x,y) and radius(150) are known.
Question:
Is there any formula which gives me the coordinates of dividing points as shown in figure. Can anyone please tell me the formula. I want to implement it in Java.
Circle image for refrence:
I have already accepted answer... the formula works perfectly.
Here is the solution coded in Java. It will help other developers.
private int x[]; // Class variable
private int y[]; // Class variable
private void getPoints(int x0,int y0,int r,int noOfDividingPoints)
{
double angle = 0;
x = new int[noOfDividingPoints];
y = new int[noOfDividingPoints];
for(int i = 0 ; i < noOfDividingPoints ;i++)
{
angle = i * (360/noOfDividingPoints);
x[i] = (int) (x0 + r * Math.cos(Math.toRadians(angle)));
y[i] = (int) (y0 + r * Math.sin(Math.toRadians(angle)));
}
for(int i = 0 ; i < noOfDividingPoints ;i++)
{
Log.v("x",""+i+": "+x[i]);
Log.v("y",""+i+": "+y[i]);
}
}
Where x0 and y0 are co ordinates of circle's centre.and r is radius.
In my case:
Input x0 = 0 , y0 = 0 and r = 150 , noOfDividingPoints = 5
output
point1: (150,0)
point2: (46,142)
point3: (-121,88)
point4: (-121,-88)
point5: (46,-142)
You need to convert between polar and Cartesian coordinates. The angle you need is the angle between the (imaginary) vertical line that splits the circle in half and the line that connects the center with the circle's boundary. With this formula you can calculate the X and Y offsets from the center.
In your example image the first angle is 0, and the second one is 360/n. Each next is i*(360/n) where i is the index of the current line you need to draw. Applying this will give you the X and Y offsets in a clockwise order (and you can just add them to the X and Y coordinates of the center to find the coordinates of each point)
EDIT: some kind of pseudo-code:
//x0, y0 - center's coordinates
for(i = 1 to n)
{
angle = i * (360/n);
point.x = x0 + r * cos(angle);
point.y = y0 + r * sin(angle);
}

Get quaternion from Android gyroscope?

The official development documentation suggests the following way of obtaining the quaternion from the 3D rotation rate vector (wx, wy, wz).
// Create a constant to convert nanoseconds to seconds.
private static final float NS2S = 1.0f / 1000000000.0f;
private final float[] deltaRotationVector = new float[4]();
private float timestamp;
public void onSensorChanged(SensorEvent event) {
// This timestep's delta rotation to be multiplied by the current rotation
// after computing it from the gyro sample data.
if (timestamp != 0) {
final float dT = (event.timestamp - timestamp) * NS2S;
// Axis of the rotation sample, not normalized yet.
float axisX = event.values[0];
float axisY = event.values[1];
float axisZ = event.values[2];
// Calculate the angular speed of the sample
float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
// Normalize the rotation vector if it's big enough to get the axis
// (that is, EPSILON should represent your maximum allowable margin of error)
if (omegaMagnitude > EPSILON) {
axisX /= omegaMagnitude;
axisY /= omegaMagnitude;
axisZ /= omegaMagnitude;
}
// Integrate around this axis with the angular speed by the timestep
// in order to get a delta rotation from this sample over the timestep
// We will convert this axis-angle representation of the delta rotation
// into a quaternion before turning it into the rotation matrix.
float thetaOverTwo = omegaMagnitude * dT / 2.0f;
float sinThetaOverTwo = sin(thetaOverTwo);
float cosThetaOverTwo = cos(thetaOverTwo);
deltaRotationVector[0] = sinThetaOverTwo * axisX;
deltaRotationVector[1] = sinThetaOverTwo * axisY;
deltaRotationVector[2] = sinThetaOverTwo * axisZ;
deltaRotationVector[3] = cosThetaOverTwo;
}
timestamp = event.timestamp;
float[] deltaRotationMatrix = new float[9];
SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
// User code should concatenate the delta rotation we computed with the current rotation
// in order to get the updated rotation.
// rotationCurrent = rotationCurrent * deltaRotationMatrix;
}
}
My question is:
It is quite different from the acceleration case, where computing the resultant acceleration using the accelerations ALONG the 3 axes makes sense.
I am really confused why the resultant rotation rate can also be computed with the sub-rotation rates AROUND the 3 axes. It does not make sense to me.
Why would this method - finding the composite rotation rate magnitude - even work?
Since your title does not really match your questions, I'm trying to answer as much as I can.
Gyroscopes don't give an absolute orientation (as the ROTATION_VECTOR) but only rotational velocities around those axis they are built to 'rotate' around. This is due to the design and construction of a gyroscope. Imagine the construction below. The golden thing is rotating and due to the laws of physics it does not want to change its rotation. Now you can rotate the frame and measure these rotations.
Now if you want to obtain something as the 'current rotational state' from the Gyroscope, you will have to start with an initial rotation, call it q0 and constantly add those tiny little rotational differences that the gyroscope is measuring around the axis to it: q1 = q0 + gyro0, q2 = q1 + gyro1, ...
In other words: The Gyroscope gives you the difference it has rotated around the three constructed axis, so you are not composing absolute values but small deltas.
Now this is very general and leaves a couple of questions unanswered:
Where do I get an initial position from? Answer: Have a look at the Rotation Vector Sensor - you can use the Quaternion obtained from there as an initialisation
How to 'sum' q and gyro?
Depending on the current representation of a rotation: If you use a rotation matrix, a simple matrix multiplication should do the job, as suggested in the comments (note that this matrix-multiplication implementation is not efficient!):
/**
* Performs naiv n^3 matrix multiplication and returns C = A * B
*
* #param A Matrix in the array form (e.g. 3x3 => 9 values)
* #param B Matrix in the array form (e.g. 3x3 => 9 values)
* #return A * B
*/
public float[] naivMatrixMultiply(float[] B, float[] A) {
int mA, nA, mB, nB;
mA = nA = (int) Math.sqrt(A.length);
mB = nB = (int) Math.sqrt(B.length);
if (nA != mB)
throw new RuntimeException("Illegal matrix dimensions.");
float[] C = new float[mA * nB];
for (int i = 0; i < mA; i++)
for (int j = 0; j < nB; j++)
for (int k = 0; k < nA; k++)
C[i + nA * j] += (A[i + nA * k] * B[k + nB * j]);
return C;
}
To use this method, imagine that mRotationMatrix holds the current state, these two lines do the job:
SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
mRotationMatrix = naivMatrixMultiply(mRotationMatrix, deltaRotationMatrix);
// Apply rotation matrix in OpenGL
gl.glMultMatrixf(mRotationMatrix, 0);
If you chose to use Quaternions, imagine again that mQuaternion contains the current state:
// Perform Quaternion multiplication
mQuaternion.multiplyByQuat(deltaRotationVector);
// Apply Quaternion in OpenGL
gl.glRotatef((float) (2.0f * Math.acos(mQuaternion.getW()) * 180.0f / Math.PI),mQuaternion.getX(),mQuaternion.getY(), mQuaternion.getZ());
Quaternion multiplication is described here - equation (23). Make sure, you apply the multiplication correctly, since it is not commutative!
If you want to simply know rotation of your device (I assume this is what you ultimately want) I strongly recommend the ROTATION_VECTOR-Sensor. On the other hand Gyroscopes are quite precise for measuring rotational velocity and have a very good dynamic response, but suffer from drift and don't give you an absolute orientation (to magnetic north or according to gravity).
UPDATE: If you want to see a full example, you can download the source-code for a simple demo-app from https://bitbucket.org/apacha/sensor-fusion-demo.
Makes sense to me. Acceleration sensors typically work by having some measurable quantity change when force is applied to the axis being measured. E.g. if gravity is pulling down on the sensor measuring that axis, it conducts electricity better. So now you can tell how hard gravity, or acceleration in some direction, is pulling. Easy.
Meanwhile gyros are things that spin (OK, or bounce back and forth in a straight line like a tweaked diving board). The gyro is spinning, now you spin, the gyro is going to look like it is spinning faster or slower depending on the direction you spun. Or if you try to move it, it will resist and try to keep going the way it is going. So you just get a rotation change out of measuring it. Then you have to figure out the force from the change by integrating all the changes over the amount of time.
Typically none of these things are one sensor either. They are often 3 different sensors all arranged perpendicular to each other, and measuring a different axis. Sometimes all the sensors are on the same chip, but they are still different things on the chip measured separately.

Categories

Resources