CGPS Data Inaccuracies


#1

I’m back with yet another question. Everything is working great, and I ran the QueryApp and got a return sms with valid GPS coordinates. The problem is the coordinates it gave me are wrong. The difference is as follows:

-0.0011 degrees N,
-0.1592 degrees W

The GPS coordinates returned show a point about 18 miles west and about 1 mile south of my actual position. What could be the reasons for this? Anyone else experience this?

Thanks,
Scott


#2

Hi Scott,

Are you using GCC compiler to compile your QueryApp application?
If possible, try to use ARM ADS compiler and check out the results.

There was an issue with the GCC compiler wherein some offset is observed in the provided co-ordinates. If you are using GCC, can you tell me the Open AT version that you are using?

Best Regards,
Open AT Fan.


#3

-OpenAT_Fan:

Thanks for the reply. I am using the latest Open AT Version for the Q2686 (4.11 - I am not currently in the office to double check) and I am using the GCC compiled app. I think the example app came with both compiled version if I am not mistaken. If so, I will have to try the ADS compiled version tommorrow and see if in fact that is what is causing it. If it is the problem, and I do not have the ARM C/C++ compiler (Side Note: Besides RealView, any recommendations?) , what would could be a possible solution?

Thanks,
Scott


#4

Hi Scott,

As you know, that in GCC compiler, you cannot use the %f format specifier. The implementation of wm_sprintf () function for %f format specifier is done inside the file gccspecific.c.

When you use GCC compiler, the code present in this file comes into play. In this code, there is a function called “power”. The intend of this function is to compute the value of 10 raised to the power the number specified in the argument.
The return value of this function is u16 which sometimes leads to an overflow, if the value to be returned is greater than 65535.
This leads to error after the decimal point in the returned NMEA frames which causes the offset.

To solve the problem, please update the power function (present in gccspecific.c) as follows:

static u32 power(u32 base, u16 power)
{
u32 mul = base;
while (power>1)
{
base = base * mul;
power --;
}
return base;
}

(Note that I have changed the return type and datatype of mul).
Also check the place from where this function is called and update the variable (if any) which is receiving the return value from this function.

Recompile the application and then download and check.
Hope this should solve your problem.

Best Regards,
Open AT Fan.


#5

OpenAT_Fan:

You are certainly a wealth of knowledge in this forum! I appreciate your response. I am going to try and test that out this evening. I’ll let you know how the results turn out.

Again thanks for the lesson and helpful advice (and code snipet),
Scott


#6

OpenAT_Fan:

I tried the ADS compiled version of the QuerryApp and it had the same results. I noticed that the NMEA frames returned on the UART that it is giving the correct location, but for some reason on both compiled apps it is calculating incorectly when returning the formatted SMS. I am trying the code you gave me, but it doesn’t seem specific to the GCC compiler since the ADS compiled version is returning exactly the same thing as the GCC compiled version.

Thanks


#7

Hi Scott,

Are you trying to receive the GPS information in degress only (without minutes)? This is because; the CGPS samples return the value in the SMS that is degrees.minutes.
The returned SMS is created by taking information from the GPS frames only (which are sent on UART) and extracting the degree and minute information from them. So, if the information provided on UART is correct, the information in the SMS should also be the same.

However, if you still feel that there is some discrepancy, then I have to check out the code to find out if there is some miscalculation in the degree.minute information returned by the SMS.

Please let me know your inputs on the same.

Best Regards,
Open AT Fan.


#8

OpenAT_Fan:

The correct GPS information is being returned on the $GPGGA NMEA frame. The function that updates the structure the sms uses is called before the frame is written to the UART. So the GPS information is correct, but somewhere between this point and the sms being sent, it gets converted wrong. I think it is in the following function:

static void UpdatePvtHelper(pvtDataCacheStruct *pvtData,
                           const erPvtStruct *pvt,
                           const erTimeStruct *erTime) {

    const s32 *llaPos;

    UpdateTimeHelper(pvtData, erTime);
    if (erPvtIsFix((erPvtStruct *) pvt)) {
        //pvtLlaFilt is the basic filtered position
        //llaPos = pvt->pvtLlaFilt;
        // It incorporates pinning at the user's request by
        // calling erSetPinningStrength(int) in the API.
        llaPos = pvt->pvtLlaFilt;
        pvtData->statCh = 'A';
        pvtData->statInt = 1;
    }
    else {
        llaPos = pvt->pvtLla;
        pvtData->statCh = 'V';
        pvtData->statInt = 0;
    }

    pvtData->lldeg[0] = ER_I2F(llaPos[0],-28)*(180.0/3.141592654);
    pvtData->lldeg[1] = ER_I2F(llaPos[1],-28)*(180.0/3.141592654);
    pvtData->lldir[0] = (pvtData->lldeg[0] >= 0) ? 'N' : 'S';
    pvtData->lldir[1] = (pvtData->lldeg[1] >= 0) ? 'E' : 'W';
    pvtData->llmin[0] = pvtData->lldeg[0] - ((s32)(pvtData->lldeg[0]));
    pvtData->llmin[1] = pvtData->lldeg[1] - ((s32)(pvtData->lldeg[1]));
    pvtData->lldeg[0] = (s32)(((s32)pvtData->lldeg[0])*100) + ((pvtData->llmin[0])*60);
    pvtData->lldeg[1] = (s32)(((s32)pvtData->lldeg[1])*100) + ((pvtData->llmin[1])*60);

    pvtData->knots = (double)((ER_I2F(pvt->pvtSpeed,-12))*(3600.0/1852.0));
    pvtData->speedKmh = (double)((ER_I2F(pvt->pvtSpeed,-12))*(3.6));
    pvtData->dir = pvt->pvtHeadingFilt;
    pvtData->alt = ER_I2F(llaPos[2], -6);
}

I am on my out for the day, but I will confim this tommorrow. Can you see where the problem is?

Thanks,
Scott


#9

Hi Scott,

The GPS information for the SMS is filled in the function “AppGetNmeaRMC” and is extracted from the NMEA RMC frame. This is done using the following logic:

if (pvtData->statCh =='A')
	{
		LocValid = TRUE;
		GpsInformation.position.latitude = (fabs(pvtData->lldeg[0]))/100;
		GpsInformation.position.latitude = (u32)GpsInformation.position.latitude + pvtData->llmin[0];
		
		
		GpsInformation.position.latitude_direction = pvtData->lldir[0];
		

		GpsInformation.position.longitude = (fabs(pvtData->lldeg[1]))/100;
		GpsInformation.position.longitude = (u32)GpsInformation.position.longitude + pvtData->llmin[1];
		

		
		GpsInformation.position.longitude_direction = pvtData->lldir[1];
		

		GpsInformation.position.altitiude = pvtData->alt;
		

		GpsInformation.velocity.kmperhour = pvtData->speedKmh;
		

		if (GpsInformation.velocity.kmperhour){
			GpsInformation.velocity.direction = pvtData->dir;
		
		}
		else {
			GpsInformation.velocity.direction = 0;
		}

	}
	else {
		LocValid = FALSE;
		TRACE((1,"Location not valid"));
	}

The structure GpsInformation (presented in the code snippet above) is then accessed in the function “FillPVTData” which creates and SMS using the “GpsInformation” structure. Hence, if the RMC frame is correct, the information in the SMS should also be correct.
Can you please let me know the discrepancy that you have observed in the returned values?

Best Regards,
Open AT Fan.


#10

OpenAT_Fan,

Sorry for the delay. I had to focus my attention on a few other issues. But, I am back and took a look at this yesterday. I am still a bit confused on this issue. You are right, the GPS info for the SMS is filled in the function “AppGetNmeaRMS”. I have looked at it a bit closer and realized one thing:

After the “if” statement you coded in your previous reply, is where it builds the string that is sent to the debug UART. The following:

len = wm_sprintf(dst,"$GPRMC,%02u%02u%02u.%03d,%c,%09.4f,%c,%010.4f,%c,%.2f,%.2f,%02u%02u%02u,,",
                  pvtData->hms[2],pvtData->hms[1],pvtData->hms[0],
                  erTime->gpsMsec,pvtData->statCh,
                  fabs(pvtData->lldeg[0]),pvtData->lldir[0],
                  fabs(pvtData->lldeg[1]),pvtData->lldir[1],
                  pvtData->knots,pvtData->dir,
                  pvtData->dmy[0],pvtData->dmy[1],pvtData->dmy[2]%100);

outputs the correct coordinates. So the following:

fabs(pvtData->lldeg[0])
fabs(pvtData-lldeg[1]

is fine. The problem is when the program translates the minute decimal into degree decimal that it messes up:

GpsInformation.position.latitude = (fabs(pvtData->lldeg[0]))/100; 
      GpsInformation.position.latitude = (u32)GpsInformation.position.latitude + pvtData->llmin[0]; 
       
       
      GpsInformation.position.latitude_direction = pvtData->lldir[0]; 
       

      GpsInformation.position.longitude = (fabs(pvtData->lldeg[1]))/100; 
      GpsInformation.position.longitude = (u32)GpsInformation.position.longitude + pvtData->llmin[1]; 
       

       
      GpsInformation.position.longitude_direction = pvtData->lldir[1];

Well, that is not completely true. For some reason, my latitude is correct but my longitude is way off the mark. I am clueless as to what might cause this as they are both calculated the same. I have ran the ADS and GCC compiled versions and get exactly the same result. Have you ran this program and gotten favorable results?

Thanks,
Scott


#11

Here is an example of how it is calculating wrong.

fabs(pvtData->lldeg[1]) is returning 09704.7725, which is correct.
GpsInformation.position.longitude is returning 96.920

It should return 97.0795416 (without that much precision).

Thanks,
Scott


#12

Hi Scott,

I do not have access to the CGPS daughter board as of now.
Can you do a small check in the application?

You can try to put traces for the values contained in pvtData->llmin[1] and pvtData->lldeg[1].

I think that the problem might be related to some invalid value contained in the pvtData->llmin[1] (which is used to create the longitude value) and when this value is added up in the GpsInformation.position.longitude, the result becomes an erroneous value.
This might occur, if there is some problem in the CGPS library where it is not properly updating the value in the pvtData->llmin[1].

If possible, you can try to trace out the values after each step (i.e. after the fabs function is called , after the GpsInformation.position.longitude is calculated) and so on.

Once, I get access to the CGPS daughter board, I will try to executed the same on my side also and find the cause of the problem.

Hope this helps.

Best Regards,
Open AT Fan.


#13

Thanks for the reply OpenAt_Fan.

I put a few traces inside the AppGetNmeaRMC function and got some crazy numbers. I can only assume that I put the trace in wrong. This is what I put in:

if (pvtData->statCh =='A')
	{
		LocValid = TRUE;
		TRACE(( 1 ,"lldeg[0] = %09.4f  llmin[0] = %.9f",fabs(pvtData->lldeg[0]),pvtData->llmin[0]  ));
	    TRACE(( 1 ,"lldeg[1] = %010.4f  llmin[1] = %.9f",fabs(pvtData->lldeg[1]),pvtData->llmin[1] ));

		GpsInformation.position.latitude = (fabs(pvtData->lldeg[0]))/100;
		GpsInformation.position.latitude = (u32)GpsInformation.position.latitude + pvtData->llmin[0];
		GpsInformation.position.latitude_direction = pvtData->lldir[0];
		GpsInformation.position.longitude = (fabs(pvtData->lldeg[1]))/100;
		GpsInformation.position.longitude = (u32)GpsInformation.position.longitude + pvtData->llmin[1];
		GpsInformation.position.longitude_direction = pvtData->lldir[1];

The numbers I get back from that don’t make any sense at all. Neither lldeg[] nor llmin[] is returning anything logical:

Trace	CUS4	1	lldeg[0] = 1690760564074573600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000  llmin[0] = 0.000000000
Trace	CUS4	1	lldeg[1] = -2135648225281326800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000  ll ...

Please tell me my error.

Thanks,
Scott


#14

Hi Scott,

I think that you have put the traces in the application which is compiled using GCC. (In GCC, the %f format specifier does not work correctly).

If possible, can you please try to put the traces in the application compiled using ADS compiler?
Also, try to put the traces for the “GpsInformation.position.longitude” and “ptvData->llmin[1]” (i.e. put the traces after the calculation has been performed).

Hope this helps finding the cause of the problem.

Best Regards,
Open AT Fan.


#15

Thanks OpenAt_Fan.

That’s the problem with multi-tasking, you forget some of the simple things (such as %f not working with GCC).
Unfortunately, I don’t have the ability to compile using ADS, but I’ll go ahead and put the traces in where you suggested this afternoon and post my results.

Thanks,
Scott


#16

OpenAT_Fan:

Here are the the trace results for GpsInformation.position.longitude and llmin[1]:

Trace	1	GpsInformation.position.longitude = 96.920723   llmin[1] = 0.042941

$GPRMC is returning a value of 09704.7552 which should be 97.0792533.

Let me know what you think about this.

Thanks,
Scott


#17

I added a bit to the Trace. Here is a little more detailed Trace return. You can clearly see where it messes up.

Trace  1  GpsInformation.position.longitude = 97.477696   llmin[1] = 0.042941   GpsInformation.position.longitude + pvtData->llmin[1] = 96.920378

I double checked the code, and the code looks correct. The following is what I notice:$GPRMS returns 09704.7776
GpsInformation.position.longitude should be 97.047769 not 97.477
If you add 97.047769 + 0.042941 it equals 97.09071, which is closer, but still should be 97.0796
llmin[1] needs to be 0.03184 instead of 0.042941
– GpsInformation.position.latitude = (fabs(pvtData->lldeg[0]))/100; is returning incorrect value.
– llmin[1] is returning incorrect value;
– (u32)GpsInformation.position.longitude + pvtData->llmin[1] is adding incorrectly

What do you think?

Thanks,
Scott


#18

Hi Scott,

I think that the problem lies in the conversions that are performed in the code. For instance, the function fabs () is applied to the longitude information which is then divided by 100. Also, this value is then converted to u32 and then the minute information is added to it. This could lead to some error in the values after decimal.

I think that if we directly try to manipulate the value in the pvtData->lldeg[0], (without typecasting it to u32 and adding llmin[1]) then we might be able to get the correct value.

As, I don’t have a dev board with me, I am unable to test and provide you a concrete solution. However, I would recommend, that you experiment with the values that is present in pvtData->lldeg[0] and use only this variable to get the longitude values.

Also, if possible, try to use the ADS compiler as with GCC some problems are experienced in the printing of floating point numbers. Also, if we use GCC then, it can also happen that some offset is introduced by gcc_sprintf () function.

What you can do is, try to print the following code snippet:
GpsInformation.position.latitude = float(pvtData->lldeg[0]/100.00);
and then print this value alone.

Hope that this provide you with correct information and removes the offset.

Best Regards,
Open AT Fan.


#19

Hi everyone!

I’m not sure that I understood every detail of this thread, but let me summarize what I found out about the GPS data inaccuracy problem.

If GCC compiler is used, then %f causes problems in the sprintf function, therefore a substitute wm_sprintf was written. Unfortunately this wm_sprintf functions has some serious bugs, so the sample applications QueryApp and InternetConnection are providing inaccurate positions.

Now I got a corrected version of QueryApp from my distributor, which performs well (accurate positions), but still has a couple of irritating bugs (bad UTC time, bad HDOP, bad VDOP), so I guess it’s not the final version.

I hope we will have a final version soon…