Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm writing a piece of software which is responsible for logging the position of certain machine parts.
Now this is the case:
There is 1 RTK fixed GPS receiver (+/- 2cm accuracy), fixed on the machine. The heading is calculated using 2 different locations
There are 2 arms (left and right arm) on the machine that can rotate independent of each other outwards or inwards
There is 1 arm (mid arm) with a fixed location on the machine
What I Already have:
A piece of software which calculates the location of the outer location of the arms (this works like a charm). This produces a shapefile as logfile in which the location of the arms are visible and this works good for every heading.
The problem is:
The algorithm is calculating the location of the arms using the delta X and delta Y distances in mm.
My assumption was that the longitude 0.00000001 is equal to 1.1 mm on the X axis (source). Boy, what was I wrong...
When the shapefile that is generated is being measured using a shapefile viewer it returnes 2,19 meter instead of the calculated 3,25. Note that this is on the latitude 52.810146939 (Northern Hemisphere).
Thus the question:
Has anybody any idea how a formula can be formed that takes a latitude or longitude as starting point and a distance in [mm] and then returnes the corrected latitude or longitude? Or how I can calcuate the relative delta coordinates values to sum them with the Original coordinates?
I've got a snippet of the code:
Armlocations->leftarm.locationX = ownLocation.locationX + MM_TO_COOR(deltaX);
Armlocations->leftarm.locationY = ownLocation.locationY + MM_TO_COOR(deltaY);
deltaX and deltaY are the distances in mm that should be added to the coordinate. The macro MM_TO_COOR is this:
#define COOR_TO_MM(x) ((x) * 110000000)
#define MM_TO_COOR(x) ((x) / 110000000)
The question is not about programming -> I got that going for me, but more about the math involved to this.
I am sure this is not the right place, it might be a better fit to use https://gis.stackexchange.com.
About the latitude, it is always (about) 111 km per degree, so .00000001° (1E-8°) should indeed be 1.1 mm in y direction.
The relation for the longitude indeed depends on your current latitude: here, the factor per degree is 111 km multiplied by cos(latitude). In your case, that would (on a spherical earth) make a factor of 0.60445804192912, resulting in 67.1 km per degree or .671 mm per 1E-8°. On our earch, being flattened at the poles, the value is slightly different, but should be about the same (I cannot, however, tell how big the error is.)
Are you sure that your GPS device has this high resolution of several mm?
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have designed a board that samples audio input using a 16 bit DAC at 48kHz. It stores the data as signed 16-bit integers. I have also implemented a 16 bit ADC on the board and I am able to pass audio through the board successfully.
I would like to design a low pass filter using MATLAB and implement it on this board. I understand how to create basic filters using MATLAB but I cant quite grasp how to bridge the gap between creating the filter in MATLAB and implementing this filter using C code on my board. I would like to be able to pass the signal into the board and observe the filtered signal on the output in 'real-time'.
How can this be achieved?
ok, you said that you get your coefficients from a [B,A]= butter(..) likewise filter (try getting them in Z domain AKA digital filter), those A,B coefficients correspond to a simple transfer function you know
H(z) = B(z)/A(z) = (b(1)+b(2) z^−1+⋯+b(n+1) z^−n)/(a(1)+a(2) z^−1+⋯+a(n+1) z^−n)
right?
you just need to remember that the output y = H(z)*x or in other words
y = B(z)/A(z) * x and finally A(z)*y = b(z)*x
and what was x(t) * z^-1 equals? yep x(t-1)
that means that you'll end with an ecuation similar to:
y(t)*a(1)+y(t-1)*a(2)+⋯+y(t-n)a(n+1) = x(t)*b(1)+x(t-1)*b(2)+⋯+x(t-n)b(n+1)
and what we need is the actual value of y(t) with the known values of actual x(t) and past x(t-1) etc, and also with known and stored values of past y(t-1) etc...
y(t) = 1/a(1) * (x(t)*b(1)+x(t-1)*b(2)+⋯+x(t-n)b(n+1) - y(t-1)*a(2)-⋯-y(t-n)a(n+1))
that means you need two arrays for x and y, and apply the equation with the B and A arrays you got from matlab...
sadly, this assumes you ALREADY took in consideration the sampling time in the butter() (hence Wn should be normalized) and make sure you take your samples at that exact sampling time (and ideally calculate your output at the exact time too)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I am trying to classify the events above as 1 or 0. 1 would be the lower values and 0 would be the higher values. Usually the data is does not look as clean as this. Currently the approach I am taking is to have two different thresholds so that in order to go from 0 to 1 it has to go past the 1 to 0 threshold and it has to be above for 20 sensor values. This threshold is set to the highest value I receive minus ten percent of that value. I dont think a machine learning approach will work because I have too few features to work with and also the implementation has to take up minimal code space. I am hoping someone may be able to point me in the direction of a known algorithm that would apply well to this sort of problem, googling it and checking my other sources isnt producing great results. The current implementation is very effective and the hardware inst going to change.
Currently the approach I am taking is to have two different thresholds so that in order to go from 0 to 1 it has to go past the 1 to 0 threshold and it has to be above for 20 sensor values
Calculate the area on your graph of those 20 sensor values. If the area is greater than a threshold (perhaps half the peak value) assign it as 1, else assign it as 0.
Since your measurements are one unit wide (pixels, or sensor readings) the area ends up being the sum of the 20 sensor values.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
Update: this has been reported to Microsoft.
In a simple (SQL Server 2012) table with a geography column (name geopoint) populated with a few simple rows points similar to this. POINT (-0.120875610750927 54.1165118880234) etc. executing
select [geopoint].[STAsText](),
[geopoint].Lat lat,
[geopoint].Long long
from mytable
produces this
Untitled1 lat long
POINT (-0.120875610750927 54.1165118880234) 54.1165118880234 -0.120875610750927
which looks like a bug, but it is too basic and should have been caught before release. So am I doing something wrong?
Added info
IT professionals should look for the details of Microsoft's implementation of SQL server on MSDN. As there can be differences in implementation. As per this case. As a proof of this I just checked PostGist's implementation of ST_AsText for a geographic column. This works fine! and result is as one would expect. Therefore the bug is in implementation of SQL. The correct result for the above example should be
POINT (54.1165118880234 -0.120875610750927 ) 54.1165118880234 -0.120875610750927
Dare I say there is a high likelihood that there are other bugs associated with functions working geographic columns. As basic functionality in this area has not been fully tested.
This is working as intended.
According to your question, you stored the data in this pattern:
POINT (-0.120875610750927 54.1165118880234)
then you claimed that the lat/long is reversed according to the MSDN documentation of
Point(Lat, Long, SRID).
You may realize that the syntax you're using is not the same as the one you claim:
POINT(aValue anotherValue) vs Point(Lat, Long, SRID)
Now, the question is, what does MS SQL do to the data?
Turns out, MS SQL interprets the data as Open Geospatial Consortium (OGC) Well-Known Text (WKT), and thus use STPointFromText function since the format is the most suitable for 2-D point:
POINT(x y)
Now, the follow-up question, does it mean POINT(Lat Long)?
From the sample code
SET #g = geography::STPointFromText('POINT(-122.34900 47.65100)', 4326);
it should be clear that the first parameter is not latitude, but longitude (the range of latitude range is from -90 to 90 only), so now we guess that the format is POINT(Long Lat) then. But why?
As explained in this article,
As you can see [...], the longitude is specified first before the latitude. The reason is because in the Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation, the format is (x, y). Geographic coordinates are usually specified by Lat/Long but between these two, the X is the Longitude while the Y is the Latitude.
You may be wondering why the X-coordinate is the Longitude while the Y-coordinate is the Latitude. Think of the equator of the earth as the x-axis while the prime meridian is the Y-axis. Longitude is defined as the distance from the prime meridian along the x-axis (or the equator). Similarly, latitude is defined as the distance from the equator along the Y-axis.
This is a bug. Returned value for STAsText for a geography column swaps the Lat and Long values. Definitely a bug which people should be aware of.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have 8 data points that form the peak of a partial sine wave. I am trying to fit these to get an equation so I discover the point of the true maximum position (which most likely lies between the data points). The coding will be in C. Does anyone have any info on algorithms or ideally code samples?
Since the data points are all near a maximum, the wave y = A*sin(B*x + C) + D can be approximated as a parabola much like the first 2 terms of cos(x) = (1.0 - x*x/2! + ...).
So find the best fit parabola for the 8 data points and calculate the maximum.
C- Peak detection via quadratic fit
Lots of google examples exist. Example
Provided your sample-values form a "hump", i.e. increasing followed by decreasing samples, you could try viewing the samplevalues as "weights" and compute the "center of gravity":
float cog = 0f;
for (i=0; i<num_samples; ii+) {
cog += i * samples[i];
}
cog /= num_samples;
I've used that in similar cases in the past.
NOTE: This scheme only works if the set of samples used contain a single peak, which the question phrasing certainly made me think was the case. Finding locations of interest can easily be done by monitoring, if sample values are increasing or decreasing, selecting an "interesting" range of samples and computing the peak location as described.
Also note, that if the actual goal is to determine the sine wave phase or frequency of an input signal, it would be a lot better to correlate the signal against reference set of sine-waves (in other words, do a Fourier transform).
I have wasted 2 days (and nights) on this specific issue and completely failed in tilt compensating my magnetometer output.
I tried about everything I could read on Google and in open source examples, nothing guided me to a proper tilt compensation for both (roll and pitch). .
The Setup:
I use calibrated values but not unity values.
I have a fused gravity vector which is working properly and exact.
The sensor is a 9dof BMX055 (http://www.mouser.com/ds/2/621/BST-BMX055-DS000-01-274824.pdf)
The magnetometer min/max are +- 512 on each axis (with small differences but all axes are zero'd out).
The hardware is Sam3X8e (Cortex M3), all written in C.
Floating point and trigonometry can be done quite fast, so that's no problem.
The BMX055 chip is aligned so that the pins 20,19,18 point to the front.
Datasheet page 159-161 show the orientation.
Pitch rises when I rise the front.
Roll rises when I rise the left side.
Example values:
Pointing at a direction my algorithm calls 305deg when leveled horizontal
Pitch: 0 , Roll 0 : MAG cal: x 132 y 93 z -364
Pitch: +24, Roll 0 : MAG cal: x -109 y 93 z -397
Pitch: +46, Roll 0 : MAG cal: x -303 y 89 z -351
Pitch: 0 , Roll -44 : MAG cal: x 151 y 352 z -235
Pitch: 0 , Roll +36 : MAG cal: x 130 y -140 z -328
Pitch: 78 , Roll -2 : MAG cal: x -503 y 93 z -199
Pitch: 7 , Roll -53 : MAG cal: x 135 y 424 z -180
The alignment should always have been around 305 degree (as good as I could do it), maybe +- 5 degree.
The formula: (same one used about everywhere)
uint16_t compass_tilt_compensation(float roll_radians, float pitch_radians,float mag_y, float mag_x, float mag_z)
{
float tilt_compensated_heading;
float MAG_X;
float MAG_Y;
float cos_roll;
float sin_roll;
float cos_pitch;
float sin_pitch;
int16_t heading;
//pitch_radians =roll_radians;
//roll_radians *= -1;
//mag_x *= -1;
//roll_radians=0.0f;
//pitch_radians=0;v
//pitch_radians *=-1;
cos_roll = cos(roll_radians);
sin_roll = sin(roll_radians);
cos_pitch = cos(pitch_radians);
sin_pitch = sin(pitch_radians);
#if 0
MAG_X = mag_x*cos_pitch+mag_y*sin_roll*sin_pitch+mag_z*cos_roll*sin_pitch;
MAG_Y = mag_y*cos_roll-mag_z*sin_roll;
tilt_compensated_heading = atan2f(-MAG_Y,MAG_X);
#else
MAG_X = mag_x * cos_pitch + mag_z * sin_pitch;
MAG_Y = mag_x * sin_roll * sin_pitch + mag_y * cos_roll - mag_z * sin_roll * cos_pitch;
tilt_compensated_heading = atan2f(-MAG_Y,MAG_X);
//tilt_compensated_heading = atan2f(-mag_y,mag_x); // works fine when leveled
#endif
//convert to degree from 0-3599
heading = tilt_compensated_heading * RAD_TO_DEG * 10;
if ( heading < 0 )
{
heading += 3600;
}
return heading;
}
I tried various combinations, I tried to only fix one axis and leave one always at 0, exchanging X/Y pitch/roll, *-1 on any of the inputs.
The results are always completely wrong.
Sometimes (depending on where I try to invert or not invert a value by trial/error) the values seem to be off nearly linear. Sometimes one axis is compensated in positive areas.
However rolling and pitching always causes 'random' jumps and changes of the heading.
Math has never been my favourite, now I regret it.
My personal guess is that the formula is right in principe, the mag is working in principe (after all I get proper degrees when leveled) but I am somehow feeding something wrong.
(Like Y and X need to be exchanged, z*-1, pitch needs to be *-1)
Could someone who is good in this subject maybe take a look and guide me how to get a proper heading ?
Would be great to have a few hours sleep this night without having to dream about a dysfunctional algorithm again :)
Update:
The tilt compensation here works for negative roll when pointing at the 305deg heading.
It is also used here: http://www.emcu.it/MEMS/Compass/MEMS_Compass_A_RTM1v3.pdf
3 days of work, finally I found the issues I had and tilt compensation is working !
I read quite a few people had such issues in various forums, so here is what I did:
I explain what I did and why I did, step by step. Maybe someone with a similar issue will find a solution that way.
Playing around with the values can help (maybe just pitch or roll has to be inverted, X or Y has to be exchanged).
However, there are quite a lot of values and the amount of combinations is too high if your problem is more than a tiny one.
The formula posted works fine (the one which is in the active #if branch.
If you have a magnetometer and the atan2(-y,x) gives you a proper heading when leveled flat, then this formula will work for you too.
What I did was to completely go through all my sensors and vectors beginning from the I2C binary logic (and the datasheet).
Important in this secial case (BMX055), the Datasheet orientation page is WRONG!
There are multiple bugs regarding orientation of axes (x,y) as well as when a rotation is positive or negative. Sometimes right hand rule applies, sometimes not and the drawings are misleading (wrong). Bosch did a bad job documenting this chip (and the previous one).
They do not seem to want people to understand it properly, they write about a fusion API several times with optimized fixed point arithmetiks and advanced calibration but it's not available for the public.
What I needed to do was to make a proper body reference system.
Decide yourself where X is and then make it so all your sensors properly change the X axis when pitched/rolled into the same direction (positive/negative).
Do this for pitch,roll and gravity/magnetic field.
Once all of them play together nicely I started all over again.
The heading formula was still dysfunctional but now I trusted the vextors the first time.
I added a vector rotation matrix function and rotated the magnetic vector back using roll and pitch and yaw=0.
Surprise: the magnetic vector was tilt compensated.
Now I knew it CAN be done :)
I went back to the original formula, replaced X with Y (because I had exchanged them to match the body reference system (X and Y of gyro/mag).
Now tilt compensation worked for pitch but not for roll.
So I inverted roll_radians and suddenly it's perfectly tilt compensated.
I have two solutions now. One is a rotation matrix solution and the other one the standard solution everyone is using. I will see if one of them performs better and maybe give a last update here if the results are worth it.
First, verify that it is indeed a software problem. Your equations seem to be correct. Just in case, generate a table populated with test data to pass to your procedure and compare the output of your function with the expected values if the code was correct.
You are using a magnetometer and these are very sensitive devices. The first thing I would check is whether there are any large metal structures near the sensor. If you have access to an oscilloscope, probe the chip's power rails and see if power going into it is stable. Adding a 1uF decoupling cap could solve power issues. I would also suggest getting a graph while having a sampling frequency larger than 100Hz and see if the jumps are periodic. If the signal is periodic with a 50Hz frequency, assuming the sensor is not being moved, that would indicate interference from your mains supply. Performing FFT analysis over the data can't hurt. We had similar problems caused by power cables running underneath our lab floor. If the sensor keeps jumping around randomly, the chip is probably dead. Did you use proper ESD protection while handling it?
Hope this helps.