Nav-Soft an OpenSource Software GNSS company.

Home > GPS Data Encoding > Raw Almanac Transform

GPS Almanac Message Transformation.

Here we will go through the code that takes a raw or binary Almanac message and transforms it into the Almanac values used in a program to calculate the Satellites rough position. This code has been developed using the C programming language as that is a language we are familiar with and that is suitable for embedded programming.

We begin by defining several variables that will be used during the calculation. It should also be noted that the 6 parity bits have already been stripped from the message words.

void    almanac_sfr(subframe_t *subframe)
GPS_structAlmanac *alm;
unsigned int prn;
unsigned int utemp;
int temp,wordno;

    prn = (subframe->word[2]>>16) & 0x3f;
    alm = &almanacs[prn-1];

First we determine the Satellite whose almanac mesage this is and then we fetch the almanac structure for that satellite.

    if(alm->toa == alm_toa && alm->week == alm_week) return;
    temp = (subframe->word[3]>>16)*4096;
    if(temp != alm_toa) return;

Next we see if this is a new almanac message that needs tranforming or not, by comparing the time of the current almanac with that from frame 5 page 25 which tells us the value for the current almanacs being transmitted. If the latest alamanc is not already in memory then we check to see if this message contains the new almanac data, if this is the latest almanac message that we have not already acquired then we carry on transforming it. In case the structure is empty we set the satellite id and update the current almanac gps week value.

    alm->prn = prn;
    alm->week = alm_week;

    utemp = (subframe->word[2])&0xffff;
    alm->ecc = (double)utemp * c_2m21;

We now extract the last 16 bits from the 3rd word in the frame, note C arrays begin at 0, and then multiply it by the scale factor to give a value of the correct size. Then we save the resulting eccentricity value in the almanac structure.

    alm->toa = (subframe->word[3]>>16)*4096;
    temp = (subframe->word[3])&0xffff
    if(temp&0x8000) temp |= 0xffff0000;
    alm->i0 = (double)temp*c_2m19 + 0.3;
    alm->i0 *= PI;

We now break the words up into their component fields, if required, and multiply those by the relevant scale factor before storing the resulting values in the almanac structure. Because these values are two's complement we need to make all the leading bits in memory the same as the leading bit from the message.

    temp = subframe->word[4]>>8;
    if(temp&0x8000) temp |= 0xffff0000;
    alm->omegadot = (double)temp*c_2m38*PI;
    alm->health = subframe->word[4]&0xff;

    utemp = subframe->word[5];
    alm->sqrta = (double)utemp*c_2m11 ;

    temp = subframe->word[6];
    if(temp&0x800000) temp |= 0xff000000;
    alm->omega0 = (double)temp*c_2m23*PI;

    temp = subframe->word[7];
    if(temp&0x800000) temp |= 0xff000000;
    alm->w = (double)temp*c_2m23*PI;

    temp = subframe->word[8];
    if(temp&0x800000) temp |= 0xff000000;
    alm->m0 = (double)temp*c_2m23*PI;

    temp = (subframe->word[9]>>5)&0x07ff;
    if(temp&0x400) temp |= 0xfffff800;
    alm->af1 = (double)temp*c_2m38;
    temp = (subframe->word[9]>>2)&0x07;
    temp += (subframe->word[9]>>13)&0x07f8;
    if(temp&0x400) temp |= 0xfffff800;
    alm->af0 = (double)temp*c_2m20;

Once we have done all the parameters in the almanac message, we update the status of the strucure to note that it is available again to use in further calculation and does not contain a mix from two seperate almanacs.

    alm->isValid = 1;

//  sprintf(string,"Updating sat %d Almanac for toa %d week %d\n\r%n",
//      prn,alm->toa,alm->week,&slen);
//  cyg_io_write(ser1_hdl,string,&slen);

        storedData.almanacs[prn-1][wordno] = subframe->word[wordno+2];
//  temp = 0x1000 + 0x20*(prn-1);
//  nvtlssii_eeprom_write(temp,storedData.almanacs[prn-1],32,true);
    log_alm[prn-1] = 1;
} © 2018

To complete the process the new almanac data is stored in non-volatile memory, so that it will be available if we switch the GPS receiver off and on again some time later. We also tell the logging function that we have an updated almanac to output.

Similar logic is followed to transform the raw/binary Ephemeris message except this spans 3 seperate frames, also the Iono parameter model message and the UTC conversion message.

Back to Top of Page