1. 程式人生 > >利用rtklib開原始碼處理GPS以及北斗資料詳解

利用rtklib開原始碼處理GPS以及北斗資料詳解

利用rtklib開原始碼處理GPS以及北斗資料詳解

來自:崇亮

利用rtklib開原始碼處理GPS以及北斗資料詳解

         在GNSS領域最基礎的工作是這些GNSS系統的定位工作,對於絕大多數研究者,自己著手完成這些工作是一個“雞肋”:完全獨立設計的話費時費力,運用開原始碼又很難弄懂。我當初也是如此。但想到畢竟開原始碼已經做了很多工作,不用實在可惜,最終毅然決定咬緊牙關弄懂rtklib。嘗試用過rtklib的人都知道,其功能固然完全,然而程式碼卻太過複雜,把人攪得一頭霧水。想用vs2008使用那些程式碼,從新增檔案到使用函式,簡直是步步艱難。我已經從中吃了不少苦頭,在用的時候也找不到比較詳細的使用方法。不想後來者也像我一樣,在rtklib使用中痛苦萬分,故以現有的研究程度,對rtklib做個入門介紹。

         關於rtklib的基本介紹,網上一堆,在此不再贅言,本文重點介紹如何用vs2008使用其src檔案中的開原始碼以及修改以完成自己需要的功能。

 

一、rtklib程式碼的新增

由於習慣了vs2008,在開發程式時用到這個編譯器。新增過程如下:

1、  在vs中新建一個控制檯專案(含預編譯頭);

2、  在建好的專案中新增rtklib.h以及需要用到的source檔案(.c檔案),然後將.c改為.cpp並在每個檔案首句增加一行#include "stdafx.h",當然在stdafx.h檔案中新增#include "rtklib.h"; 這樣編譯基本可以通過了;

3、  一般而言,我們不會需要用到rtklib程式集中的所有檔案,只是需要部分。比如我需要用到其中的pntpos這個標準單點定位函式,這個時候就需要新增該函式所在實現檔案(pntpos.c)。於是添加了這個檔案。但是一般而言,只新增這一個可能不能解決問題,因為rtklib的各個檔案之間並不是完全獨立,pntpos檔案中某些函式可能會呼叫到其他檔案中實現的函式。於是需要再把相關檔案新增到工程中。對於這個問題,可以根據自己新增的檔案,編譯時候的提示,依次新增進來相應檔案。這樣可以解決fatal error的問題;

4、  在新增完成後,可能會遇到一些其他問題。主要問題有:a.關於某些地方陣列越界或為空(主要是glonass),這個時候,檢視rtklib.h標頭檔案,可以發現關於系統啟用的#define語句,其中除GPS系統外,其他系統數目都是0。解決辦法如截圖:主要

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

是註釋掉這個判斷語句。(當然,這樣造成的是所有系統直接啟用,這是我的處理辦法,不是最佳的辦法,讀者有更好的辦法求賜教哈)b.關於很多地方會出現const char*與char*的不能轉化問題,這個很簡單,在相應地方進行強制轉化就行。c.還存在字符集採用的問題,這個只需要在專案屬性中使用多位元組字符集即可(見下圖)。

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

d.關於某些函式存在未實現的問題,這個時候,可以網上直接搜尋那些沒有實現的函式,進行替換,或是直接遮蔽掉。

rtklib中程式碼的新增工作基本就這些問題,解決後應該就可以使用了。

 

二、rtklib程式碼的修改

rtkilib的頭疼之處不只在於新增工作一堆問題,還在於即便新增好了,在使用其中函式的時候還是一堆問題。我這次使用主要是用最新版本rtklib_2.4.2進行GPS與北斗的標準單點定位:主要會用到readrnx、pntpos、postpos等函式(函式裡面又有一堆子函式),本以為呼叫成功就可以了,沒想到根本不是那麼順利。rtklib雖然聲稱能處理北斗資料和rinex3.0以上版本,但實際上並沒完全實現。要想處理這些問題,還得自己修改程式碼。我這次主要是修改了檔案讀取和定位部分。

1、rinex檔案讀取函式的修改

a.  讀取北斗導航檔案的問題:rtklib在讀取導航檔案的時候沒法區分GPS n檔案與北斗c檔案,這會導致後面沒法進行北斗的定位。下面詳述修改方法:本人的方法是在readrnxfp函式的readrnxh函式裡面進行系統的標示。

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

如上圖,在type確認出文件為導航n檔案時,區分GPS與北斗。並將系統標示賦在sys裡面。增加這些後,區分沒問題了。但還不夠,如果這樣,後面還是無法區分,而且sys一直是GPS。當時這個破問題廢了我兩個多小時(無語死了)。後來仔細除錯,才終於發現,問題出在該函式後面的一個語句有誤。如下圖,只需要在該處新增一個break!!!(小問題害死人!)

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

不要以為這樣就行了,這還只是解決了系統辨認的問題,革命尚未成功!在導航檔案的檔案體讀取中,還得修改。Readrnxnavb中需要增加處理北斗系統的語句,以與GPS區分。在增加了處理部分後,區分並讀取北斗導航檔案就沒問題了,就不會影響到後面北斗的定位了。

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

b.  rinex3.0以上版本北斗觀測值檔案的讀取:如果沒進行修改就去讀取含北斗的rinex3.0以上版本o檔案,會發現北斗資料壓根就沒有讀取進去。(雖然聲稱已解決,但不夠完美)這個時候,又需要修改讀取函數了。首先需要修改讀取觀測值檔案頭的函式decode_obsh中的convcode。由於3.0版本的觀測值型別跟低版本的差別較大,而且GNSS系統較多,觀測值型別的儲存有一定轉化規律,然而這個究竟如何,暫時也沒有一定之規。該函式中的轉化不夠合理,沒法處理北斗的部分

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

這個需要自己增加處理北斗的語句,至於具體怎麼新增,主要是採用截圖所示方法,但具體編碼之間的對應,則各人見仁見智了。

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

在檔案體中則需要修改readrnxobsb中用到的set_index。這個是將

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

改為

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

方法很笨拙,目前還沒仔細思考更好的辦法(多交流。。),不過這樣就可以了。

2、  GPS以及北斗單點定位的程式碼修改

a.pntpos的使用:如果直接在讀取了rinex檔案後進行pntpos的定位操作,會發現定位結果為0。這是直接用pntpos會存在的問題。單步除錯會發現其實是因為函式中用到的lam為0,仔細查詢,發現其實根本沒有地方給這個變數賦值。這時候需要在外部直接賦值。在處理北斗時候,由於14s(得感謝何師兄的點撥才解決)的存在,需要再衛星位置計算函式裡面設定判斷,當處理北斗時進行14s的處理。然後就行了。

在用此函式定位時,引數輸入會很多,程式碼裡面自帶一個預設引數配置,如果切換定位系統則需要相應的修改引數。

主要是將navsys相應的切換就行。

利用rtklib開原始碼處理GPS以及北斗資料詳解 - 崇亮 - 一往無前

c.  postpos的使用:postpos的單點定位實際上是用到了前述的所有函式,而且一般是作為外部呼叫的最佳介面。前面各個部分都改好了的話,直接使用這個函式是沒問題的,如果GPS或是北斗沒法定位那絕對是前面沒改好。

在處理好上述問題後,用程式碼單獨處理北斗資料或者GPS資料都是沒問題的。至於如何同時都利用則是一個更復雜的問題,rtklib提供的可執行程式也沒實現這個問題,這需要在以後的工作中繼續研究。

 

三、呼叫函式時候引數的設定程式碼

函式怎麼用也是一個問題,為了方便使用,貼出我的呼叫程式碼作為參考,相信可以減少不少時間。

1、  pntpos模式:

//  const char *file="d:\\rinex\\*.*";//cent1530.12o";

//  int rcv=0;//接收機編號

//  const char *opt="";//選擇提取訊號型別

//  obs_t *obs=new obs_t();//函式裡面會分配記憶體

//  nav_t *nav=new nav_t();//同上

//  sta_t *sta=new sta_t();//同上

        //      for (int ii=0;ii

        //      {

//               nav->lam[ii][0]=CLIGHT/FREQ1;

//               nav->lam[ii][1]=CLIGHT/FREQ2;

//               nav->lam[ii][2]=CLIGHT/FREQ5;

//      }

//      for(intii=NSATGPS+NSATGLO+NSATGAL;ii

//      {

//               nav->lam[ii][0]=CLIGHT/FREQ2_CMP;

//               nav->lam[ii][1]=CLIGHT/FREQ7_CMP;

//               nav->lam[ii][2]=CLIGHT/FREQ6_CMP;

//      }

//      readrnx(file, rcv, opt, obs, nav, sta);//全部讀取

//

//      char sat[4]="";

//      for (int i=0;i<25;i++)

//      {

//               satno2id(obs->data[i].sat,sat);

//               printf("%d         %s    ",obs->data[i].sat,sat);

//               cout<<setiosflags(ios::fixed)<<setprecision(4)<<obs->data[i].P[0]<<" "

//                         <<obs->data[i].P[1]<<" "

//                         <<obs->data[i].P[2]<<endl; //

  //     }

//      for (int i=9;i<18;i++)

//      {

//               satno2id(nav->eph[i].sat,sat);

//               printf("%d         %s    ",nav->eph[i].sat,sat);

//               cout<<setiosflags(ios::fixed)<<setprecision(4)<<nav->eph[i].toes<<" "

//                         <<nav->eph[i].week<<endl;

//      }

//

//      cout<<"read rinex over"<<endl;

//

//      const prcopt_t prcopt_df={

//    PMODE_SINGLE,0,2,SYS_CMP,  

//    15.0*D2R,{{0,0}},          

//   EPHOPT_BRDC,1,1,5,0,10,       

//        IONOOPT_BRDC,TROPOPT_SAAS,0,0,                    //edit by wfb

//    1,0,0,0,0,                 

//    0,0,                       

//    {100.0,100.0},             

//    {100.0,0.003,0.003,0.0,1.0},

//    {30.0,0.03,0.3},           

//    {1E-4,1E-3,1E-4,1E-1,1E-2},

//    5E-12,                     

//    {3.0,0.9999,0.20},         

//    0.0,0.0,0.05,              

//    30.0,30.0,30.0,            

//    {0},{0},{0},               

//    {"",""},                   

//    {{0}},{{0}},{0}            

//};

//      int nn=18-9;

//      const prcopt_t *optn=new prcopt_t(prcopt_df);//前面設定好系統(GPS、北斗等)

//      sol_t *sol=new sol_t();//(sol_t*)malloc(sizeof(sol_t)*1);

//      //ssat_t *ssat=(ssat_t*)malloc(sizeof(ssat_t)*obs->n);

  //    double *azel=zeros(2,nn);//

  //    char *msg=new char(1024);//同上

//      //ssat_t *ssat=NULL;

//      pntpos(obs->data+9,nn,nav,optn,sol,azel,NULL,msg);//

//      for (int i=0;i

//      {

//               satno2id(obs->data[i].sat,sat);

//               printf("%s         ",sat);

//               cout<<azel[i*2]<<"  "<<azel[i*2+1]<<endl;

//      }

//

//      cout<<"single postioning over\n\npos and vel:\n"<<endl;

//      for (int i=0;i<2;i++)

//      {

//               printf("%.4f      %.4f %.4f\n",sol->rr[i*3],sol->rr[i*3+1],sol- >rr[i*3+2]);

//      }

//      cout<<"all over"<<endl;

//

//      free(azel);free(obs);free(nav);free(sta);free(sol);//free(ssat);

//      return 0;

2、  postpose模式:

const prcopt_t prcopt_df={

           PMODE_SINGLE,0,2,SYS_CMP,   //                           15.0*D2R,{{0,0}},          

           EPHOPT_BRDC,1,1,5,0,10,              

           IONOOPT_BRDC,TROPOPT_SAAS,0,0,                    //edit by wfb

           1,0,0,0,0,                 

           0,0,                       

           {100.0,100.0},             

           {100.0,0.003,0.003,0.0,1.0},

           {30.0,0.03,0.3},            

           {1E-4,1E-3,1E-4,1E-1,1E-2},

           5E-12,                     

           {3.0,0.9999,0.20},         

           0.0,0.0,0.05,              

           30.0,30.0,30.0,            

           {0},{0},{0},               

           {"",""},                   

           {{0}},{{0}},{0}            

};

const solopt_t solopt_df={

           SOLF_XYZ,TIMES_GPST,1,3,    //times            0,1,0,0,0,0,               

           0,0,0,                     

           {0.0,0.0},                 

           " ",""                     

};

gtime_t ts={0,0};

gtime_t te={0,0};

double ti=0;

double tu=0;

const prcopt_t *popt=new prcopt_t(prcopt_df);

const solopt_t *sopt=new solopt_t(solopt_df);

const filopt_t *fopt=new filopt_t();

char *infile[]={"d:\\rinex\\huashicom3.12O","d:\\rinex\\huashicom3.12C"};

int n=2;

char *outfile="D:\\pos.txt";

const char *rov="";

const char *base="";

 

cout<<"*********postpos start*********"<<endl;

postpos(ts,te,ti,tu,popt,sopt,fopt,infile,n,outfile,rov,base);

cout<<"*********postpos over*********"<<endl;