├── .vscode └── launch.json ├── LICENSE ├── README.md ├── app ├── convbin │ ├── convbin.go │ └── go.mod ├── plot │ ├── collector.go │ ├── go.mod │ ├── go.sum │ └── plot.go ├── pos2kml │ ├── go.mod │ └── pos2kml.go ├── rnx2rtkp │ ├── go.mod │ ├── go.sum │ ├── go.work.sum │ └── rnx2rtkp.go ├── rtkrcv │ ├── conf │ │ ├── rtk.conf │ │ └── single.conf │ ├── go.mod │ ├── go.sum │ ├── rtkrcv.conf │ ├── rtkrcv.go │ ├── rtkrcv.go.removed │ └── rtkrcv_test.go └── str2str │ ├── go.mod │ ├── oem6_20121107.rtcm3 │ └── str2str.go ├── go.sum ├── go.work ├── go.work.sum ├── readme.md ├── src ├── binex.go ├── clickhouse.sql ├── common.go ├── convgpx.go ├── convkml.go ├── convrnx.go ├── crescent.go ├── datum.go ├── download.go ├── ephemeris.go ├── geoid.go ├── gis.go ├── go.mod ├── go.sum ├── httpUtils.go ├── ionex.go ├── javad.go ├── lamda.go ├── novatel.go ├── nvs.go ├── options.go ├── pntpos.go ├── postpos.go ├── ppp.go ├── preceph.go ├── rcvraw.go ├── renix.go ├── rtcm.go ├── rtcm2.go ├── rtcm3.go ├── rtcm3e.go ├── rtkpos.go ├── rtksvr.go ├── sbas.go ├── skytraq.go ├── solution.go ├── ss2.go ├── stream.go ├── streamsvr.go ├── tides.go ├── tle.go ├── types.go ├── ublox.go └── workspace.code-workspace └── unittest ├── atmos_test.go ├── coord_test.go ├── geoid_test.go ├── glo.eph ├── gloeph_test.go ├── go.mod ├── go.sum ├── grammar_test.go ├── ionex_test.go ├── lambda_test.go ├── matrix_test.go ├── misc_test.go ├── ppp_test.go ├── preceph_test.go ├── renix_test.go ├── time_test.go └── tle_test.go /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Package", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${fileDirname}", 13 | // mx2rtkp spp 14 | // "args": [ 15 | // "-p", "0", 16 | // "-t", 17 | // "-e", 18 | // "-x", "5", 19 | // "-o", "../../out/result.pos", 20 | // "../../data/bjfs3370.12o","../../data/bjfs3370.12n" 21 | // ] 22 | // mx2rtkp rtk pos 23 | // "args": [ 24 | // "-k", "../../data/2.0 RTK(100m)/best.conf", 25 | // "-o", "../../out/wtza0010.pos", 26 | // "-x", "5", 27 | // "../../data/2.0 RTK(100m)/wtza0010.18o", 28 | // "../../data/2.0 RTK(100m)/wtzs0010.18o", 29 | // "../../data/2.0 RTK(100m)/brdc0010.18n" 30 | // ] 31 | // mx2rtkp PPP 32 | // "args": [ 33 | // "-k", "../../data/3.0 PPP/PPP_BJFS.conf", 34 | // "-o", "../../out/bjfs3370.pos", 35 | // "-x", "5", 36 | // "../../data/3.0 PPP/bjfs3370.12o", 37 | // "../../data/3.0 PPP/bjfs3370.12n", 38 | // "../../data/3.0 PPP/igs17170.sp3", 39 | // "../../data/3.0 PPP/igs17170.clk" 40 | // ] 41 | // mx2rtkp PPP for 海格数据 42 | // "args": [ 43 | // "-k", "../../data/3.0 PPP/PPP_BJFS.conf", 44 | // "-sys", "C", 45 | // "-ts", "2022/07/20,02:00:00", 46 | // "-te", "2022/07/20,03:30:00", 47 | // // "-t", "-e", 48 | // "-o", "../../out/2022072010001130.pos", 49 | // "-x", "5", 50 | // "../../data/haige/2022072010001130.obs", 51 | // "../../data/haige/2022072010001130.nav", 52 | // "../../data/haige/WUM0MGXULA_20222030200_01D_05M_CLK.clk", 53 | // "../../data/haige/WUM0MGXULA_20222030200_01D_05M_ORB.sp3" 54 | // ] 55 | // mx2rtkp RTD 56 | // "args": [ 57 | // "-k", "../../data/2.0 RTK(100m)/best.conf", 58 | // "-o", "../../out/wtza0010.pos", 59 | // "-x", "5", 60 | // "-p", "1", // RTD: DGPS 61 | // "../../data/2.0 RTK(100m)/wtza0010.18o", 62 | // "../../data/2.0 RTK(100m)/wtzs0010.18o", 63 | // "../../data/2.0 RTK(100m)/brdc0010.18n" 64 | // ] 65 | // rtkrcv 66 | // "args": [ 67 | // "-s", 68 | // "-t", 69 | // "5" 70 | // // "-d", "/dev/vvt" 71 | // ] 72 | // str2str 73 | // "args": [ 74 | // "-in", "ntrip://landsd-gncaster.realtime.data.gov.hk:2101/HKCL", 75 | // "-out", "file://E:/Users/fengxb/Codes/gnssgo/out/HKCL%n.RTCM3::S=24", 76 | // "-t", "5" 77 | // ] 78 | // str2str test4 79 | // "args": [ 80 | // "-in", "../../data/rcvraw/oemv_200911218.gps#nov", 81 | // "-out", "oem6_20121107.rtcm3#rtcm3", 82 | // "-sta", "123", 83 | // "-msg", "1077(10),1087(10),1097(10),1107(10),1117(10),1019,1020", 84 | // "-t", "5" 85 | // ] 86 | // convbin 87 | // "args": [ 88 | // "-r", "rtcm3", 89 | // "-v", "3.02", 90 | // // "-ti", "30", 91 | // "-os", 92 | // "-od", 93 | // // "-ts", "2022/6/23,0:0:0", 94 | // // "-te", "2022/6/23,23:59:59", 95 | // // "-trace", "5", 96 | // "../../out/HKCL174.RTCM3" 97 | // ] 98 | // convbin for rtcm2 99 | // "args": [ 100 | // "-d", ".", 101 | // "-tr", "2009/12/18,23:20:00", 102 | // // "-te", "2022/6/23,23:59:59", 103 | // "-trace", "5", 104 | // "../../data/rcvraw/testglo.rtcm2" 105 | // ] 106 | //convbin for rtcm2 107 | "args": [ 108 | "-d", 109 | ".", 110 | // "-tr", 111 | // "2009/12/18,23:20:00", 112 | // "-te", "2022/6/23,23:59:59", 113 | "-trace", 114 | "5", 115 | "../../data/sh0115*.23o", 116 | ] // convbin for rtcm2 117 | // "args": [ 118 | // "-d", 119 | // ".", 120 | // //"-r", 121 | // //"oem3", // novatel oem3 verstion 122 | // // "-tr", "2009/12/18,23:20:00", 123 | // // "-te", "2022/6/23,23:59:59", 124 | // "-trace", 125 | // "5", 126 | // "../../data/rcvraw/0415.stq" 127 | // ] 128 | // plot 129 | // "args": [ 130 | // // "-ti", "30", 131 | // "-ts", "2018/01/01,00:00:00", 132 | // "-te", "2018/01/01,23:59:59", 133 | // // "-trace", "5", 134 | // "../../out/wtza0010.pos" 135 | // ] 136 | // pos2kml 137 | // "args": [ 138 | // "-ag", "-tu",// "-gpx", 139 | // "../../out/bjfs3370.pos" 140 | // ] 141 | } 142 | ] 143 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2 | # gnssgo 1.0 3 | # 4 | 5 | # DESCRIPTION 6 | 7 | The development branch for golang version of RTKLIB 2.4.3. 8 | 9 | RTKLIB is an excellent tool for GNSS development and research. Golang became population in recent. According to requirement of project, I recoded RTKLIB with golang for almost one years. 10 | 11 | Due to limitation of commit folder size, I didn't commit data files. If you want to test the project, you could download from RTKLIB. 12 | 13 | Author: Dr. Feng Xuebin, Explore Data Technology (Shenzhen) Ltd., co 14 | 15 | # UPDATE HISTORY 16 | 17 | 2023/06/06 1.0 18 | 19 | # Build and Installation 20 | In file 'go.work', you could choose your app by uncommenting app path. 21 | 22 | For configuring app, you could define command line arguments in file 'luanch.json' under directory .vscode. 23 | -------------------------------------------------------------------------------- /app/convbin/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo_app 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /app/plot/collector.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/prometheus/client_golang/prometheus" 5 | ) 6 | 7 | //Define a struct for you collector that contains pointers 8 | //to prometheus descriptors for each metric you wish to expose. 9 | //Note you can also include fields of other types if they provide utility 10 | //but we just won't be exposing them as metrics. 11 | type fooCollector struct { 12 | fooMetric *prometheus.Desc 13 | barMetric *prometheus.Desc 14 | } 15 | 16 | //You must create a constructor for you collector that 17 | //initializes every descriptor and returns a pointer to the collector 18 | func newFooCollector() *fooCollector { 19 | return &fooCollector{ 20 | fooMetric: prometheus.NewDesc("foo_metric", 21 | "Shows whether a foo has occurred in our cluster", 22 | nil, nil, 23 | ), 24 | barMetric: prometheus.NewDesc("bar_metric", 25 | "Shows whether a bar has occurred in our cluster", 26 | nil, nil, 27 | ), 28 | } 29 | } 30 | 31 | //Each and every collector must implement the Describe function. 32 | //It essentially writes all descriptors to the prometheus desc channel. 33 | func (collector *fooCollector) Describe(ch chan<- *prometheus.Desc) { 34 | 35 | //Update this section with the each metric you create for a given collector 36 | ch <- collector.fooMetric 37 | ch <- collector.barMetric 38 | } 39 | 40 | //Collect implements required collect function for all promehteus collectors 41 | func (collector *fooCollector) Collect(ch chan<- prometheus.Metric) { 42 | 43 | //Implement logic here to determine proper metric value to return to prometheus 44 | //for each descriptor or call other functions that do so. 45 | var metricValue float64 46 | if 1 == 1 { 47 | metricValue = 1 48 | } 49 | 50 | //Write latest value for each metric in the prometheus metric channel. 51 | //Note that you can pass CounterValue, GaugeValue, or UntypedValue types here. 52 | ch <- prometheus.MustNewConstMetric(collector.fooMetric, prometheus.CounterValue, metricValue) 53 | ch <- prometheus.MustNewConstMetric(collector.barMetric, prometheus.CounterValue, metricValue) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/plot/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo_app 2 | 3 | go 1.18 4 | 5 | require github.com/influxdata/influxdb-client-go/v2 v2.9.1 6 | 7 | require ( 8 | github.com/beorn7/perks v1.0.1 // indirect 9 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 10 | github.com/golang/protobuf v1.5.2 // indirect 11 | github.com/google/uuid v1.3.0 // indirect 12 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 13 | github.com/prometheus/client_model v0.2.0 // indirect 14 | github.com/prometheus/common v0.35.0 // indirect 15 | github.com/prometheus/procfs v0.7.3 // indirect 16 | golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect 17 | google.golang.org/protobuf v1.28.0 // indirect 18 | ) 19 | 20 | require ( 21 | github.com/deepmap/oapi-codegen v1.11.0 // indirect 22 | github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect 23 | github.com/pkg/errors v0.9.1 // indirect 24 | github.com/prometheus/client_golang v1.12.2 25 | golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect 26 | gopkg.in/yaml.v2 v2.4.0 // indirect 27 | ) 28 | -------------------------------------------------------------------------------- /app/pos2kml/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo_app 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /app/pos2kml/pos2kml.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * pos2kml.c : convert positions to google earth KML or GPX file 3 | * 4 | * Copyright (C) 2007-2016 by T.TAKASU, All rights reserved. 5 | * 6 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:54:53 $ 7 | * history : 2007/01/20 1.0 new 8 | * 2007/03/15 1.1 modify color sequence 9 | * 2007/04/03 1.2 add geodetic height option 10 | * support input of NMEA GGA sentence 11 | * delete altitude info for track 12 | * add time stamp option 13 | * separate readsol.c file 14 | * 2008/07/18 1.3 support change of convkml() arguments 15 | * 2016/06/11 1.4 add option -gpx for gpx conversion 16 | *-----------------------------------------------------------------------------*/ 17 | package main 18 | 19 | import ( 20 | "flag" 21 | "fmt" 22 | "os" 23 | "strings" 24 | 25 | "gnssgo" 26 | "strconv" 27 | ) 28 | 29 | /* help text -----------------------------------------------------------------*/ 30 | var help = []string{ 31 | "", 32 | " usage: pos2kml [option]... file [...]", 33 | "", 34 | " Read solution file(s) and convert it to Google Earth KML file or GPX file.", 35 | " Each line in the input file shall contain fields of time, position fields ", 36 | " (latitude/longitude/height or x/y/z-ecef), and quality flag(option). The line", 37 | " started with '%', '#', ';' is treated as comment. Command options are as ", 38 | " follows. ([]:default)", 39 | "", 40 | " -h print help", 41 | " -ts ds,ts start day/time (ds=y/m/d ts=h:m:s) [obs start time]", 42 | " -te de,te end day/time (de=y/m/d te=h:m:s) [obs end time]", 43 | " -o file output file [infile + .kml]", 44 | " -c color track color (0:off,1:white,2:green,3:orange,4:red,5:yellow) [5]", 45 | " -p color point color (0:off,1:white,2:green,3:orange,4:red,5:by qflag) [5]", 46 | " -a output altitude information [off]", 47 | " -ag output geodetic altitude [off]", 48 | " -tg output time stamp of gpst [off]", 49 | " -tu output time stamp of utc [gpst]", 50 | " -i tint output time interval (s) (0:all) [0]", 51 | " -q qflg output q-flags (0:all) [0]", 52 | " -f n,e,h add north/east/height offset to position (m) [0 0 0]", 53 | " -gpx output GPX file", 54 | } 55 | 56 | /* print help ----------------------------------------------------------------*/ 57 | func printhelp() { 58 | for i := range help { 59 | fmt.Fprintf(os.Stderr, "%s\n", help[i]) 60 | } 61 | os.Exit(0) 62 | } 63 | 64 | func searchHelp(key string) string { 65 | for _, v := range help { 66 | if strings.Contains(v, key) { 67 | return v 68 | } 69 | } 70 | return "no surported augument" 71 | } 72 | 73 | type timeFlag struct { 74 | time *gnssgo.Gtime 75 | configured bool 76 | } 77 | 78 | func (f *timeFlag) Set(s string) error { 79 | var es []float64 = []float64{2000, 1, 1, 0, 0, 0} 80 | n, _ := fmt.Sscanf(s, "%f/%f/%f,%f:%f:%f", &es[0], &es[1], &es[2], &es[3], &es[4], &es[5]) 81 | if n < 6 { 82 | return fmt.Errorf("too few argument") 83 | } 84 | *(f.time) = gnssgo.Epoch2Time(es) 85 | f.configured = true 86 | return nil 87 | } 88 | func (f *timeFlag) String() string { 89 | return "2000/1/1,0:0:0" 90 | } 91 | func newGtime(p *gnssgo.Gtime) *timeFlag { 92 | tf := timeFlag{p, false} 93 | return &tf 94 | } 95 | 96 | type posFlag struct { 97 | pos []float64 98 | configured bool 99 | } 100 | 101 | func (f *posFlag) Set(s string) error { 102 | values := strings.Split(s, ",") 103 | if len(values) < 3 { 104 | return fmt.Errorf("too few arguments") 105 | } 106 | for i, v := range values { 107 | posFlag(*f).pos[i], _ = strconv.ParseFloat(v, 64) 108 | } 109 | f.configured = true 110 | return nil 111 | } 112 | func (f *posFlag) String() string { 113 | return "0,0,0" 114 | } 115 | 116 | func newFloatSlice(value []float64, p *[]float64) *posFlag { 117 | pf := posFlag{value, false} 118 | *p = pf.pos 119 | return &pf 120 | } 121 | 122 | /* pos2kml main --------------------------------------------------------------*/ 123 | func main() { 124 | var ( 125 | i, n, outalt, outtime, qflg int 126 | tcolor, pcolor int = 5, 5 127 | stat int 128 | infiles []string 129 | outfile string 130 | offset [3]float64 131 | tint float64 132 | ts, te gnssgo.Gtime 133 | ba, bag, btg, btu, bgpx bool 134 | ) 135 | 136 | flag.Var(newGtime(&ts), "ts", searchHelp("-ts")) 137 | flag.Var(newGtime(&te), "te", searchHelp("-te")) 138 | flag.StringVar(&outfile, "o", outfile, searchHelp("-o")) 139 | flag.IntVar(&tcolor, "c", tcolor, searchHelp("-c")) 140 | flag.IntVar(&pcolor, "p", pcolor, searchHelp("-p")) 141 | rp := offset[:] 142 | rpFlag := newFloatSlice([]float64{}, &rp) 143 | flag.Var(rpFlag, "f", searchHelp("-f")) 144 | 145 | flag.BoolVar(&ba, "a", false, searchHelp("-a")) 146 | flag.BoolVar(&bag, "ag", false, searchHelp("-ag")) 147 | flag.BoolVar(&btg, "tg", false, searchHelp("-tg")) 148 | flag.BoolVar(&btu, "tu", false, searchHelp("-tu")) 149 | flag.Float64Var(&tint, "i", tint, searchHelp("-i")) 150 | flag.IntVar(&qflg, "q", qflg, searchHelp("-q")) 151 | flag.BoolVar(&bgpx, "gpx", false, searchHelp("-gpx")) 152 | 153 | flag.Parse() 154 | 155 | if flag.NFlag() < 1 { 156 | // if there is not any arguments, exit 157 | for _, h := range help { 158 | fmt.Printf("%s\n", h) 159 | } 160 | return 161 | } 162 | if ba { 163 | outalt = 1 164 | } 165 | if bag { 166 | outalt = 2 167 | } 168 | if btg { 169 | outtime = 1 170 | } 171 | if btu { 172 | outtime = 2 173 | } 174 | 175 | infiles = flag.CommandLine.Args() 176 | if n = len(infiles); n < 1 { 177 | fmt.Fprintf(os.Stderr, "pos2kml : no input file\n") 178 | os.Exit(-1) 179 | } 180 | 181 | if tcolor < 0 || 5 < tcolor || pcolor < 0 || 5 < pcolor { 182 | fmt.Fprintf(os.Stderr, "pos2kml : command option error\n") 183 | os.Exit(-1) 184 | } 185 | for i = 0; i < n; i++ { 186 | if bgpx { 187 | stat = gnssgo.ConvGpx(infiles[i], outfile, ts, te, tint, qflg, offset[:], tcolor, pcolor, 188 | outalt, outtime) 189 | } else { 190 | stat = gnssgo.ConvKml(infiles[i], outfile, ts, te, tint, qflg, offset[:], tcolor, pcolor, 191 | outalt, outtime) 192 | } 193 | switch stat { 194 | case -1: 195 | fmt.Fprintf(os.Stderr, "pos2kml : file read error (%d)\n", i+1) 196 | case -2: 197 | fmt.Fprintf(os.Stderr, "pos2kml : file format error (%d)\n", i+1) 198 | case -3: 199 | fmt.Fprintf(os.Stderr, "pos2kml : no input data (%d)\n", i+1) 200 | case -4: 201 | fmt.Fprintf(os.Stderr, "pos2kml : file write error (%d)\n", i+1) 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /app/rnx2rtkp/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo_app 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /app/rnx2rtkp/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengXuebin/gnssgo/fddcd58a3beb5f41ff0cfe5ab3bd8a1b9e85a212/app/rnx2rtkp/go.sum -------------------------------------------------------------------------------- /app/rnx2rtkp/go.work.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 3 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 4 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 5 | github.com/tarm/goserial v0.0.0-20151007205400-b3440c3c6355 h1:Kp3kg8YL2dc75mckomrHZQTfzNyFGnaqFhJeQw4ozGc= 6 | github.com/tarm/goserial v0.0.0-20151007205400-b3440c3c6355/go.mod h1:jcMo2Odv5FpDA6rp8bnczbUolcICW6t54K3s9gOlgII= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 8 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 9 | -------------------------------------------------------------------------------- /app/rnx2rtkp/rnx2rtkp.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rnx2rtkp.c : read rinex obs/nav files and compute receiver positions 3 | * 4 | * Copyright (C) 2007-2016 by T.TAKASU, All rights reserved. 5 | * 6 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:55:16 $ 7 | * history : 2007/01/16 1.0 new 8 | * 2007/03/15 1.1 add library mode 9 | * 2007/05/08 1.2 separate from postpos.c 10 | * 2009/01/20 1.3 support rtklib 2.2.0 api 11 | * 2009/12/12 1.4 support glonass 12 | * add option -h, -a, -l, -x 13 | * 2010/01/28 1.5 add option -k 14 | * 2010/08/12 1.6 add option -y implementation (2.4.0_p1) 15 | * 2014/01/27 1.7 fix bug on default output time format 16 | * 2015/05/15 1.8 -r or -l options for fixed or ppp-fixed mode 17 | * 2015/06/12 1.9 output patch level in header 18 | * 2016/09/07 1.10 add option -sys 19 | *-----------------------------------------------------------------------------*/ 20 | 21 | package main 22 | 23 | import ( 24 | "flag" 25 | "fmt" 26 | "os" 27 | "strconv" 28 | "strings" 29 | 30 | "gnssgo" 31 | ) 32 | 33 | var PROGNAME string = "rnx2rtkp" 34 | 35 | /* help text -----------------------------------------------------------------*/ 36 | var help []string = []string{ 37 | "", 38 | " usage: rnx2rtkp [option]... file file [...]", 39 | "", 40 | " Read RINEX OBS/NAV/GNAV/HNAV/CLK, SP3, SBAS message log files and ccompute ", 41 | " receiver (rover) positions and output position solutions.", 42 | " The first RINEX OBS file shall contain receiver (rover) observations. For the", 43 | " relative mode, the second RINEX OBS file shall contain reference", 44 | " (base station) receiver observations. At least one RINEX NAV/GNAV/HNAV", 45 | " file shall be included in input files. To use SP3 precise ephemeris, specify", 46 | " the path in the files. The extension of the SP3 file shall be .sp3 or .eph.", 47 | " All of the input file paths can include wild-cards (*). To avoid command", 48 | " line deployment of wild-cards, use \"...\" for paths with wild-cards.", 49 | " Command line options are as follows ([]:default). With -k option, the", 50 | " processing options are input from the configuration file. In this case,", 51 | " command line options precede options in the configuration file.", 52 | "", 53 | " -? print help", 54 | " -k file input options from configuration file [off]", 55 | " -o file set output file [stdout]", 56 | " -ts ds,ts start day/time (ds=y/m/d ts=h:m:s) [obs start time]", 57 | " -te de,te end day/time (de=y/m/d te=h:m:s) [obs end time]", 58 | " -ti tint time interval (sec) [all]", 59 | " -p mode mode (0:single,1:dgps,2:kinematic,3:static,4:moving-base,", 60 | " 5:fixed,6:ppp-kinematic,7:ppp-static) [2]", 61 | " -m mask elevation mask angle (deg) [15]", 62 | " -sys s[,s...] nav system(s) (s=G:GPS,R:GLO,E:GAL,J:QZS,C:BDS,I:IRN) [G|R]", 63 | " -f freq number of frequencies for relative mode (1:L1,2:L1+L2,3:L1+L2+L5) [2]", 64 | " -v thres validation threshold for integer ambiguity (0.0:no AR) [3.0]", 65 | " -b backward solutions [off]", 66 | " -c forward/backward combined solutions [off]", 67 | " -i instantaneous integer ambiguity resolution [off]", 68 | " -h fix and hold for integer ambiguity resolution [off]", 69 | " -e output x/y/z-ecef position [latitude/longitude/height]", 70 | " -a output e/n/u-baseline [latitude/longitude/height]", 71 | " -n output NMEA-0183 GGA sentence [off]", 72 | " -g output latitude/longitude in the form of ddd mm ss.ss' [ddd.ddd]", 73 | " -t output time in the form of yyyy/mm/dd hh:mm:ss.ss [sssss.ss]", 74 | " -u output time in utc [gpst]", 75 | " -d col number of decimals in time [3]", 76 | " -s sep field separator [' ']", 77 | " -r x,y,z reference (base) receiver ecef pos (m) [average of single pos]", 78 | " rover receiver ecef pos (m) for fixed or ppp-fixed mode", 79 | " -l lat,lon,hgt reference (base) receiver latitude/longitude/height (deg/m)", 80 | " rover latitude/longitude/height for fixed or ppp-fixed mode", 81 | " -y level output soltion status (0:off,1:states,2:residuals) [0]", 82 | " -x level debug trace level (0:off) [0]"} 83 | 84 | func searchHelp(key string) string { 85 | for _, v := range help { 86 | if strings.Contains(v, key) { 87 | return v 88 | } 89 | } 90 | return "no surported augument" 91 | } 92 | 93 | type timeFlag struct { 94 | time *gnssgo.Gtime 95 | configured bool 96 | } 97 | 98 | func (f *timeFlag) Set(s string) error { 99 | var es []float64 = []float64{2000, 1, 1, 0, 0, 0} 100 | n, _ := fmt.Sscanf(s, "%f/%f/%f,%f:%f:%f", &es[0], &es[1], &es[2], &es[3], &es[4], &es[5]) 101 | if n < 6 { 102 | return fmt.Errorf("too few argument") 103 | } 104 | *(f.time) = gnssgo.Epoch2Time(es) 105 | f.configured = true 106 | return nil 107 | } 108 | func (f *timeFlag) String() string { 109 | return "2000/1/1,0:0:0" 110 | } 111 | func newGtime(p *gnssgo.Gtime) *timeFlag { 112 | tf := timeFlag{p, false} 113 | return &tf 114 | } 115 | 116 | type navsysFlag struct { 117 | sys *int 118 | } 119 | 120 | func (f *navsysFlag) Set(s string) error { 121 | sys := strings.Split(s, ",") 122 | if len(sys) == 0 { 123 | return fmt.Errorf("null argument") 124 | } 125 | var r int 126 | for _, v := range sys { 127 | switch v[0] { 128 | case 'G': 129 | r |= gnssgo.SYS_GPS 130 | case 'R': 131 | r |= gnssgo.SYS_GLO 132 | case 'E': 133 | r |= gnssgo.SYS_GAL 134 | case 'J': 135 | r |= gnssgo.SYS_QZS 136 | case 'C': 137 | r |= gnssgo.SYS_CMP 138 | case 'I': 139 | r |= gnssgo.SYS_IRN 140 | } 141 | } 142 | *f.sys = r 143 | return nil 144 | } 145 | func (f *navsysFlag) String() string { 146 | return "G,R" 147 | } 148 | func newNavSys(value int, p *int) *navsysFlag { 149 | nf := navsysFlag{p} 150 | return &nf 151 | } 152 | 153 | type posFlag struct { 154 | pos []float64 155 | configured bool 156 | } 157 | 158 | func (f *posFlag) Set(s string) error { 159 | values := strings.Split(s, ",") 160 | if len(values) < 3 { 161 | return fmt.Errorf("too few arguments") 162 | } 163 | for i, v := range values { 164 | posFlag(*f).pos[i], _ = strconv.ParseFloat(v, 64) 165 | } 166 | f.configured = true 167 | return nil 168 | } 169 | func (f *posFlag) String() string { 170 | return "0,0,0" 171 | } 172 | func newFloatSlice(value []float64, p *[]float64) *posFlag { 173 | pf := posFlag{value, false} 174 | *p = pf.pos 175 | return &pf 176 | } 177 | 178 | /* show message --------------------------------------------------------------*/ 179 | func showmsg(format string, v ...interface{}) int { 180 | fmt.Fprintf(os.Stderr, format, v...) 181 | if len(format) > 0 { 182 | fmt.Fprintf(os.Stderr, "\r") 183 | } else { 184 | fmt.Fprintf(os.Stderr, "\n") 185 | } 186 | return 0 187 | } 188 | 189 | /* rnx2rtkp main -------------------------------------------------------------*/ 190 | func main() { 191 | var ( 192 | filopt gnssgo.FilOpt 193 | ts, te gnssgo.Gtime 194 | tint float64 = 0.0 195 | pos [3]float64 196 | j, n int 197 | infiles []string 198 | outfile string = "" 199 | config string = "" 200 | soltype1, soltype2, modear2, modear3, timef, times bool 201 | posfxyz, posfenu, posfnmea, degf bool 202 | ) 203 | prcopt := gnssgo.DefaultProcOpt() 204 | solopt := gnssgo.DefaultSolOpt() 205 | 206 | prcopt.Mode = gnssgo.PMODE_KINEMA 207 | prcopt.NavSys = 0 208 | prcopt.RefPos = 1 209 | prcopt.GloModeAr = 1 210 | solopt.TimeF = 0 211 | solopt.Prog = fmt.Sprintf("%s ver.%s %s", PROGNAME, gnssgo.VER_GNSSGO, gnssgo.PATCH_LEVEL) 212 | filopt.Trace = fmt.Sprintf("%s.trace", PROGNAME) 213 | 214 | gnssgo.ShowMsg_Ptr = showmsg 215 | 216 | flag.StringVar(&outfile, "o", outfile, searchHelp("-o")) 217 | flag.Var(newGtime(&ts), "ts", searchHelp("-ts")) 218 | flag.Var(newGtime(&te), "te", searchHelp("-te")) 219 | flag.Float64Var(&tint, "ti", tint, searchHelp("-ti")) 220 | flag.IntVar(&prcopt.Mode, "p", prcopt.Mode, searchHelp("-p")) 221 | flag.StringVar(&config, "k", config, searchHelp("-k")) 222 | flag.IntVar(&prcopt.Nf, "f", prcopt.Nf, searchHelp("-f")) 223 | nsFlag := newNavSys(prcopt.NavSys, &prcopt.NavSys) 224 | flag.Var(nsFlag, "sys", searchHelp("-sys")) 225 | flag.Float64Var(&prcopt.Elmin, "m", prcopt.Elmin, searchHelp("-m")) 226 | flag.Float64Var(&prcopt.ThresAr[0], "v", prcopt.ThresAr[0], searchHelp("-v")) 227 | flag.StringVar(&solopt.Sep, "s", solopt.Sep, searchHelp("-s")) 228 | flag.IntVar(&solopt.TimeU, "d", solopt.TimeU, searchHelp("-d")) 229 | flag.BoolVar(&soltype1, "b", false, searchHelp("-b")) 230 | flag.BoolVar(&soltype2, "c", false, searchHelp("-c")) 231 | flag.BoolVar(&modear2, "i", false, searchHelp("-i")) 232 | flag.BoolVar(&modear3, "h", false, searchHelp("-h")) 233 | flag.BoolVar(&timef, "t", false, searchHelp("-t")) 234 | flag.BoolVar(×, "u", false, searchHelp("-u")) 235 | flag.BoolVar(&posfxyz, "e", false, searchHelp("-e")) 236 | flag.BoolVar(&posfenu, "a", false, searchHelp("-a")) 237 | flag.BoolVar(&posfnmea, "n", false, searchHelp("-n")) 238 | flag.BoolVar(°f, "g", false, searchHelp("-g")) 239 | rb := prcopt.Rb[:] 240 | rbFlag := newFloatSlice([]float64{}, &rb) 241 | rp := pos[:] 242 | rpFlag := newFloatSlice([]float64{}, &rp) 243 | flag.Var(rbFlag, "r", searchHelp("-r")) 244 | flag.Var(rpFlag, "l", searchHelp("-l")) 245 | flag.IntVar(&solopt.SStat, "y", solopt.SStat, searchHelp("-y")) 246 | flag.IntVar(&solopt.Trace, "x", solopt.Trace, searchHelp("-x")) 247 | 248 | flag.Parse() 249 | 250 | if flag.NFlag() < 1 { 251 | // if there is not any arguments, exit 252 | for _, h := range help { 253 | fmt.Printf("%s\n", h) 254 | } 255 | return 256 | } 257 | 258 | if len(config) > 0 { 259 | gnssgo.ResetSysOpts() 260 | if gnssgo.LoadOpts(config, &gnssgo.SysOpts) == 0 { 261 | fmt.Fprintf(os.Stderr, "no options file: %s. defaults used\n", config) 262 | return 263 | } 264 | gnssgo.GetSysOpts(&prcopt, &solopt, &filopt) 265 | } 266 | 267 | flag.Parse() 268 | 269 | if soltype1 { 270 | prcopt.SolType = 1 271 | } 272 | if soltype2 { 273 | prcopt.SolType = 2 274 | } 275 | if modear2 { 276 | prcopt.ModeAr = 2 277 | } 278 | if modear3 { 279 | prcopt.ModeAr = 3 280 | } 281 | if timef { 282 | solopt.TimeF = 1 283 | } 284 | if times { 285 | solopt.TimeS = gnssgo.TIMES_UTC 286 | } 287 | if posfxyz { 288 | solopt.Posf = gnssgo.SOLF_XYZ 289 | } 290 | if posfenu { 291 | solopt.Posf = gnssgo.SOLF_ENU 292 | } 293 | if posfnmea { 294 | solopt.Posf = gnssgo.SOLF_NMEA 295 | } 296 | if degf { 297 | solopt.DegF = 1 298 | } 299 | if rbFlag.configured { 300 | prcopt.RefPos = 0 301 | prcopt.RovPos = 0 302 | gnssgo.MatCpy(prcopt.Ru[:], prcopt.Rb[:], 3, 1) 303 | } 304 | if rpFlag.configured { 305 | for j = 0; j < 2; j++ { 306 | pos[j] *= gnssgo.D2R 307 | } 308 | gnssgo.Pos2Ecef(pos[:], prcopt.Rb[:]) 309 | gnssgo.MatCpy(prcopt.Ru[:], prcopt.Rb[:], 3, 1) 310 | } 311 | infiles = flag.CommandLine.Args() 312 | if n = len(infiles); n < 1 { 313 | return 314 | } 315 | if prcopt.NavSys == 0 { 316 | prcopt.NavSys = gnssgo.SYS_ALL 317 | } 318 | 319 | ret := gnssgo.PostPos(ts, te, tint, 0.0, &prcopt, &solopt, &filopt, infiles[:], n, &outfile, "", "") 320 | if ret == 0 { 321 | fmt.Printf("%40s\r", "") 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /app/rtkrcv/conf/rtk.conf: -------------------------------------------------------------------------------- 1 | # RTKNAVI options (2016/09/19 07:28:53, v.2.4.3 b24) 2 | 3 | console-passwd =admin 4 | console-timetype =gpst # (0:gpst,1:utc,2:jst,3:tow) 5 | console-soltype =dms # (0:dms,1:deg,2:xyz,3:enu,4:pyl) 6 | console-solflag =1 # (0:off,1:std+2:age/ratio/ns) 7 | 8 | pos1-posmode =kinematic # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed) 9 | pos1-frequency =l1 # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l5) 10 | pos1-soltype =forward # (0:forward,1:backward,2:combined) 11 | pos1-elmask =20 # (deg) 12 | pos1-snrmask_r =off # (0:off,1:on) 13 | pos1-snrmask_b =off # (0:off,1:on) 14 | pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0 15 | pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0 16 | pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0 17 | pos1-dynamics =off # (0:off,1:on) 18 | pos1-tidecorr =off # (0:off,1:on,2:otl) 19 | pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:stec) 20 | pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad,5:ztd) 21 | pos1-sateph =brdc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom) 22 | pos1-posopt1 =on # (0:off,1:on) 23 | pos1-posopt2 =on # (0:off,1:on) 24 | pos1-posopt3 =on # (0:off,1:on,2:precise) 25 | pos1-posopt4 =on # (0:off,1:on) 26 | pos1-posopt5 =on # (0:off,1:on) 27 | pos1-posopt6 =off # (0:off,1:on) 28 | pos1-exclsats =C02 # (prn ...) 29 | pos1-navsys =61 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp) 30 | pos2-armode =fix-and-hold # (0:off,1:continuous,2:instantaneous,3:fix-and-hold) 31 | pos2-gloarmode =off # (0:off,1:on,2:autocal) 32 | pos2-bdsarmode =on # (0:off,1:on) 33 | pos2-arthres =3 34 | pos2-arthres1 =0.9999 35 | pos2-arthres2 =0.25 36 | pos2-arthres3 =0.1 37 | pos2-arthres4 =0.05 38 | pos2-arlockcnt =30 39 | pos2-arelmask =0 # (deg) 40 | pos2-arminfix =30 41 | pos2-armaxiter =1 42 | pos2-elmaskhold =0 # (deg) 43 | pos2-aroutcnt =30 44 | pos2-maxage =30 # (s) 45 | pos2-syncsol =off # (0:off,1:on) 46 | pos2-slipthres =0.05 # (m) 47 | pos2-rejionno =30 # (m) 48 | pos2-rejgdop =30 49 | pos2-niter =1 50 | pos2-baselen =0 # (m) 51 | pos2-basesig =0 # (m) 52 | out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea) 53 | out-outhead =off # (0:off,1:on) 54 | out-outopt =off # (0:off,1:on) 55 | out-timesys =jst # (0:gpst,1:utc,2:jst) 56 | out-timeform =hms # (0:tow,1:hms) 57 | out-timendec =3 58 | out-degform =dms # (0:deg,1:dms) 59 | out-fieldsep = 60 | out-outsingle =off # (0:off,1:on) 61 | out-maxsolstd =0 # (m) 62 | out-height =geodetic # (0:ellipsoidal,1:geodetic) 63 | out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000) 64 | out-solstatic =all # (0:all,1:single) 65 | out-nmeaintv1 =0 # (s) 66 | out-nmeaintv2 =0 # (s) 67 | out-outstat =off # (0:off,1:state,2:residual) 68 | stats-eratio1 =100 69 | stats-eratio2 =100 70 | stats-errphase =0.01 # (m) 71 | stats-errphaseel =0.01 # (m) 72 | stats-errphasebl =0 # (m/10km) 73 | stats-errdoppler =1 # (Hz) 74 | stats-stdbias =30 # (m) 75 | stats-stdiono =0.03 # (m) 76 | stats-stdtrop =0.3 # (m) 77 | stats-prnaccelh =10 # (m/s^2) 78 | stats-prnaccelv =10 # (m/s^2) 79 | stats-prnbias =0.0001 # (m) 80 | stats-prniono =0.001 # (m) 81 | stats-prntrop =0.0001 # (m) 82 | stats-prnpos =0 # (m) 83 | stats-clkstab =5e-12 # (s/s) 84 | ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) 85 | ant1-pos1 =90 # (deg|m) 86 | ant1-pos2 =0 # (deg|m) 87 | ant1-pos3 =-6335367.6285 # (m|m) 88 | ant1-anttype = 89 | ant1-antdele =0 # (m) 90 | ant1-antdeln =0 # (m) 91 | ant1-antdelu =0 # (m) 92 | ant2-postype =rtcm # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) 93 | ant2-pos1 =0 # (deg|m) 94 | ant2-pos2 =0 # (deg|m) 95 | ant2-pos3 =0 # (m|m) 96 | ant2-anttype = 97 | ant2-antdele =0 # (m) 98 | ant2-antdeln =0 # (m) 99 | ant2-antdelu =0 # (m) 100 | ant2-maxaveep =3600 101 | ant2-initrst =on # (0:off,1:on) 102 | misc-timeinterp =off # (0:off,1:on) 103 | misc-sbasatsel =0 # (0:all) 104 | misc-rnxopt1 = 105 | misc-rnxopt2 = 106 | misc-pppopt = 107 | file-satantfile = 108 | file-rcvantfile = 109 | file-staposfile = 110 | file-geoidfile = 111 | file-ionofile = 112 | file-dcbfile = 113 | file-eopfile = 114 | file-blqfile = 115 | file-tempdir = 116 | file-geexefile = 117 | file-solstatfile = 118 | file-tracefile = 119 | # 120 | 121 | inpstr1-type =tcpcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 122 | inpstr2-type =tcpcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 123 | inpstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 124 | inpstr1-path =:10008 125 | inpstr2-path =:10009 126 | inpstr3-path = 127 | inpstr1-format =ubx # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3) 128 | inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3) 129 | inpstr3-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3) 130 | inpstr2-nmeareq =off # (0:off,1:latlon,2:single) 131 | inpstr2-nmealat =0 # (deg) 132 | inpstr2-nmealon =0 # (deg) 133 | outstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 134 | outstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 135 | outstr1-path = 136 | outstr2-path = 137 | outstr1-format =llh # (0:llh,1:xyz,2:enu,3:nmea) 138 | outstr2-format =llh # (0:llh,1:xyz,2:enu,3:nmea) 139 | logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 140 | logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 141 | logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 142 | logstr1-path = 143 | logstr2-path = 144 | logstr3-path = 145 | misc-svrcycle =10 # (ms) 146 | misc-timeout =10000 # (ms) 147 | misc-reconnect =10000 # (ms) 148 | misc-nmeacycle =5000 # (ms) 149 | misc-buffsize =32768 # (bytes) 150 | misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr) 151 | misc-proxyaddr = 152 | misc-fswapmargin =30 # (s) 153 | -------------------------------------------------------------------------------- /app/rtkrcv/conf/single.conf: -------------------------------------------------------------------------------- 1 | # RTKNAVI options (2016/09/18 10:17:10, v.2.4.3 b24) 2 | 3 | console-passwd =admin 4 | console-timetype =gpst # (0:gpst,1:utc,2:jst,3:tow) 5 | console-soltype =dms # (0:dms,1:deg,2:xyz,3:enu,4:pyl) 6 | console-solflag =1 # (0:off,1:std+2:age/ratio/ns) 7 | 8 | pos1-posmode =single # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed) 9 | pos1-frequency =l1 # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l5) 10 | pos1-soltype =forward # (0:forward,1:backward,2:combined) 11 | pos1-elmask =15 # (deg) 12 | pos1-snrmask_r =off # (0:off,1:on) 13 | pos1-snrmask_b =off # (0:off,1:on) 14 | pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0 15 | pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0 16 | pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0 17 | pos1-dynamics =off # (0:off,1:on) 18 | pos1-tidecorr =off # (0:off,1:on,2:otl) 19 | pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:stec) 20 | pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad,5:ztd) 21 | pos1-sateph =brdc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom) 22 | pos1-posopt1 =on # (0:off,1:on) 23 | pos1-posopt2 =on # (0:off,1:on) 24 | pos1-posopt3 =on # (0:off,1:on,2:precise) 25 | pos1-posopt4 =on # (0:off,1:on) 26 | pos1-posopt5 =on # (0:off,1:on) 27 | pos1-posopt6 =off # (0:off,1:on) 28 | pos1-exclsats =C02 # (prn ...) 29 | pos1-navsys =61 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp) 30 | pos2-armode =continuous # (0:off,1:continuous,2:instantaneous,3:fix-and-hold) 31 | pos2-gloarmode =off # (0:off,1:on,2:autocal) 32 | pos2-bdsarmode =on # (0:off,1:on) 33 | pos2-arthres =3 34 | pos2-arthres1 =0.9999 35 | pos2-arthres2 =0.25 36 | pos2-arthres3 =0.1 37 | pos2-arthres4 =0.05 38 | pos2-arlockcnt =30 39 | pos2-arelmask =0 # (deg) 40 | pos2-arminfix =100 41 | pos2-armaxiter =1 42 | pos2-elmaskhold =0 # (deg) 43 | pos2-aroutcnt =30 44 | pos2-maxage =30 # (s) 45 | pos2-syncsol =off # (0:off,1:on) 46 | pos2-slipthres =0.05 # (m) 47 | pos2-rejionno =30 # (m) 48 | pos2-rejgdop =30 49 | pos2-niter =1 50 | pos2-baselen =0 # (m) 51 | pos2-basesig =0 # (m) 52 | out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea) 53 | out-outhead =off # (0:off,1:on) 54 | out-outopt =off # (0:off,1:on) 55 | out-timesys =jst # (0:gpst,1:utc,2:jst) 56 | out-timeform =hms # (0:tow,1:hms) 57 | out-timendec =3 58 | out-degform =dms # (0:deg,1:dms) 59 | out-fieldsep = 60 | out-outsingle =off # (0:off,1:on) 61 | out-maxsolstd =0 # (m) 62 | out-height =geodetic # (0:ellipsoidal,1:geodetic) 63 | out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000) 64 | out-solstatic =all # (0:all,1:single) 65 | out-nmeaintv1 =0 # (s) 66 | out-nmeaintv2 =0 # (s) 67 | out-outstat =off # (0:off,1:state,2:residual) 68 | stats-eratio1 =100 69 | stats-eratio2 =100 70 | stats-errphase =0.01 # (m) 71 | stats-errphaseel =0.01 # (m) 72 | stats-errphasebl =0 # (m/10km) 73 | stats-errdoppler =1 # (Hz) 74 | stats-stdbias =30 # (m) 75 | stats-stdiono =0.03 # (m) 76 | stats-stdtrop =0.3 # (m) 77 | stats-prnaccelh =10 # (m/s^2) 78 | stats-prnaccelv =10 # (m/s^2) 79 | stats-prnbias =0.0001 # (m) 80 | stats-prniono =0.001 # (m) 81 | stats-prntrop =0.0001 # (m) 82 | stats-prnpos =0 # (m) 83 | stats-clkstab =5e-12 # (s/s) 84 | ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) 85 | ant1-pos1 =90 # (deg|m) 86 | ant1-pos2 =0 # (deg|m) 87 | ant1-pos3 =-6335367.6285 # (m|m) 88 | ant1-anttype = 89 | ant1-antdele =0 # (m) 90 | ant1-antdeln =0 # (m) 91 | ant1-antdelu =0 # (m) 92 | ant2-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) 93 | ant2-pos1 =35.8729894219997 # (deg|m) 94 | ant2-pos2 =138.389669681 # (deg|m) 95 | ant2-pos3 =1003.95090000026 # (m|m) 96 | ant2-anttype = 97 | ant2-antdele =0 # (m) 98 | ant2-antdeln =0 # (m) 99 | ant2-antdelu =0 # (m) 100 | ant2-maxaveep =3600 101 | ant2-initrst =on # (0:off,1:on) 102 | misc-timeinterp =off # (0:off,1:on) 103 | misc-sbasatsel =0 # (0:all) 104 | misc-rnxopt1 = 105 | misc-rnxopt2 = 106 | misc-pppopt = 107 | file-satantfile = 108 | file-rcvantfile = 109 | file-staposfile = 110 | file-geoidfile = 111 | file-ionofile = 112 | file-dcbfile = 113 | file-eopfile = 114 | file-blqfile = 115 | file-tempdir = 116 | file-geexefile = 117 | file-solstatfile = 118 | file-tracefile = 119 | # 120 | 121 | inpstr1-type =tcpcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 122 | inpstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 123 | inpstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 124 | inpstr1-path =192.168.0.11:10008 125 | inpstr2-path = 126 | inpstr3-path = 127 | inpstr1-format =ubx # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3) 128 | inpstr2-format =ubx # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3) 129 | inpstr3-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,17:sp3) 130 | inpstr2-nmeareq =off # (0:off,1:latlon,2:single) 131 | inpstr2-nmealat =0 # (deg) 132 | inpstr2-nmealon =0 # (deg) 133 | outstr1-type =tcpsvr # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 134 | outstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 135 | outstr1-path =:10009/ 136 | outstr2-path = 137 | outstr1-format =llh # (0:llh,1:xyz,2:enu,3:nmea) 138 | outstr2-format =llh # (0:llh,1:xyz,2:enu,3:nmea) 139 | logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 140 | logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 141 | logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 142 | logstr1-path = 143 | logstr2-path = 144 | logstr3-path = 145 | misc-svrcycle =10 # (ms) 146 | misc-timeout =10000 # (ms) 147 | misc-reconnect =10000 # (ms) 148 | misc-nmeacycle =5000 # (ms) 149 | misc-buffsize =32768 # (bytes) 150 | misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr) 151 | misc-proxyaddr = 152 | misc-fswapmargin =30 # (s) 153 | -------------------------------------------------------------------------------- /app/rtkrcv/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo_app 2 | 3 | go 1.18 4 | 5 | require github.com/influxdata/influxdb-client-go/v2 v2.9.1 6 | 7 | require ( 8 | github.com/ClickHouse/clickhouse-go/v2 v2.2.0 // indirect 9 | github.com/go-stack/stack v1.8.0 // indirect 10 | github.com/golang/snappy v0.0.1 // indirect 11 | github.com/hashicorp/go-version v1.6.0 // indirect 12 | github.com/jinzhu/inflection v1.0.0 // indirect 13 | github.com/jinzhu/now v1.1.5 // indirect 14 | github.com/josharian/intern v1.0.0 // indirect 15 | github.com/klauspost/compress v1.13.6 // indirect 16 | github.com/mailru/easyjson v0.7.7 // indirect 17 | github.com/olivere/elastic/v7 v7.0.32 // indirect 18 | github.com/paulmach/orb v0.7.1 // indirect 19 | github.com/pierrec/lz4/v4 v4.1.15 // indirect 20 | github.com/shopspring/decimal v1.3.1 // indirect 21 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect 22 | github.com/xdg-go/scram v1.0.2 // indirect 23 | github.com/xdg-go/stringprep v1.0.2 // indirect 24 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect 25 | go.opentelemetry.io/otel v1.7.0 // indirect 26 | go.opentelemetry.io/otel/trace v1.7.0 // indirect 27 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect 28 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect 29 | golang.org/x/text v0.3.5 // indirect 30 | gorm.io/gorm v1.23.7 // indirect 31 | ) 32 | 33 | require ( 34 | github.com/deepmap/oapi-codegen v1.8.2 // indirect 35 | github.com/google/uuid v1.3.0 36 | github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect 37 | github.com/jmoiron/sqlx v1.3.5 38 | github.com/pkg/errors v0.9.1 // indirect 39 | go.mongodb.org/mongo-driver v1.9.1 40 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect 41 | gopkg.in/olivere/elastic.v5 v5.0.86 42 | gopkg.in/yaml.v2 v2.3.0 // indirect 43 | gorm.io/driver/clickhouse v0.4.2 44 | ) 45 | -------------------------------------------------------------------------------- /app/rtkrcv/rtkrcv.conf: -------------------------------------------------------------------------------- 1 | # rtkrcv options (2010/08/12 07:12:16, v.2.4.0) 2 | 3 | console-passwd =admin 4 | console-timetype =gpst # (0:gpst,1:utc,2:jst,3:tow) 5 | console-soltype =dms # (0:dms,1:deg,2:xyz,3:enu,4:pyl) 6 | console-solflag =1 # (0:off,1:std+2:age/ratio/ns) 7 | inpstr1-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 8 | inpstr2-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 9 | inpstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) 10 | inpstr1-path =amourleung:oicq2345@ntrip.gnsslab.cn/WSRT00NLD0 11 | inpstr2-path =amourleung:oicq2345@ntrip.gnsslab.cn/RTCM3EPH-MGEX 12 | inpstr3-path =anonymous:passwd@cddis.gsfc.nasa.gov/gps/products/%W/igu%W%D_%hb.sp3.Z::T=-14400,21600,7200,600 13 | inpstr1-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,14:sp3) 14 | inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,14:sp3) 15 | inpstr3-format =sp3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,14:sp3) 16 | inpstr2-nmeareq =off # (0:off,1:latlon,2:single) 17 | inpstr2-nmealat =0 # (deg) 18 | inpstr2-nmealon =0 # (deg) 19 | outstr1-type =file # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 20 | outstr2-type =file # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 21 | outstr1-path =sol1_%Y%m%d%h%M.pos 22 | outstr2-path =sol2_%Y%m%d%h%M.pos 23 | outstr1-format =llh # (0:llh,1:xyz,2:enu,3:nmea) 24 | outstr2-format =nmea # (0:llh,1:xyz,2:enu,3:nmea) 25 | logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 26 | logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 27 | logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) 28 | logstr1-path =rov_%Y%m%d%h%M.log 29 | logstr2-path =ref_%Y%m%d%h%M.log 30 | logstr3-path =cor_%Y%m%d%h%M.log 31 | misc-svrcycle =10 # (ms) 32 | misc-timeout =30000 # (ms) 33 | misc-reconnect =3000 # (ms) 34 | misc-nmeacycle =5000 # (ms) 35 | misc-buffsize =32768 # (bytes) 36 | misc-navmsgsel =all # (0:all,1:rover,1:base,2:corr) 37 | misc-startcmd = 38 | misc-stopcmd = 39 | file-cmdfile1 = 40 | file-cmdfile2 = 41 | file-cmdfile3 = 42 | pos1-posmode =single # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static) 43 | pos1-frequency =l1 # (1:l1,2:l1+l2,3:l1+l2+l5) 44 | pos1-soltype =forward # (0:forward,1:backward,2:combined) 45 | pos1-elmask =15 # (deg) 46 | pos1-snrmask =0 # (dBHz) 47 | pos1-dynamics =off # (0:off,1:on) 48 | pos1-tidecorr =off # (0:off,1:on) 49 | pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec) 50 | pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad) 51 | pos1-sateph =brdc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom) 52 | pos1-exclsats = # (prn ...) 53 | pos1-navsys =33 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp) 54 | pos2-armode =off # (0:off,1:continuous,2:instantaneous,3:fix-and-hold) 55 | pos2-gloarmode =off # (0:off,1:on,2:autocal) 56 | pos2-arthres =5 57 | pos2-arlockcnt =0 58 | pos2-arelmask =0 # (deg) 59 | pos2-aroutcnt =5 60 | pos2-arminfix =10 61 | pos2-slipthres =0.05 # (m) 62 | pos2-maxage =30 # (s) 63 | pos2-rejionno =30 # (m) 64 | pos2-niter =1 65 | pos2-baselen =0 # (m) 66 | pos2-basesig =0 # (m) 67 | out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea) 68 | out-outhead =on # (0:off,1:on) 69 | out-outopt =on # (0:off,1:on) 70 | out-timesys =gpst # (0:gpst,1:utc,2:jst) 71 | out-timeform =hms # (0:tow,1:hms) 72 | out-timendec =3 73 | out-degform =deg # (0:deg,1:dms) 74 | out-fieldsep = 75 | out-height =ellipsoidal # (0:ellipsoidal,1:geodetic) 76 | out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000) 77 | out-solstatic =all # (0:all,1:single) 78 | out-nmeaintv1 =0 # (s) 79 | out-nmeaintv2 =0 # (s) 80 | out-outstat =off # (0:off,1:state,2:residual) 81 | stats-errratio =100 82 | stats-errphase =0.003 # (m) 83 | stats-errphaseel =0.003 # (m) 84 | stats-errphasebl =0 # (m/10km) 85 | stats-errdoppler =1 # (Hz) 86 | stats-stdbias =30 # (m) 87 | stats-stdiono =0.03 # (m) 88 | stats-stdtrop =0.3 # (m) 89 | stats-prnaccelh =1 # (m/s^2) 90 | stats-prnaccelv =0.1 # (m/s^2) 91 | stats-prnbias =0.0001 # (m) 92 | stats-prniono =0.001 # (m) 93 | stats-prntrop =0.0001 # (m) 94 | stats-clkstab =5e-12 # (s/s) 95 | ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm) 96 | ant1-pos1 =0 # (deg|m) 97 | ant1-pos2 =0 # (deg|m) 98 | ant1-pos3 =0 # (m|m) 99 | ant1-anttype = 100 | ant1-antdele =0 # (m) 101 | ant1-antdeln =0 # (m) 102 | ant1-antdelu =0 # (m) 103 | ant2-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm) 104 | ant2-pos1 =0 # (deg|m) 105 | ant2-pos2 =0 # (deg|m) 106 | ant2-pos3 =0 # (m|m) 107 | ant2-anttype = 108 | ant2-antdele =0 # (m) 109 | ant2-antdeln =0 # (m) 110 | ant2-antdelu =0 # (m) 111 | misc-timeinterp =off # (0:off,1:on) 112 | misc-sbasatsel =0 # (0:all) 113 | file-satantfile = 114 | file-rcvantfile = 115 | file-staposfile = 116 | file-geoidfile = 117 | file-dcbfile = 118 | file-tempdir =temp 119 | file-geexefile = 120 | file-solstatfile = 121 | file-tracefile = 122 | -------------------------------------------------------------------------------- /app/rtkrcv/rtkrcv_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtkrcv.c : rtk-gps/gnss receiver console ap 3 | * 4 | * Copyright (C) 2009-2015 by T.TAKASU, All rights reserved. 5 | * 6 | * notes : 7 | * current version does not support win32 without pthread library 8 | * 9 | * version : $Revision:$ $Date:$ 10 | * history : 2009/12/13 1.0 new 11 | * 2010/07/18 1.1 add option -m 12 | * 2010/08/12 1.2 fix bug on ftp/http 13 | * 2011/01/22 1.3 add option misc-proxyaddr,misc-fswapmargin 14 | * 2011/08/19 1.4 fix bug on size of arg solopt arg for rtksvrstart() 15 | * 2012/11/03 1.5 fix bug on setting output format 16 | * 2013/06/30 1.6 add "nvs" option for inpstr*-format 17 | * 2014/02/10 1.7 fix bug on printing obs data 18 | * add print of status, glonass nav data 19 | * ignore SIGHUP 20 | * 2014/04/27 1.8 add "binex" option for inpstr*-format 21 | * 2014/08/10 1.9 fix cpu overload with abnormal telnet shutdown 22 | * 2014/08/26 1.10 support input format "rt17" 23 | * change file paths of solution status and debug trace 24 | * 2015/01/10 1.11 add line editting and command history 25 | * separate codes for virtual console to vt.c 26 | * 2015/05/22 1.12 fix bug on sp3 id in inpstr*-format options 27 | * 2015/07/31 1.13 accept 4:stat for outstr1-format or outstr2-format 28 | * add reading satellite dcb 29 | * 2015/12/14 1.14 add option -sta for station name (#339) 30 | * 2015/12/25 1.15 fix bug on -sta option (#339) 31 | * 2015/01/26 1.16 support septentrio 32 | * 2016/07/01 1.17 support CMR/CMR+ 33 | * 2016/08/20 1.18 add output of patch level with version 34 | * 2016/09/05 1.19 support ntrip caster for output stream 35 | * 2016/09/19 1.20 support multiple remote console connections 36 | * add option -w 37 | * 2017/09/01 1.21 add command ssr 38 | *-----------------------------------------------------------------------------*/ 39 | 40 | package main 41 | 42 | import "testing" 43 | 44 | func Test_prstatus(t *testing.T) { 45 | type args struct { 46 | vt *VTerm 47 | } 48 | tests := []struct { 49 | name string 50 | args args 51 | }{ 52 | // TODO: Add test cases. 53 | } 54 | for _, tt := range tests { 55 | t.Run(tt.name, func(t *testing.T) { 56 | prstatus(tt.args.vt) 57 | }) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/str2str/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo_app 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /app/str2str/oem6_20121107.rtcm3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengXuebin/gnssgo/fddcd58a3beb5f41ff0cfe5ab3bd8a1b9e85a212/app/str2str/oem6_20121107.rtcm3 -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 3 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 4 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 5 | github.com/tarm/goserial v0.0.0-20151007205400-b3440c3c6355 h1:Kp3kg8YL2dc75mckomrHZQTfzNyFGnaqFhJeQw4ozGc= 6 | github.com/tarm/goserial v0.0.0-20151007205400-b3440c3c6355/go.mod h1:jcMo2Odv5FpDA6rp8bnczbUolcICW6t54K3s9gOlgII= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 8 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 9 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.18 2 | 3 | use ( 4 | ./src 5 | // ./app/rnx2rtkp 6 | // ./unittest 7 | // ./app/rtkrcv 8 | // ./app/str2str 9 | ./app/convbin 10 | // ./app/plot 11 | // ./app/pos2kml 12 | ) 13 | -------------------------------------------------------------------------------- /go.work.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= 5 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 6 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 7 | github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= 8 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= 9 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= 10 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 11 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 2 | # gnssgo 1.0 3 | # 4 | 5 | # DESCRIPTION 6 | 7 | The development branch for golang version of RTKLIB 2.4.3. 8 | 9 | RTKLIB is an excellent tool for GNSS development and research. Golang became population in recent. According to requirement of project, I recoded RTKLIB with golang for almost one years. 10 | 11 | Due to limitation of commit folder size, I didn't commit data files. If you want to test the project, you could download from RTKLIB. 12 | 13 | Author: Dr. Feng Xuebin, Explore Data Technology (Shenzhen) Ltd., co 14 | 15 | # UPDATE HISTORY 16 | 17 | 2023/06/06 1.0 18 | 19 | # Build and Installation 20 | In file 'go.work', you could choose your app by uncommenting app path. 21 | 22 | For configuring app, you could define command line arguments in file 'luanch.json' under directory .vscode. 23 | -------------------------------------------------------------------------------- /src/clickhouse.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS gnss 2 | 3 | clickhouse-client --query "CREATE TABLE gnss.obs 4 | ( 5 | `Time` DateTime COMMENT '时间', 6 | `Sat` Int32 COMMENT '卫星号', 7 | `Rcv` Int32 COMMENT '接收机号', 8 | `SNR` UInt16 COMMENT '信噪比', 9 | `LLI` UInt8 COMMENT 'loss of lock indicator', 10 | `Code` UInt8 COMMENT 'code indicator', 11 | `L` Float64 COMMENT 'observation data carrier-phase', 12 | `P` String COMMENT 'observation data pseudorange (m)', 13 | `D` String COMMENT 'observation data doppler frequency (Hz)', 14 | )" 15 | -------------------------------------------------------------------------------- /src/convgpx.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * convgpx.c : gpx converter 3 | * 4 | * Copyright (C) 2016 by T.TAKASU, All rights reserved. 5 | * 6 | * references : 7 | * [1] GPX The GPS Exchange Format http://www.topografix.com/gpx.asp 8 | * 9 | * version : $Revision:$ $Date:$ 10 | * history : 2016/06/11 1.0 new 11 | * 2016/09/18 1.1 modify labels according GPX specs 12 | * 2022/05/31 1.0 rewrite convgpx.c with golang by fxb 13 | *-----------------------------------------------------------------------------*/ 14 | 15 | package gnssgo 16 | 17 | import ( 18 | "fmt" 19 | "os" 20 | "strings" 21 | ) 22 | 23 | const HEADXML string = "\n" 24 | const HEADGPX string = "\n" 25 | const TAILGPX string = "" 26 | 27 | const XMLNS string = "http://www.topografix.com/GPX/1/1" 28 | 29 | /* output waypoint -----------------------------------------------------------*/ 30 | func OutPoint(fp *os.File, time Gtime, pos []float64, label string, stat, outalt, outtime int) { 31 | /* fix, float, sbas and ppp are rtklib extentions to GPX */ 32 | var ( 33 | fix_label = []string{"fix", "float", "sbas", "dgps", "3d", "ppp"} 34 | ep [6]float64 35 | ) 36 | 37 | fp.WriteString(fmt.Sprintf("\n", pos[0]*R2D, pos[1]*R2D)) 38 | if outalt > 0 { 39 | var tmp float64 40 | if outalt == 2 { 41 | tmp = GeoidH(pos) 42 | } 43 | fp.WriteString(fmt.Sprintf(" %.4f\n", pos[2]-tmp)) 44 | } 45 | if outtime > 0 { 46 | if outtime == 2 { 47 | time = GpsT2Utc(time) 48 | } else if outtime == 3 { 49 | time = TimeAdd(GpsT2Utc(time), 9*3600.0) 50 | } 51 | Time2Epoch(time, ep[:]) 52 | fp.WriteString(fmt.Sprintf(" \n", 53 | ep[0], ep[1], ep[2], ep[3], ep[4], ep[5])) 54 | } 55 | if outalt == 2 { 56 | fp.WriteString(fmt.Sprintf(" %.4f\n", GeoidH(pos))) 57 | } 58 | if stat >= 1 && stat <= 6 { 59 | fp.WriteString(fmt.Sprintf(" %s\n", fix_label[stat-1])) 60 | } 61 | 62 | fp.WriteString(fmt.Sprintf(" %s\n", label)) 63 | 64 | fp.WriteString("\n") 65 | } 66 | 67 | /* output track --------------------------------------------------------------*/ 68 | func OutTrack(fp *os.File, solbuf *SolBuf, outalt, outtime int) { 69 | var ( 70 | time Gtime 71 | pos [3]float64 72 | ep [6]float64 73 | i int 74 | ) 75 | 76 | fp.WriteString("\n") 77 | fp.WriteString(" \n") 78 | for i = 0; i < solbuf.N; i++ { 79 | Ecef2Pos(solbuf.Data[i].Rr[:], pos[:]) 80 | fp.WriteString(fmt.Sprintf(" \n", pos[0]*R2D, 81 | pos[1]*R2D)) 82 | if outalt > 0 { 83 | var tmp float64 = 0.0 84 | if outalt == 2 { 85 | tmp = GeoidH(pos[:]) 86 | } 87 | fp.WriteString(fmt.Sprintf(" %.4f\n", pos[2]-tmp)) 88 | } 89 | if outtime > 0 { 90 | time = solbuf.Data[i].Time 91 | if outtime == 2 { 92 | time = GpsT2Utc(time) 93 | } else if outtime == 3 { 94 | time = TimeAdd(GpsT2Utc(time), 9*3600.0) 95 | } 96 | Time2Epoch(time, ep[:]) 97 | fp.WriteString(fmt.Sprintf(" \n", 98 | ep[0], ep[1], ep[2], ep[3], ep[4], ep[5])) 99 | } 100 | if outalt == 2 { 101 | fp.WriteString(fmt.Sprintf(" %.4f\n", GeoidH(pos[:]))) 102 | } 103 | fp.WriteString(" \n") 104 | } 105 | fp.WriteString(" \n") 106 | fp.WriteString("\n") 107 | } 108 | 109 | /* save gpx file -------------------------------------------------------------*/ 110 | func SaveGpx(file string, solbuf *SolBuf, outtrk, outpnt, outalt, outtime int) int { 111 | var ( 112 | fp *os.File 113 | pos [3]float64 114 | i int 115 | err error 116 | ) 117 | fp, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModeAppend|os.ModePerm) 118 | if err != nil { 119 | Trace(2, "file open error : %s\n", file) 120 | return 0 121 | } 122 | defer fp.Close() 123 | 124 | fp.WriteString(HEADXML) 125 | fp.WriteString(fmt.Sprintf(HEADGPX, "gnssgo ", XMLNS)) 126 | 127 | /* output waypoint */ 128 | if outpnt > 0 { 129 | for i = 0; i < solbuf.N; i++ { 130 | Ecef2Pos(solbuf.Data[i].Rr[:], pos[:]) 131 | OutPoint(fp, solbuf.Data[i].Time, pos[:], "", int(solbuf.Data[i].Stat), outalt, 132 | outtime) 133 | } 134 | } 135 | /* output waypoint of ref position */ 136 | if Norm(solbuf.Rb[:], 3) > 0.0 { 137 | Ecef2Pos(solbuf.Rb[:], pos[:]) 138 | OutPoint(fp, solbuf.Data[0].Time, pos[:], "Reference Position", 0, outalt, 0) 139 | } 140 | /* output track */ 141 | if outtrk > 0 { 142 | OutTrack(fp, solbuf, outalt, outtime) 143 | } 144 | fp.WriteString(fmt.Sprintf("%s\n", TAILGPX)) 145 | 146 | return 1 147 | } 148 | 149 | /* convert to GPX file --------------------------------------------------------- 150 | * convert solutions to GPX file [1] 151 | * args : char *infile I input solutions file 152 | * char *outfile I output google earth kml file ("":.kml) 153 | * gtime_t ts,te I start/end time (gpst) 154 | * int tint I time interval (s) (0.0:all) 155 | * int qflg I quality flag (0:all) 156 | * double *offset I add offset {east,north,up} (m) 157 | * int outtrk I output track (0:off,1:on) 158 | * int outpnt I output waypoint (0:off,1:on) 159 | * int outalt I output altitude (0:off,1:elipsoidal,2:geodetic) 160 | * int outtime I output time (0:off,1:gpst,2:utc,3:jst) 161 | * return : status (0:ok,-1:file read,-2:file format,-3:no data,-4:file write) 162 | *-----------------------------------------------------------------------------*/ 163 | func ConvGpx(infile, outfile string, ts, te Gtime, tint float64, qflg int, offset []float64, 164 | outtrk, outpnt, outalt, outtime int) int { 165 | var ( 166 | solbuf SolBuf 167 | rr, pos, dr [3]float64 168 | i, j int 169 | file string 170 | ) 171 | 172 | Trace(4, "convgpx : infile=%s outfile=%s\n", infile, outfile) 173 | if len(outfile) == 0 { 174 | index := strings.LastIndex(infile, ".") 175 | if index > 0 { 176 | file = infile[:index] 177 | } 178 | file += ".gpx" 179 | } else { 180 | file = outfile 181 | } 182 | 183 | var files []string = []string{infile} 184 | /* read solution file */ 185 | if ReadSolt(files, 1, ts, te, tint, qflg, &solbuf) == 0 { 186 | return -1 187 | } 188 | 189 | /* mean position */ 190 | for i = 0; i < 3; i++ { 191 | for j = 0; j < solbuf.N; j++ { 192 | rr[i] += solbuf.Data[j].Rr[i] 193 | } 194 | rr[i] /= float64(solbuf.N) 195 | } 196 | /* add offset */ 197 | Ecef2Pos(rr[:], pos[:]) 198 | Enu2Ecef(pos[:], offset, dr[:]) 199 | for i = 0; i < solbuf.N; i++ { 200 | for j = 0; j < 3; j++ { 201 | solbuf.Data[i].Rr[j] += dr[j] 202 | } 203 | } 204 | if Norm(solbuf.Rb[:], 3) > 0.0 { 205 | for i = 0; i < 3; i++ { 206 | solbuf.Rb[i] += dr[i] 207 | } 208 | } 209 | /* save gpx file */ 210 | if SaveGpx(file, &solbuf, outtrk, outpnt, outalt, outtime) > 0 { 211 | return 0 212 | } else { 213 | return -4 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/convkml.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * convkml.c : google earth kml converter 3 | * 4 | * Copyright (C) 2007-2017 by T.TAKASU, All rights reserved. 5 | * 6 | * references : 7 | * [1] Open Geospatial Consortium Inc., OGC 07-147r2, OGC(R) KML, 2008-04-14 8 | * 9 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:48:06 $ 10 | * history : 2007/01/20 1.0 new 11 | * 2007/03/15 1.1 modify color sequence 12 | * 2007/04/03 1.2 add geodetic height option 13 | * support input of NMEA GGA sentence 14 | * delete altitude info for track 15 | * add time stamp option 16 | * separate readsol.c file 17 | * 2009/01/19 1.3 fix bug on display mark with by-q-flag option 18 | * 2010/05/10 1.4 support api readsolt() change 19 | * 2010/08/14 1.5 fix bug on readsolt() (2.4.0_p3) 20 | * 2017/06/10 1.6 support wild-card in input file 21 | * 2022/05/31 1.0 rewrite convkml.c with golang by fxb 22 | *-----------------------------------------------------------------------------*/ 23 | 24 | package gnssgo 25 | 26 | import ( 27 | "fmt" 28 | "math" 29 | "os" 30 | "strings" 31 | ) 32 | 33 | /* constants -----------------------------------------------------------------*/ 34 | 35 | const ( 36 | SIZP = 0.2 /* mark size of rover positions */ 37 | SIZR = 0.3 /* mark size of reference position */ 38 | TINT = 60.0 /* time label interval (sec) */ 39 | 40 | head1 = "" 41 | head2 = "" 42 | mark = "http://maps.google.com/mapfiles/kml/pal2/icon18.png" 43 | ) 44 | 45 | /* output track --------------------------------------------------------------*/ 46 | func OutTrackKml(f *os.File, solbuf *SolBuf, color string, outalt, outtime int) { 47 | var pos [3]float64 48 | 49 | f.WriteString("\n") 50 | f.WriteString("Rover Track\n") 51 | f.WriteString("\n") 56 | f.WriteString("\n") 57 | if outalt > 0 { 58 | f.WriteString("absolute\n") 59 | } 60 | f.WriteString("\n") 61 | for i := 0; i < solbuf.N; i++ { 62 | Ecef2Pos(solbuf.Data[i].Rr[:], pos[:]) 63 | if outalt == 0 { 64 | pos[2] = 0.0 65 | } else if outalt == 2 { 66 | pos[2] -= GeoidH(pos[:]) 67 | } 68 | f.WriteString(fmt.Sprintf("%13.9f,%12.9f,%5.3f\n", pos[1]*R2D, pos[0]*R2D, pos[2])) 69 | } 70 | f.WriteString("\n") 71 | f.WriteString("\n") 72 | f.WriteString("\n") 73 | } 74 | 75 | /* output point --------------------------------------------------------------*/ 76 | func OutPointKml(fp *os.File, time Gtime, pos []float64, label string, style, outalt, outtime int) { 77 | var ( 78 | ep [6]float64 79 | alt float64 = 0.0 80 | str string 81 | ) 82 | 83 | fp.WriteString("\n") 84 | if label != "" { 85 | fp.WriteString(fmt.Sprintf("%s\n", label)) 86 | } 87 | fp.WriteString(fmt.Sprintf("#P%d\n", style)) 88 | if outtime > 0 { 89 | if outtime == 2 { 90 | time = GpsT2Utc(time) 91 | } else if outtime == 3 { 92 | time = TimeAdd(GpsT2Utc(time), 9*3600.0) 93 | } 94 | Time2Epoch(time, ep[:]) 95 | if !(len(label) == 0 && math.Mod(ep[5]+0.005, TINT) < 0.01) { 96 | str = fmt.Sprintf("%02.0f:%02.0f", ep[3], ep[4]) 97 | fp.WriteString(fmt.Sprintf("%s\n", str)) 98 | } 99 | str = fmt.Sprintf("%04.0f-%02.0f-%02.0fT%02.0f:%02.0f:%05.2fZ", 100 | ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]) 101 | fp.WriteString(fmt.Sprintf("%s\n", str)) 102 | } 103 | fp.WriteString("\n") 104 | if outalt > 0 { 105 | fp.WriteString("1\n") 106 | fp.WriteString("absolute\n") 107 | alt = pos[2] 108 | if outalt == 2 { 109 | alt -= GeoidH(pos) 110 | } 111 | } 112 | fp.WriteString(fmt.Sprintf("%13.9f,%12.9f,%5.3f\n", pos[1]*R2D, 113 | pos[0]*R2D, alt)) 114 | fp.WriteString("\n") 115 | fp.WriteString("\n") 116 | } 117 | 118 | /* save kml file -------------------------------------------------------------*/ 119 | func SaveKml(file string, solbuf *SolBuf, tcolor, pcolor, outalt, outtime int) int { 120 | var ( 121 | pos [3]float64 122 | qcolor []int = []int{0, 1, 2, 5, 4, 3, 0} 123 | color []string = []string{ 124 | "ffffffff", "ff008800", "ff00aaff", "ff0000ff", "ff00ffff", "ffff00ff"} 125 | ) 126 | 127 | fp, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModeAppend|os.ModePerm) 128 | if err != nil { 129 | Trace(2, "file open error : %s\n", file) 130 | return 0 131 | } 132 | defer fp.Close() 133 | 134 | fp.WriteString(fmt.Sprintf("%s\n%s\n", head1, head2)) 135 | fp.WriteString("\n") 136 | for i := 0; i < 6; i++ { 137 | fp.WriteString(fmt.Sprintf("\n") 148 | } 149 | if tcolor > 0 { 150 | OutTrackKml(fp, solbuf, color[tcolor-1], outalt, outtime) 151 | } 152 | if pcolor > 0 { 153 | fp.WriteString("\n") 154 | fp.WriteString(" Rover Position\n") 155 | for i := 0; i < solbuf.N; i++ { 156 | Ecef2Pos(solbuf.Data[i].Rr[:], pos[:]) 157 | if pcolor == 5 { 158 | OutPointKml(fp, solbuf.Data[i].Time, pos[:], "", 159 | qcolor[solbuf.Data[i].Stat], outalt, outtime) 160 | } else { 161 | OutPointKml(fp, solbuf.Data[i].Time, pos[:], "", 162 | pcolor-1, outalt, outtime) 163 | } 164 | } 165 | fp.WriteString("\n") 166 | } 167 | if Norm(solbuf.Rb[:], 3) > 0.0 { 168 | Ecef2Pos(solbuf.Rb[:], pos[:]) 169 | OutPointKml(fp, solbuf.Data[0].Time, pos[:], "Reference Position", 0, outalt, 0) 170 | } 171 | fp.WriteString("\n") 172 | fp.WriteString("\n") 173 | 174 | return 1 175 | } 176 | 177 | /* convert to google earth kml file -------------------------------------------- 178 | * convert solutions to google earth kml file 179 | * args : char *infile I input solutions file (wild-card (*) is expanded) 180 | * char *outfile I output google earth kml file ("":.kml) 181 | * gtime_t ts,te I start/end time (gpst) 182 | * int tint I time interval (s) (0.0:all) 183 | * int qflg I quality flag (0:all) 184 | * double *offset I add offset {east,north,up} (m) 185 | * int tcolor I track color 186 | * (0:none,1:white,2:green,3:orange,4:red,5:yellow) 187 | * int pcolor I point color 188 | * (0:none,1:white,2:green,3:orange,4:red,5:by qflag) 189 | * int outalt I output altitude (0:off,1:elipsoidal,2:geodetic) 190 | * int outtime I output time (0:off,1:gpst,2:utc,3:jst) 191 | * return : status (0:ok,-1:file read,-2:file format,-3:no data,-4:file write) 192 | * notes : see ref [1] for google earth kml file format 193 | *-----------------------------------------------------------------------------*/ 194 | func ConvKml(infile, outfile string, ts, te Gtime, tint float64, qflg int, offset []float64, 195 | tcolor, pcolor, outalt, outtime int) int { 196 | var ( 197 | solbuf SolBuf 198 | rr, pos, dr [3]float64 199 | i, j, nfile, stat, index int 200 | files []string = make([]string, MAXEXFILE) 201 | file string 202 | ) 203 | 204 | Trace(4, "convkml : infile=%s outfile=%s\n", infile, outfile) 205 | 206 | /* expand wild-card of infile */ 207 | 208 | if nfile = ExPath(infile, files, MAXEXFILE); nfile <= 0 { 209 | 210 | return -3 211 | } 212 | if len(outfile) == 0 { 213 | index = strings.LastIndex(infile, ".") 214 | if index >= 0 { 215 | file = infile[:index] 216 | file += ".kml" 217 | } else { 218 | file = fmt.Sprintf("%s.kml", infile) 219 | } 220 | 221 | } else { 222 | file = outfile 223 | } 224 | 225 | /* read solution file */ 226 | stat = ReadSolt(files, nfile, ts, te, tint, qflg, &solbuf) 227 | 228 | if stat == 0 { 229 | return -1 230 | } 231 | /* mean position */ 232 | for i = 0; i < 3; i++ { 233 | for j = 0; j < solbuf.N; j++ { 234 | rr[i] += solbuf.Data[j].Rr[i] 235 | } 236 | rr[i] /= float64(solbuf.N) 237 | } 238 | /* add offset */ 239 | Ecef2Pos(rr[:], pos[:]) 240 | Enu2Ecef(pos[:], offset, dr[:]) 241 | for i = 0; i < solbuf.N; i++ { 242 | for j = 0; j < 3; j++ { 243 | solbuf.Data[i].Rr[j] += dr[j] 244 | } 245 | } 246 | if Norm(solbuf.Rb[:], 3) > 0.0 { 247 | for i = 0; i < 3; i++ { 248 | solbuf.Rb[i] += dr[i] 249 | } 250 | } 251 | /* save kml file */ 252 | if SaveKml(file, &solbuf, tcolor, pcolor, outalt, outtime) > 0 { 253 | return 0 254 | } 255 | return -4 256 | } 257 | -------------------------------------------------------------------------------- /src/datum.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * datum.c : datum transformation 3 | * 4 | * Copyright (C) 2007 by T.TAKASU, All rights reserved. 5 | * 6 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:48:06 $ 7 | * history : 2007/02/08 1.0 new 8 | * 2022/05/31 1.0 rewrite datum.c with golang by fxb 9 | *-----------------------------------------------------------------------------*/ 10 | package gnssgo 11 | 12 | import ( 13 | "bufio" 14 | "fmt" 15 | "io" 16 | "os" 17 | "sort" 18 | ) 19 | 20 | const MAXPRM = 400000 /* max number of parameter records */ 21 | 22 | type Tprm struct { /* datum trans parameter type */ 23 | code int /* mesh code */ 24 | db, dl float32 /* difference of latitude/longitude (sec) */ 25 | } 26 | 27 | var prm []Tprm = nil /* datum trans parameter table */ 28 | var prm_n int = 0 /* datum trans parameter table size */ 29 | /* compare datum trans parameters --------------------------------------------*/ 30 | // func cmpprm(const void *p1, const void *p2)int 31 | // { 32 | // tprm_t *q1=(tprm_t *)p1,*q2=(tprm_t *)p2; 33 | // return q1->code-q2->code; 34 | // } 35 | 36 | /* search datum trans parameter ----------------------------------------------*/ 37 | func SearchPrm(lat, lon float64) int { 38 | var i, j, k, n1, m1, n2, m2, code int 39 | 40 | lon -= 6000.0 41 | n1 = int(lat / 40.0) 42 | lat -= float64(n1) * 40.0 43 | m1 = int(lon / 60.0) 44 | lon -= float64(m1) * 60.0 45 | n2 = int(lat / 5.0) 46 | lat -= float64(n2) * 5.0 47 | m2 = int(lon / 7.5) 48 | lon -= float64(m2) * 7.5 49 | code = n1*1000000 + m1*10000 + n2*1000 + m2*100 + (int)(lat/0.5)*10 + (int)(lon/0.75) 50 | j = prm_n - 1 51 | for i = 0; i < j; { /* binary search */ 52 | k = (i + j) / 2 53 | if prm[k].code == code { 54 | return k 55 | } 56 | if prm[k].code < code { 57 | i = k + 1 58 | } else { 59 | j = k 60 | } 61 | } 62 | return -1 63 | } 64 | 65 | /* tokyo datum to jgd2000 lat/lon corrections --------------------------------*/ 66 | func DLatDLon(post, dpos []float64) int { 67 | var ( 68 | db, dl [2][2]float64 69 | a, b, c, d float64 70 | i, j, k int 71 | ) 72 | lat := post[0] * R2D * 60.0 73 | lon := post[1] * R2D * 60.0 /* arcmin */ 74 | dlat := 0.5 75 | dlon := 0.75 76 | 77 | if prm_n == 0 { 78 | return -1 79 | } 80 | for i = 0; i < 2; i++ { 81 | for j = 0; j < 2; j++ { 82 | if k = SearchPrm(lat+float64(i)*dlat, lon+float64(j)*dlon); k < 0 { 83 | return -1 84 | } 85 | db[i][j] = float64(prm[k].db) 86 | dl[i][j] = float64(prm[k].dl) 87 | } 88 | } 89 | a = lat/dlat - float64(int(lat/dlat)) 90 | c = 1.0 - a 91 | b = lon/dlon - float64(int(lon/dlon)) 92 | d = 1.0 - b 93 | dpos[0] = (db[0][0]*c*d + db[1][0]*a*d + db[0][1]*c*b + db[1][1]*a*b) * D2R / 3600.0 94 | dpos[1] = (dl[0][0]*c*d + dl[1][0]*a*d + dl[0][1]*c*b + dl[1][1]*a*b) * D2R / 3600.0 95 | return 0 96 | } 97 | 98 | /* load datum transformation parameter ----------------------------------------- 99 | * load datum transformation parameter 100 | * args : char *file I datum trans parameter file path 101 | * return : status (0:ok,0>:error) 102 | * notes : parameters file shall comply with GSI TKY2JGD.par 103 | *-----------------------------------------------------------------------------*/ 104 | func LoadDatumP(file string) int { 105 | var ( 106 | fp *os.File 107 | err error 108 | n int 109 | ) 110 | buff := make([]byte, 256) 111 | 112 | if prm_n > 0 { 113 | return 0 114 | } /* already loaded */ 115 | 116 | if fp, err = os.OpenFile(file, os.O_RDWR, 0666); err != nil { 117 | Trace(2, "datum.go: datum prm file open error : %s\n", file) 118 | return -1 119 | } 120 | defer fp.Close() 121 | prm = make([]Tprm, MAXPRM) 122 | for { 123 | rd := bufio.NewReader(fp) 124 | n, err = rd.Read(buff) 125 | if err != nil && err != io.EOF { 126 | Trace(2, "fail to read file") 127 | break 128 | } 129 | if n == 0 { 130 | break 131 | } 132 | if n, _ = fmt.Sscanf(string(buff), "%d %f %f", &prm[n].code, &prm[n].db, &prm[n].dl); n >= 3 { 133 | prm_n++ 134 | } 135 | } 136 | 137 | sort.Slice(prm, func(i, j int) bool { /* sort parameter table */ 138 | return prm[i].code < prm[j].code 139 | }) 140 | 141 | return 0 142 | } 143 | 144 | /* tokyo datum to JGD2000 datum ------------------------------------------------ 145 | * transform position in Tokyo datum to JGD2000 datum 146 | * args : double *pos I position in Tokyo datum {lat,lon,h} (rad,m) 147 | * O position in JGD2000 datum {lat,lon,h} (rad,m) 148 | * return : status (0:ok,0>:error,out of range) 149 | * notes : before calling, call loaddatump() to set parameter table 150 | *-----------------------------------------------------------------------------*/ 151 | func Tokyo2Jgd(pos []float64) int { 152 | var post, dpos [2]float64 153 | 154 | post[0] = pos[0] 155 | post[1] = pos[1] 156 | if DLatDLon(post[:], dpos[:]) > 0 { 157 | return -1 158 | } 159 | pos[0] = post[0] + dpos[0] 160 | pos[1] = post[1] + dpos[1] 161 | return 0 162 | } 163 | 164 | /* JGD2000 datum to Tokyo datum ------------------------------------------------ 165 | * transform position in JGD2000 datum to Tokyo datum 166 | * args : double *pos I position in JGD2000 datum {lat,lon,h} (rad,m) 167 | * O position in Tokyo datum {lat,lon,h} (rad,m) 168 | * return : status (0:ok,0>:error,out of range) 169 | * notes : before calling, call loaddatump() to set parameter table 170 | *-----------------------------------------------------------------------------*/ 171 | func Jgd2Tokyo(pos []float64) int { 172 | var posj, dpos [2]float64 173 | 174 | posj[0] = pos[0] 175 | posj[1] = pos[1] 176 | for i := 0; i < 2; i++ { 177 | if DLatDLon(pos[:], dpos[:]) > 0 { 178 | return -1 179 | } 180 | pos[0] = posj[0] - dpos[0] 181 | pos[1] = posj[1] - dpos[1] 182 | } 183 | return 0 184 | } 185 | -------------------------------------------------------------------------------- /src/gis.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * gis.c: GIS data functions 3 | * 4 | * Copyright (C) 2016 by T.TAKASU, All rights reserved. 5 | * 6 | * references: 7 | * [1] ESRI Shapefile Technical Description, An ESRI White Paper, July, 1998 8 | * 9 | * version : $Revision:$ $Date:$ 10 | * history : 2016/06/10 1.0 new 11 | * 2016/07/31 1.1 add boundary of polyline and polygon 12 | * 2022/05/31 1.0 rewrite gis.c with golang by fxb 13 | *-----------------------------------------------------------------------------*/ 14 | 15 | package gnssgo 16 | 17 | import ( 18 | "encoding/binary" 19 | "math" 20 | "os" 21 | "strings" 22 | ) 23 | 24 | const SHAPE_CODE = 9994 /* shapefile code */ 25 | 26 | /* get integer big-endian ----------------------------------------------------*/ 27 | func I4_B(buff []uint8) int { 28 | return int(binary.BigEndian.Uint32(buff)) 29 | } 30 | 31 | /* get integer little-endian -------------------------------------------------*/ 32 | func I4_L(buff []uint8) int { 33 | return int(binary.LittleEndian.Uint32(buff)) 34 | } 35 | 36 | /* get double little-endian --------------------------------------------------*/ 37 | func D8_L(buff []uint8) float64 { 38 | 39 | bits := binary.LittleEndian.Uint64(buff) 40 | 41 | return math.Float64frombits(bits) 42 | 43 | } 44 | 45 | /* get double big-endian --------------------------------------------------*/ 46 | func D8_B(buff []uint8) float64 { 47 | 48 | bits := binary.BigEndian.Uint64(buff) 49 | 50 | return math.Float64frombits(bits) 51 | 52 | } 53 | 54 | /* read shapefile header -----------------------------------------------------*/ 55 | func ReadShapeHead(fp *os.File) int { 56 | var buff [128]uint8 57 | 58 | n, err := fp.Read(buff[:]) 59 | if err != nil || n < 1 { 60 | return -1 61 | } 62 | if I4_B(buff[:]) != SHAPE_CODE { 63 | return -1 64 | } 65 | return I4_L(buff[32:]) 66 | } 67 | 68 | /* initialize boundary -------------------------------------------------------*/ 69 | func init_bound(bound []float64) { 70 | bound[0] = PI / 2.0 71 | bound[1] = -PI / 2.0 72 | bound[2] = PI 73 | bound[3] = -PI 74 | } 75 | 76 | /* update boundary -----------------------------------------------------------*/ 77 | func update_bound(pos, bound []float64) { 78 | if pos[0] < bound[0] { 79 | bound[0] = pos[0] 80 | } 81 | if pos[0] > bound[1] { 82 | bound[1] = pos[0] 83 | } 84 | if pos[1] < bound[2] { 85 | bound[2] = pos[1] 86 | } 87 | if pos[1] > bound[3] { 88 | bound[3] = pos[1] 89 | } 90 | } 91 | 92 | /* add gis data --------------------------------------------------------------*/ 93 | func GisAdd(p **GisD, dtype int, data interface{}) int { 94 | var new_data *GisD = new(GisD) 95 | 96 | new_data.next = *p 97 | new_data.dtype = dtype 98 | new_data.data = data 99 | *p = new_data 100 | return 1 101 | } 102 | 103 | /* read point data -----------------------------------------------------------*/ 104 | func ReadPnt(fp *os.File, bound []float64, p **GisD) int { 105 | var ( 106 | pnt *Gis_Pnt = new(Gis_Pnt) 107 | pos [3]float64 108 | buff [16]uint8 109 | ) 110 | 111 | n, err := fp.Read(buff[:]) 112 | if err != nil || n < 1 { 113 | return 0 114 | } 115 | 116 | pos[0] = D8_L(buff[8:]) * D2R 117 | pos[1] = D8_L(buff[:]) * D2R 118 | update_bound(pos[:], bound[:]) 119 | Pos2Ecef(pos[:], pnt.pos[:]) 120 | 121 | return GisAdd(p, 1, pnt) 122 | } 123 | 124 | /* read multi-point data ------------------------------------------------------*/ 125 | func ReadMPnt(fp *os.File, bound []float64, p **GisD) int { 126 | var ( 127 | buff [36]uint8 128 | i, np int 129 | ) 130 | 131 | n, err := fp.Read(buff[:]) 132 | if err != nil || n < 1 { 133 | return 0 134 | } 135 | 136 | np = I4_L(buff[32:]) 137 | 138 | for i = 0; i < np; i++ { 139 | if ReadPnt(fp, bound, p) == 0 { 140 | return 0 141 | } 142 | } 143 | return 1 144 | } 145 | 146 | /* read polyline data ---------------------------------------------------------*/ 147 | func ReadPoly(fp *os.File, bound []float64, p **GisD) int { 148 | var ( 149 | poly *Gis_Poly 150 | pos [3]float64 151 | buff [40]uint8 152 | i, j, nt, np, nr, n int 153 | ) 154 | 155 | n, err := fp.Read(buff[:]) 156 | if err != nil || n < 1 { 157 | return 0 158 | } 159 | nt = I4_L(buff[32:]) 160 | np = I4_L(buff[36:]) 161 | 162 | var part []int = make([]int, nt) 163 | 164 | for i = 0; i < nt; i++ { 165 | fp.Read(buff[:4]) 166 | 167 | part[i] = I4_L(buff[:4]) 168 | } 169 | for i = 0; i < nt; i++ { 170 | if i < nt-1 { 171 | nr = part[i+1] - part[i] 172 | } else { 173 | nr = np - part[i] 174 | 175 | } 176 | poly = new(Gis_Poly) 177 | poly.pos = make([]float64, nr*3) 178 | init_bound(poly.bound[:]) 179 | n = 0 180 | for j = 0; j < nr; j++ { 181 | _, err = fp.Read(buff[:16]) 182 | if err != nil { 183 | return 0 184 | } 185 | pos[0] = D8_L(buff[8:]) * D2R 186 | pos[1] = D8_L(buff[:]) * D2R 187 | if pos[0] < (-1e16) || pos[1] < (-1e16) { 188 | continue 189 | } 190 | update_bound(pos[:], poly.bound[:]) 191 | update_bound(pos[:], bound[:]) 192 | Pos2Ecef(pos[:], poly.pos[n*3:]) 193 | n++ 194 | } 195 | poly.npnt = n 196 | if GisAdd(p, 2, poly) == 0 { 197 | return 0 198 | } 199 | } 200 | return 1 201 | } 202 | 203 | /* read polygon data ---------------------------------------------------------*/ 204 | func ReadPolygon(fp *os.File, bound []float64, p **GisD) int { 205 | var ( 206 | polygon *Gis_Polygon 207 | pos [3]float64 208 | buff [40]uint8 209 | i, j, nt, np, nr, n int 210 | ) 211 | 212 | n, err := fp.Read(buff[:]) 213 | if err != nil || n < 1 { 214 | return 0 215 | } 216 | nt = I4_L(buff[32:]) 217 | np = I4_L(buff[36:]) 218 | 219 | var part []int = make([]int, nt) 220 | 221 | for i = 0; i < nt; i++ { 222 | fp.Read(buff[:4]) 223 | 224 | part[i] = I4_L(buff[:4]) 225 | } 226 | for i = 0; i < nt; i++ { 227 | if i < nt-1 { 228 | nr = part[i+1] - part[i] 229 | } else { 230 | nr = np - part[i] 231 | 232 | } 233 | 234 | polygon = new(Gis_Polygon) 235 | polygon.pos = make([]float64, nr*3) 236 | init_bound(polygon.bound[:]) 237 | n = 0 238 | for j = 0; j < nr; j++ { 239 | _, err = fp.Read(buff[:16]) 240 | if err != nil { 241 | return 0 242 | } 243 | pos[0] = D8_L(buff[8:]) * D2R 244 | pos[1] = D8_L(buff[:]) * D2R 245 | if pos[0] < (-1e16) || pos[1] < (-1e16) { 246 | continue 247 | } 248 | update_bound(pos[:], polygon.bound[:]) 249 | update_bound(pos[:], bound[:]) 250 | Pos2Ecef(pos[:], polygon.pos[n*3:]) 251 | n++ 252 | } 253 | polygon.npnt = n 254 | if GisAdd(p, 3, polygon) == 0 { 255 | return 0 256 | } 257 | } 258 | return 1 259 | } 260 | 261 | /* read shapefile records ----------------------------------------------------*/ 262 | func GisReadRecord(fp, fp_idx *os.File, dtype int, bound []float64, data **GisD) int { 263 | 264 | var ( 265 | p, next *GisD 266 | buff [16]uint8 267 | i, off, num, len1, len2, typ2 int 268 | ) 269 | 270 | for i = 0; ; i++ { 271 | n, _ := fp_idx.Read(buff[:8]) 272 | if n != 8 { 273 | break 274 | } 275 | off = I4_B(buff[:]) * 2 276 | len1 = I4_B(buff[4:]) * 2 277 | ns, _ := fp.Seek(int64(off), 1) 278 | nb, _ := fp.Read(buff[:12]) 279 | if ns < 0 || nb != 12 { 280 | return 0 281 | } 282 | num = I4_B(buff[:]) 283 | len2 = I4_B(buff[4:8]) * 2 284 | typ2 = I4_L(buff[8:12]) 285 | 286 | if num != i+1 || len1 != len2 || dtype != typ2 { 287 | Trace(2, "shapefile record error n=%d %d len=%d %d type=%d %d\n", 288 | i+1, num, len1, len2, dtype, typ2) 289 | continue 290 | } 291 | switch dtype { 292 | case 1: 293 | ReadPnt(fp, bound, data) /* point */ 294 | case 8: 295 | ReadMPnt(fp, bound, data) /* multi-point */ 296 | case 3: 297 | ReadPoly(fp, bound, data) /* polyline */ 298 | case 5: 299 | ReadPolygon(fp, bound, data) /* polygon */ 300 | } 301 | 302 | } 303 | /* reverse list order */ 304 | *data = nil 305 | for p = *data; p != nil; p = next { 306 | next = p.next 307 | p.next = *data 308 | *data = p 309 | } 310 | return 1 311 | } 312 | 313 | /* read gis data from shapefile ------------------------------------------------ 314 | * read gis data from shapefile (ref [1]) 315 | * args : char *file I shapefile 316 | * gis_t *gis IO GIS data 317 | * return : status (0:error) 318 | * notes : only support point, multipoint, polyline and polygon. 319 | * only support lat-lon for map projection. 320 | *-----------------------------------------------------------------------------*/ 321 | func (gis *Gis) GisRead(file string, layer int) int { 322 | var ( 323 | fp, fp_idx *os.File 324 | type1, type2 int = 0, 0 325 | err error 326 | ) 327 | Trace(4, "gis_read file=%s layer=%d\n", file, layer) 328 | 329 | path := file 330 | index := strings.LastIndex(path, ".") 331 | 332 | if index > 0 { 333 | path = path[:index-1] + ".shx" 334 | } else { 335 | path = path + ".shx" 336 | } 337 | 338 | if fp, err = os.OpenFile(file, os.O_RDONLY, 0666); err != nil { /* shapefile */ 339 | Trace(2, "shapefile open error: %s\n", file) 340 | return 0 341 | } 342 | defer fp.Close() 343 | if fp_idx, _ = os.OpenFile(path, os.O_RDONLY, 0666); fp_idx == nil { /* index file */ 344 | 345 | Trace(2, "shapefile index open error: %s\n", path) 346 | return 0 347 | } 348 | defer fp_idx.Close() 349 | 350 | /* read header */ 351 | type1 = ReadShapeHead(fp) 352 | type2 = ReadShapeHead(fp_idx) 353 | if type1 < 0 || type2 < 0 || type1 != type2 { 354 | Trace(2, "shapefile header error: %s type=%d %d\n", file, type1, type2) 355 | return 0 356 | } 357 | init_bound(gis.bound[:]) 358 | 359 | /* read records */ 360 | if GisReadRecord(fp, fp_idx, type1, gis.bound[:], &gis.data[layer]) == 0 { 361 | return 0 362 | } 363 | gis.name[layer] = "" 364 | gis.flag[layer] = 1 365 | return 1 366 | } 367 | 368 | /* free gis-data --------------------------------------------------------------- 369 | * free and initialize gis data 370 | * args : gis_t *gis IO gis data 371 | * return : none 372 | *-----------------------------------------------------------------------------*/ 373 | func (gis *Gis) GisFree() { 374 | var data, next *GisD 375 | 376 | for i := 0; i < MAXGISLAYER; i++ { 377 | for data = gis.data[i]; data != nil; data = next { 378 | next = data.next 379 | if data.dtype == 2 { 380 | data.data.(*Gis_Poly).pos = nil 381 | } else if data.dtype == 3 { 382 | data.data.(*Gis_Polygon).pos = nil 383 | } 384 | data = nil 385 | } 386 | gis.data[i] = nil 387 | gis.name[i] = "" 388 | gis.flag[i] = 0 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /src/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo 2 | 3 | go 1.18 4 | 5 | //replace gnssgo => ../src 6 | require github.com/tarm/goserial v0.0.0-20151007205400-b3440c3c6355 7 | -------------------------------------------------------------------------------- /src/go.sum: -------------------------------------------------------------------------------- 1 | github.com/tarm/goserial v0.0.0-20151007205400-b3440c3c6355 h1:Kp3kg8YL2dc75mckomrHZQTfzNyFGnaqFhJeQw4ozGc= 2 | github.com/tarm/goserial v0.0.0-20151007205400-b3440c3c6355/go.mod h1:jcMo2Odv5FpDA6rp8bnczbUolcICW6t54K3s9gOlgII= 3 | -------------------------------------------------------------------------------- /src/httpUtils.go: -------------------------------------------------------------------------------- 1 | package gnssgo 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | type httpHeaders map[string]string 9 | 10 | func ParseHttp(buff string) httpHeaders { 11 | var headers httpHeaders = make(httpHeaders) 12 | lines := strings.Split(buff, "\r\n") 13 | for _, v := range lines { 14 | s1 := strings.Index(v, ":") 15 | if s1 == -1 { 16 | s1 = strings.Index(v, " ") 17 | } 18 | if s1 == -1 { 19 | continue 20 | } 21 | headers[v[:s1]] = v[s1+1:] 22 | } 23 | return headers 24 | } 25 | 26 | func (headers httpHeaders) GetHead(key string) (string, bool) { 27 | var ( 28 | v string 29 | ok bool = true 30 | ) 31 | if headers == nil { 32 | return "", false 33 | } 34 | v = headers[key] 35 | if len(v) == 0 { 36 | ok = false 37 | } 38 | return v, ok 39 | } 40 | 41 | func (headers httpHeaders) ParseBody(k string, v ...interface{}) error { 42 | value, ok := headers.GetHead(k) 43 | if ok { 44 | bodys := strings.Fields(value) 45 | if len(v) != len(bodys) { 46 | return errors.New("num of argument is not right") 47 | } 48 | for i := 0; i < len(v); i++ { 49 | switch a := v[i].(type) { 50 | case *string: 51 | *a = bodys[i] 52 | 53 | } 54 | } 55 | } 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /src/lamda.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * lambda.c : integer ambiguity resolution 3 | * 4 | * Copyright (C) 2007-2008 by T.TAKASU, All rights reserved. 5 | * 6 | * reference : 7 | * [1] P.J.G.Teunissen, The least-square ambiguity decorrelation adjustment: 8 | * a method for fast GPS ambiguity estimation, J.Geodesy, Vol.70, 65-82, 9 | * 1995 10 | * [2] X.-W.Chang, X.Yang, T.Zhou, MLAMBDA: A modified LAMBDA method for 11 | * integer least-squares estimation, J.Geodesy, Vol.79, 552-565, 2005 12 | * 13 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:48:06 $ 14 | * history : 2007/01/13 1.0 new 15 | * 2015/05/31 1.1 add api lambda_reduction(), lambda_search() 16 | * 2022/05/31 1.0 rewrite lambda.c with golang by fxb 17 | *-----------------------------------------------------------------------------*/ 18 | package gnssgo 19 | 20 | import ( 21 | "math" 22 | ) 23 | 24 | /* constants/macros ----------------------------------------------------------*/ 25 | 26 | const LOOPMAX int = 10000 /* maximum count of search loop */ 27 | 28 | func SGN(x float64) float64 { 29 | if x <= 0.0 { 30 | return -1.0 31 | } else { 32 | return 1.0 33 | } 34 | } 35 | 36 | // func ROUND_F(x float64) float64 { return math.Floor(x + 0.5) } 37 | func ROUND_F(x float64) float64 { 38 | t := math.Trunc(x) 39 | if math.Abs(x-t) >= 0.5 { 40 | return t + math.Copysign(1, x) 41 | } 42 | return t 43 | } 44 | 45 | // #define SWAP(x,y) do {double tmp_; tmp_=x; x=y; y=tmp_;} while (0) 46 | /* LD factorization (Q=L'*diag(D)*L) -----------------------------------------*/ 47 | func LD(n int, Q, L, D []float64) int { 48 | var ( 49 | i, j, k, info int 50 | a float64 51 | ) 52 | A := Mat(n, n) 53 | copy(A, Q) 54 | // memcpy(A,Q,sizeof(double)*n*n); 55 | for i = n - 1; i >= 0; i-- { 56 | if D[i] = A[i+i*n]; D[i] <= 0.0 { 57 | info = -1 58 | break 59 | } 60 | a = math.Sqrt(D[i]) 61 | for j = 0; j <= i; j++ { 62 | L[i+j*n] = A[i+j*n] / a 63 | } 64 | for j = 0; j <= i-1; j++ { 65 | for k = 0; k <= j; k++ { 66 | A[j+k*n] -= L[i+k*n] * L[i+j*n] 67 | } 68 | } 69 | for j = 0; j <= i; j++ { 70 | L[i+j*n] /= L[i+i*n] 71 | } 72 | } 73 | if info != 0 { 74 | Trace(2, "%s : LD factorization error\n", "lamda.go") 75 | } 76 | return info 77 | } 78 | 79 | /* integer Gauss transformation ----------------------------------------------*/ 80 | func Gauss(n int, L, Z []float64, i, j int) { 81 | if mu := int(ROUND_F(L[i+j*n])); mu != 0 { 82 | for k := i; k < n; k++ { 83 | L[k+n*j] -= float64(mu) * L[k+i*n] 84 | } 85 | for k := 0; k < n; k++ { 86 | Z[k+n*j] -= float64(mu) * Z[k+i*n] 87 | } 88 | } 89 | } 90 | 91 | /* permutations --------------------------------------------------------------*/ 92 | func Perm(n int, L, D []float64, j int, del float64, Z []float64) { 93 | eta := D[j] / del 94 | lam := D[j+1] * L[j+1+j*n] / del 95 | D[j] = eta * D[j+1] 96 | D[j+1] = del 97 | for k := 0; k <= j-1; k++ { 98 | a0 := L[j+k*n] 99 | a1 := L[j+1+k*n] 100 | L[j+k*n] = -L[j+1+j*n]*a0 + a1 101 | L[j+1+k*n] = eta*a0 + lam*a1 102 | } 103 | L[j+1+j*n] = lam 104 | for k := j + 2; k < n; k++ { 105 | L[k+j*n], L[k+(j+1)*n] = L[k+(j+1)*n], L[k+j*n] 106 | } 107 | for k := 0; k < n; k++ { 108 | Z[k+j*n], Z[k+(j+1)*n] = Z[k+(j+1)*n], Z[k+j*n] 109 | } 110 | } 111 | 112 | /* lambda Reduction (z=Z'*a, Qz=Z'*Q*Z=L'*diag(D)*L) (ref.[1]) ---------------*/ 113 | func Reduction(n int, L, D, Z []float64) { 114 | var i, j, k int 115 | 116 | j = n - 2 117 | k = n - 2 118 | for j >= 0 { 119 | if j <= k { 120 | for i = j + 1; i < n; i++ { 121 | Gauss(n, L, Z, i, j) 122 | } 123 | } 124 | del := D[j] + L[j+1+j*n]*L[j+1+j*n]*D[j+1] 125 | if del+(1e-6) < D[j+1] { /* compared considering numerical error */ 126 | Perm(n, L, D, j, del, Z) 127 | k = j 128 | j = n - 2 129 | } else { 130 | j-- 131 | } 132 | } 133 | } 134 | 135 | /* modified lambda (mlambda) Search (ref. [2]) -------------------------------*/ 136 | func Search(n, m int, L, D, zs, zn, s []float64) int { 137 | var ( 138 | i, j, k, c, nn, imax int 139 | newdist, maxdist, y float64 = 0.0, 1e99, 0.0 140 | ) 141 | S := Zeros(n, n) 142 | dist := Mat(n, 1) 143 | zb := Mat(n, 1) 144 | z := Mat(n, 1) 145 | step := Mat(n, 1) 146 | 147 | k = n - 1 148 | dist[k] = 0.0 149 | zb[k] = zs[k] 150 | z[k] = ROUND_F(zb[k]) 151 | y = zb[k] - z[k] 152 | step[k] = SGN(y) 153 | for c = 0; c < LOOPMAX; c++ { 154 | newdist = dist[k] + y*y/D[k] 155 | if newdist < maxdist { 156 | if k != 0 { 157 | k-- 158 | dist[k] = newdist 159 | for i = 0; i <= k; i++ { 160 | S[k+i*n] = S[k+1+i*n] + (z[k+1]-zb[k+1])*L[k+1+i*n] 161 | } 162 | zb[k] = zs[k] + S[k+k*n] 163 | z[k] = ROUND_F(zb[k]) 164 | y = zb[k] - z[k] 165 | step[k] = SGN(y) 166 | } else { 167 | if nn < m { 168 | if nn == 0 || newdist > s[imax] { 169 | imax = nn 170 | } 171 | for i = 0; i < n; i++ { 172 | zn[i+nn*n] = z[i] 173 | } 174 | s[nn] = newdist 175 | nn++ 176 | } else { 177 | if newdist < s[imax] { 178 | for i = 0; i < n; i++ { 179 | zn[i+imax*n] = z[i] 180 | } 181 | s[imax] = newdist 182 | for i, imax = 0, 0; i < m; i++ { 183 | if s[imax] < s[i] { 184 | imax = i 185 | } 186 | } 187 | } 188 | maxdist = s[imax] 189 | } 190 | z[0] += step[0] 191 | y = zb[0] - z[0] 192 | step[0] = -step[0] - SGN(step[0]) 193 | } 194 | } else { 195 | if k == n-1 { 196 | break 197 | } else { 198 | k++ 199 | z[k] += step[k] 200 | y = zb[k] - z[k] 201 | step[k] = -step[k] - SGN(step[k]) 202 | } 203 | } 204 | } 205 | for i = 0; i < m-1; i++ { /* sort by s */ 206 | for j = i + 1; j < m; j++ { 207 | if s[i] < s[j] { 208 | continue 209 | } 210 | s[i], s[j] = s[j], s[i] 211 | for k = 0; k < n; k++ { 212 | zn[k+i*n], zn[k+j*n] = zn[k+j*n], zn[k+i*n] 213 | } 214 | } 215 | } 216 | 217 | if c >= LOOPMAX { 218 | Trace(2, "%s : search loop count overflow\n", "lamda") 219 | return -1 220 | } 221 | return 0 222 | } 223 | 224 | /* Lambda/mlambda integer least-square estimation ------------------------------ 225 | * integer least-square estimation. reduction is performed by Lambda (ref.[1]), 226 | * and search by mlambda (ref.[2]). 227 | * args : int n I number of float parameters 228 | * int m I number of fixed solutions 229 | * double *a I float parameters (n x 1) 230 | * double *Q I covariance matrix of float parameters (n x n) 231 | * double *F O fixed solutions (n x m) 232 | * double *s O sum of squared residulas of fixed solutions (1 x m) 233 | * return : status (0:ok,other:error) 234 | * notes : matrix stored by column-major order (fortran convension) 235 | *-----------------------------------------------------------------------------*/ 236 | func Lambda(n, m int, a, Q, F, s []float64) int { 237 | var ( 238 | info int 239 | L, D, Z, z, E []float64 240 | ) 241 | 242 | if n <= 0 || m <= 0 { 243 | return -1 244 | } 245 | L = Zeros(n, n) 246 | D = Mat(n, 1) 247 | Z = Eye(n) 248 | z = Mat(n, 1) 249 | E = Mat(n, m) 250 | 251 | /* LD factorization */ 252 | if info = LD(n, Q, L, D); info == 0 { 253 | 254 | /* lambda reduction */ 255 | Reduction(n, L, D, Z) 256 | MatMul("TN", n, 1, n, 1.0, Z, a, 0.0, z) /* z=Z'*a */ 257 | 258 | /* mlambda search */ 259 | if info = Search(n, m, L, D, z, E, s); info == 0 { 260 | 261 | info = Solve("T", Z, E, n, m, F) /* F=Z'\E */ 262 | } 263 | } 264 | 265 | return info 266 | } 267 | 268 | /* lambda reduction ------------------------------------------------------------ 269 | * reduction by lambda (ref [1]) for integer least square 270 | * args : int n I number of float parameters 271 | * double *Q I covariance matrix of float parameters (n x n) 272 | * double *Z O lambda reduction matrix (n x n) 273 | * return : status (0:ok,other:error) 274 | *-----------------------------------------------------------------------------*/ 275 | func LambdaReduction(n int, Q, Z []float64) int { 276 | 277 | if n <= 0 { 278 | return -1 279 | } 280 | 281 | L := Zeros(n, n) 282 | D := Mat(n, 1) 283 | 284 | for i := 0; i < n; i++ { 285 | for j := 0; j < n; j++ { 286 | if i == j { 287 | Z[i+j*n] = 1.0 288 | } else { 289 | Z[i+j*n] = 0.0 290 | } 291 | } 292 | } 293 | /* LD factorization */ 294 | if info := LD(n, Q, L, D); info > 0 { 295 | 296 | return info 297 | } 298 | /* lambda reduction */ 299 | Reduction(n, L, D, Z) 300 | 301 | return 0 302 | } 303 | 304 | /* mlambda search -------------------------------------------------------------- 305 | * search by mlambda (ref [2]) for integer least square 306 | * args : int n I number of float parameters 307 | * int m I number of fixed solutions 308 | * double *a I float parameters (n x 1) 309 | * double *Q I covariance matrix of float parameters (n x n) 310 | * double *F O fixed solutions (n x m) 311 | * double *s O sum of squared residulas of fixed solutions (1 x m) 312 | * return : status (0:ok,other:error) 313 | *-----------------------------------------------------------------------------*/ 314 | func LambdaSearch(n, m int, a, Q, F, s []float64) int { 315 | if n <= 0 || m <= 0 { 316 | return -1 317 | } 318 | 319 | L := Zeros(n, n) 320 | D := Mat(n, 1) 321 | 322 | /* LD factorization */ 323 | if info := LD(n, Q, L, D); info > 0 { 324 | 325 | return info 326 | } 327 | /* mlambda search */ 328 | return Search(n, m, L, D, a, F, s) 329 | 330 | } 331 | -------------------------------------------------------------------------------- /src/ss2.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * ss2.c : superstar II receiver dependent functions 3 | * 4 | * Copyright (C) 2007-2020 by T.TAKASU, All rights reserved. 5 | * Copyright (C) 2007-2022 by Feng Xuebin, All rights reserved. 6 | * 7 | * reference: 8 | * [1] NovAtel, OM-20000086 Superstar II Firmware Reference Manual, 2005 9 | * 10 | * version : $Revision: 1.2 $ $Date: 2008/07/14 00:05:05 $ 11 | * history : 2008/05/18 1.0 new 12 | * 2008/06/16 1.2 separate common functions to rcvcmn.c 13 | * 2009/04/01 1.3 fix bug on decode #21 message 14 | * 2010/08/20 1.4 fix problem with minus value of time slew in #23 15 | * (2.4.0_p5) 16 | * 2011/05/27 1.5 fix problem with ARM compiler 17 | * 2013/02/23 1.6 fix memory access violation problem on arm 18 | * 2020/11/30 1.7 use integer type in stdint.h 19 | * 2022/09/27 1.8 rewrite with golang 20 | *-----------------------------------------------------------------------------*/ 21 | package gnssgo 22 | 23 | import ( 24 | "fmt" 25 | "io" 26 | "math" 27 | "os" 28 | "strings" 29 | ) 30 | 31 | const ( 32 | SS2SOH = 0x01 /* ss2 start of header */ 33 | ID_SS2LLH = 20 /* ss2 message ID#20 navigation data (user) */ 34 | ID_SS2ECEF = 21 /* ss2 message ID#21 navigation data (ecef) */ 35 | ID_SS2EPH = 22 /* ss2 message ID#22 ephemeris data */ 36 | ID_SS2RAW = 23 /* ss2 message ID#23 measurement block */ 37 | ID_SS2SBAS = 67 /* ss2 message ID#67 sbas data */ 38 | ) 39 | 40 | /* get/set fields (little-endian) --------------------------------------------*/ 41 | // declared in cresent.go, rename it as xxL 42 | // #define U1(p) (*((uint8 *)(p))) 43 | // static uint16 U2L(uint8 *p) {uint16 u; memcpy(&u,p,2); return u;} 44 | // static uint32 U4L(uint8 *p) {uint32 u; memcpy(&u,p,4); return u;} 45 | // static float64 R8L(uint8 *p) {float64 r; memcpy(&r,p,8); return r;} 46 | 47 | /* checksum ------------------------------------------------------------------*/ 48 | func chksum_ss2(buff []uint8, length int) int { 49 | var sum uint16 = 0 50 | 51 | for i := 0; i < length-2; i++ { 52 | sum += uint16(buff[i]) 53 | } 54 | if uint8(sum>>8) == buff[length-1] && uint8(sum&0xFF) == buff[length-2] { 55 | return 1 56 | } 57 | return 0 58 | } 59 | 60 | /* adjust week ---------------------------------------------------------------*/ 61 | func adjweek_ss2(raw *Raw, sec float64) int { 62 | var ( 63 | tow float64 64 | week int 65 | ) 66 | 67 | if raw.Time.Time == 0 { 68 | return 0 69 | } 70 | tow = Time2GpsT(raw.Time, &week) 71 | if sec < tow-302400.0 { 72 | sec += 604800.0 73 | } else if sec > tow+302400.0 { 74 | sec -= 604800.0 75 | } 76 | raw.Time = GpsT2Time(week, sec) 77 | return 1 78 | } 79 | 80 | /* decode id#20 navigation data (user) ---------------------------------------*/ 81 | func decode_ss2llh(raw *Raw) int { 82 | var ( 83 | ep [6]float64 84 | p = 4 85 | ) 86 | 87 | Trace(4, "decode_ss2llh: len=%d\n", raw.Len) 88 | 89 | if raw.Len != 77 { 90 | Trace(2, "ss2 id#20 length error: len=%d\n", raw.Len) 91 | return -1 92 | } 93 | ep[3] = float64(U1(raw.Buff[p:])) 94 | ep[4] = float64(U1(raw.Buff[p+1:])) 95 | ep[5] = R8L(raw.Buff[p+2:]) 96 | ep[2] = float64(U1(raw.Buff[p+10:])) 97 | ep[1] = float64(U1(raw.Buff[p+11:])) 98 | ep[0] = float64(U2L(raw.Buff[p+12:])) 99 | raw.Time = Utc2GpsT(Epoch2Time(ep[:])) 100 | return 0 101 | } 102 | 103 | /* decode id#21 navigation data (ecef) ---------------------------------------*/ 104 | func decode_ss2ecef(raw *Raw) int { 105 | var p = 4 106 | 107 | Trace(4, "decode_ss2ecef: len=%d\n", raw.Len) 108 | 109 | if raw.Len != 85 { 110 | Trace(2, "ss2 id#21 length error: len=%d\n", raw.Len) 111 | return -1 112 | } 113 | raw.Time = GpsT2Time(int(U2L(raw.Buff[p+8:])), R8L(raw.Buff[p:])) 114 | return 0 115 | } 116 | 117 | /* decode id#23 measurement block --------------------------------------------*/ 118 | func decode_ss2meas(raw *Raw) int { 119 | const ( 120 | freqif float64 = 1.405396825e6 121 | tslew = 1.75e-7 122 | ) 123 | var ( 124 | tow, slew, code, icp, d float64 125 | i, j, n, prn, sat, nobs int 126 | p = 4 127 | sc uint32 128 | ) 129 | 130 | Trace(4, "decode_ss2meas: len=%d\n", raw.Len) 131 | 132 | nobs = int(U1(raw.Buff[p+2:])) 133 | if 17+nobs*11 != raw.Len { 134 | Trace(2, "ss2 id#23 message length error: len=%d\n", raw.Len) 135 | return -1 136 | } 137 | tow = math.Floor(R8L(raw.Buff[p+3:])*1000.0+0.5) / 1000.0 /* rounded by 1ms */ 138 | if adjweek_ss2(raw, tow) == 0 { 139 | Trace(2, "ss2 id#23 message time adjustment error\n") 140 | return -1 141 | } 142 | /* time slew defined as uchar (ref [1]) but minus value appears in some f/w */ 143 | slew = float64(raw.Buff[p]) * tslew 144 | 145 | raw.Icpc += 4.5803 - freqif*slew - FREQ1*(slew-1e-6) /* phase correction */ 146 | 147 | for i, n, p = 0, 0, p+11; i < nobs && n < MAXOBS; i, p = i+1, p+11 { 148 | prn = int(raw.Buff[p]&0x1F) + 1 149 | sys := SYS_GPS 150 | if raw.Buff[p]&0x20 > 0 { 151 | sys = SYS_SBS 152 | } 153 | if sat = SatNo(sys, prn); sat == 0 { 154 | Trace(2, "ss2 id#23 satellite number error: prn=%d\n", prn) 155 | continue 156 | } 157 | raw.ObsData.Data[n].Time = raw.Time 158 | raw.ObsData.Data[n].Sat = sat 159 | code = (tow - math.Floor(tow)) - float64(U4L(raw.Buff[p+2:]))/2095104000.0 160 | if code < 0.0 { 161 | raw.ObsData.Data[n].P[0] = CLIGHT * (code + 1.0) 162 | } else { 163 | raw.ObsData.Data[n].P[0] = CLIGHT * (code) 164 | } 165 | icp = float64(U4L(raw.Buff[p+6:])>>2)/1024.0 + raw.Off[sat-1] /* unwrap */ 166 | if math.Abs(icp-raw.Icpp[sat-1]) > 524288.0 { 167 | if icp > raw.Icpp[sat-1] { 168 | d = -1048576.0 169 | } else { 170 | d = 1048576.0 171 | } 172 | raw.Off[sat-1] += d 173 | icp += d 174 | } 175 | raw.Icpp[sat-1] = icp 176 | raw.ObsData.Data[n].L[0] = icp + raw.Icpc 177 | raw.ObsData.Data[n].D[0] = 0.0 178 | raw.ObsData.Data[n].SNR[0] = uint16(float64(U1(raw.Buff[p+1:]))*0.25/SNR_UNIT + 0.5) 179 | sc = uint32(U1(raw.Buff[p+10:])) 180 | if uint8(sc)-uint8(raw.LockTime[sat-1][0]) > 0 { 181 | raw.ObsData.Data[n].LLI[0] = 1 182 | } else { 183 | raw.ObsData.Data[n].LLI[0] = 0 184 | } 185 | if U1(raw.Buff[p+6:])&1 > 0 { 186 | raw.ObsData.Data[n].LLI[0] |= 2 187 | } else { 188 | raw.ObsData.Data[n].LLI[0] |= 0 189 | } 190 | raw.ObsData.Data[n].Code[0] = CODE_L1C 191 | raw.LockTime[sat-1][0] = float64(sc) 192 | 193 | for j = 1; j < NFREQ; j++ { 194 | raw.ObsData.Data[n].L[j], raw.ObsData.Data[n].P[j] = 0.0, 0.0 195 | raw.ObsData.Data[n].D[j] = 0.0 196 | raw.ObsData.Data[n].SNR[j], raw.ObsData.Data[n].LLI[j] = 0, 0 197 | raw.ObsData.Data[n].Code[j] = CODE_NONE 198 | } 199 | n++ 200 | } 201 | raw.ObsData.n = n 202 | return 1 203 | } 204 | 205 | /* decode id#22 ephemeris data ------------------------------------------------*/ 206 | func decode_ss2eph(raw *Raw) int { 207 | var ( 208 | eph Eph 209 | tow uint32 210 | p = 4 211 | buff [90]uint8 212 | i, j, prn, sat int 213 | ) 214 | 215 | Trace(4, "decode_ss2eph: len=%d\n", raw.Len) 216 | 217 | if raw.Len != 79 { 218 | Trace(2, "ss2 id#22 length error: len=%d\n", raw.Len) 219 | return -1 220 | } 221 | prn = int(U4L(raw.Buff[p:])&0x1F) + 1 222 | if sat = SatNo(SYS_GPS, prn); sat == 0 { 223 | Trace(2, "ss2 id#22 satellite number error: prn=%d\n", prn) 224 | return -1 225 | } 226 | if raw.Time.Time == 0 { 227 | Trace(2, "ss2 id#22 week number unknown error\n") 228 | return -1 229 | } 230 | tow = uint32(Time2GpsT(raw.Time, nil) / 6.0) 231 | for i = 0; i < 3; i++ { 232 | buff[30*i+3] = uint8(tow >> 9) /* add tow + subframe id */ 233 | buff[30*i+4] = uint8(tow >> 1) 234 | buff[30*i+5] = uint8(((tow & 1) << 7) + uint32((i+1)<<2)) 235 | for j = 0; j < 24; j++ { 236 | buff[30*i+6+j] = raw.Buff[p+1+24*i+j] 237 | } 238 | } 239 | if DecodeFrame(buff[:], &eph, nil, nil, nil) == 0 { 240 | Trace(2, "ss2 id#22 subframe error: prn=%d\n", prn) 241 | return -1 242 | } 243 | if !strings.Contains(raw.Opt, "-EPHALL") { 244 | if eph.Iode == raw.NavData.Ephs[sat-1].Iode { 245 | return 0 /* unchanged */ 246 | } 247 | } 248 | eph.Sat = sat 249 | eph.Ttr = raw.Time 250 | raw.NavData.Ephs[sat-1] = eph 251 | raw.EphSat = sat 252 | raw.EphSet = 0 253 | return 2 254 | } 255 | 256 | /* decode id#67 sbas data ----------------------------------------------------*/ 257 | func decode_ss2sbas(raw *Raw) int { 258 | var ( 259 | i, prn int 260 | p = 4 261 | ) 262 | 263 | Trace(4, "decode_ss2sbas: len=%d\n", raw.Len) 264 | 265 | if raw.Len != 54 { 266 | Trace(2, "ss2 id#67 length error: len=%d\n", raw.Len) 267 | return -1 268 | } 269 | prn = int(U4L(raw.Buff[p+12:])) 270 | if prn < MINPRNSBS || MAXPRNSBS < prn { 271 | Trace(3, "ss2 id#67 prn error: prn=%d\n", prn) 272 | return 0 273 | } 274 | raw.Sbsmsg.Week = int(U4L(raw.Buff[p:])) 275 | raw.Sbsmsg.Tow = int(R8L(raw.Buff[p+4:])) 276 | _ = GpsT2Time(raw.Sbsmsg.Week, float64(raw.Sbsmsg.Tow)) /* time */ 277 | raw.Sbsmsg.Prn = uint8(prn) 278 | for i = 0; i < 29; i++ { 279 | raw.Sbsmsg.Msg[i] = raw.Buff[p+16+i] 280 | } 281 | return 3 282 | } 283 | 284 | /* decode superstar 2 raw message --------------------------------------------*/ 285 | func decode_ss2(raw *Raw) int { 286 | var ( 287 | p = 0 288 | ctype int = int(U1(raw.Buff[p+1:])) 289 | ) 290 | 291 | Trace(3, "decode_ss2: type=%2d\n", ctype) 292 | 293 | if chksum_ss2(raw.Buff[:], raw.Len) == 0 { 294 | Trace(2, "ss2 message checksum error: type=%d len=%d\n", ctype, raw.Len) 295 | return -1 296 | } 297 | if raw.OutType > 0 { 298 | copy(raw.MsgType[:], []byte(fmt.Sprintf("SS2 %2d (%4d):", ctype, raw.Len))) 299 | } 300 | switch ctype { 301 | case ID_SS2LLH: 302 | return decode_ss2llh(raw) 303 | case ID_SS2ECEF: 304 | return decode_ss2ecef(raw) 305 | case ID_SS2RAW: 306 | return decode_ss2meas(raw) 307 | case ID_SS2EPH: 308 | return decode_ss2eph(raw) 309 | case ID_SS2SBAS: 310 | return decode_ss2sbas(raw) 311 | } 312 | return 0 313 | } 314 | 315 | /* sync code -----------------------------------------------------------------*/ 316 | func sync_ss2(buff []uint8, data uint8) int { 317 | buff[0] = buff[1] 318 | buff[1] = buff[2] 319 | buff[2] = data 320 | if buff[0] == SS2SOH && (buff[1]^buff[2]) == 0xFF { 321 | return 1 322 | } 323 | return 0 324 | } 325 | 326 | /* input superstar 2 raw message from stream ----------------------------------- 327 | * input next superstar 2 raw message from stream 328 | * args : raw *Raw IO receiver raw data control struct 329 | * uint8 data I stream data (1 byte) 330 | * return : status (-1: error message, 0: no message, 1: input observation data, 331 | * 2: input ephemeris, 3: input sbas message, 332 | * 9: input ion/utc parameter) 333 | * notes : needs #20 or #21 message to get proper week number of #23 raw 334 | * observation data 335 | *-----------------------------------------------------------------------------*/ 336 | func input_ss2(raw *Raw, data uint8) int { 337 | Trace(5, "input_ss2: data=%02x\n", data) 338 | 339 | /* synchronize frame */ 340 | if raw.NumByte == 0 { 341 | if sync_ss2(raw.Buff[:], data) == 0 { 342 | return 0 343 | } 344 | raw.NumByte = 3 345 | return 0 346 | } 347 | raw.Buff[raw.NumByte] = data 348 | raw.NumByte++ 349 | 350 | if raw.NumByte == 4 { 351 | if raw.Len = int(U1(raw.Buff[3:])) + 6; raw.Len > MAXRAWLEN { 352 | Trace(2, "ss2 length error: len=%d\n", raw.Len) 353 | raw.NumByte = 0 354 | return -1 355 | } 356 | } 357 | if raw.NumByte < 4 || raw.NumByte < raw.Len { 358 | return 0 359 | } 360 | raw.NumByte = 0 361 | 362 | /* decode superstar 2 raw message */ 363 | return decode_ss2(raw) 364 | } 365 | 366 | /* input superstar 2 raw message from file ------------------------------------- 367 | * input next superstar 2 raw message from file 368 | * args : raw_t *raw IO receiver raw data control struct 369 | * FILE *fp I file pointer 370 | * return : status(-2: end of file, -1...9: same as above) 371 | *-----------------------------------------------------------------------------*/ 372 | func input_ss2f(raw *Raw, fp *os.File) int { 373 | Trace(4, "input_ss2f:\n") 374 | 375 | /* synchronize frame */ 376 | if raw.NumByte == 0 { 377 | var c [1]byte 378 | /* synchronize frame */ 379 | for i := 0; ; i++ { 380 | _, err := fp.Read(c[:]) 381 | if err == io.EOF { 382 | return -2 383 | } 384 | if sync_ss2(raw.Buff[:], uint8(c[0])) > 0 { 385 | break 386 | } 387 | if i >= 4096 { 388 | return 0 389 | } 390 | } 391 | } 392 | if n, _ := fp.Read(raw.Buff[3:4]); n < 1 { 393 | return -2 394 | } 395 | raw.NumByte = 4 396 | 397 | if raw.Len = int(U1(raw.Buff[3:]) + 6); raw.Len > MAXRAWLEN { 398 | Trace(2, "ss2 length error: len=%d\n", raw.Len) 399 | raw.NumByte = 0 400 | return -1 401 | } 402 | if n, _ := fp.Read(raw.Buff[4:raw.Len]); n < raw.Len-4 { 403 | return -2 404 | } 405 | raw.NumByte = 0 406 | 407 | /* decode superstar 2 raw message */ 408 | return decode_ss2(raw) 409 | } 410 | -------------------------------------------------------------------------------- /src/tides.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * tides.c : tidal displacement corrections 3 | * 4 | * Copyright (C) 2015-2017 by T.TAKASU, All rights reserved. 5 | * 6 | * options : -DIERS_MODEL use IERS tide model 7 | * 8 | * references : 9 | * [1] D.D.McCarthy, IERS Technical Note 21, IERS Conventions 1996, July 1996 10 | * [2] D.D.McCarthy and G.Petit, IERS Technical Note 32, IERS Conventions 11 | * 2003, November 2003 12 | * [3] D.A.Vallado, Fundamentals of Astrodynamics and Applications 2nd ed, 13 | * Space Technology Library, 2004 14 | * [4] J.Kouba, A Guide to using International GNSS Service (IGS) products, 15 | * May 2009 16 | * [5] G.Petit and B.Luzum (eds), IERS Technical Note No. 36, IERS 17 | * Conventions (2010), 2010 18 | * 19 | * version : $Revision:$ $Date:$ 20 | * history : 2015/05/10 1.0 separated from ppp.c 21 | * 2015/06/11 1.1 fix bug on computing days in tide_oload() (#128) 22 | * 2017/04/11 1.2 fix bug on calling geterp() in timdedisp() 23 | * 2022/05/31 1.0 rewrite tides.c with golang by fxb 24 | *-----------------------------------------------------------------------------*/ 25 | package gnssgo 26 | 27 | import ( 28 | "math" 29 | ) 30 | 31 | const ( 32 | GME = 3.986004415e+14 /* earth gravitational constant */ 33 | GMS = 1.327124e+20 /* sun gravitational constant */ 34 | GMM = 4.902801e+12 /* moon gravitational constant */ 35 | ) 36 | 37 | /* function prototypes -------------------------------------------------------*/ 38 | //#ifdef IERS_MODEL 39 | func dehanttideinel_(xsta []float64, year, mon, day []int, 40 | fhr, xsun, xmon, dxtide []float64) int { 41 | return 0 42 | } 43 | 44 | //#endif 45 | 46 | /* solar/lunar tides (ref [2] 7) ---------------------------------------------*/ 47 | //#ifndef IERS_MODEL 48 | func Tide_pl(eu, rp []float64, GMp float64, pos, dr []float64) { 49 | var ( 50 | H3, L3 float64 = 0.292, 0.015 51 | r, latp, lonp, p, K2, K3, a, H2, L2, dp, du, cosp, sinl, cosl float64 52 | ep [3]float64 53 | i int 54 | ) 55 | 56 | Trace(4, "tide_pl : pos=%.3f %.3f\n", pos[0]*R2D, pos[1]*R2D) 57 | 58 | if r = Norm(rp, 3); r <= 0.0 { 59 | return 60 | } 61 | 62 | for i = 0; i < 3; i++ { 63 | ep[i] = rp[i] / r 64 | } 65 | 66 | K2 = GMp / GME * SQR(RE_WGS84) * SQR(RE_WGS84) / (r * r * r) 67 | K3 = K2 * RE_WGS84 / r 68 | latp = math.Asin(ep[2]) 69 | lonp = math.Atan2(ep[1], ep[0]) 70 | cosp = math.Cos(latp) 71 | sinl = math.Sin(pos[0]) 72 | cosl = math.Cos(pos[0]) 73 | 74 | /* step1 in phase (degree 2) */ 75 | p = (3.0*sinl*sinl - 1.0) / 2.0 76 | H2 = 0.6078 - 0.0006*p 77 | L2 = 0.0847 + 0.0002*p 78 | a = Dot(ep[:], eu, 3) 79 | dp = K2 * 3.0 * L2 * a 80 | du = K2 * (H2*(1.5*a*a-0.5) - 3.0*L2*a*a) 81 | 82 | /* step1 in phase (degree 3) */ 83 | dp += K3 * L3 * (7.5*a*a - 1.5) 84 | du += K3 * (H3*(2.5*a*a*a-1.5*a) - L3*(7.5*a*a-1.5)*a) 85 | 86 | /* step1 out-of-phase (only radial) */ 87 | du += 3.0 / 4.0 * 0.0025 * K2 * math.Sin(2.0*latp) * math.Sin(2.0*pos[0]) * math.Sin(pos[1]-lonp) 88 | du += 3.0 / 4.0 * 0.0022 * K2 * cosp * cosp * cosl * cosl * math.Sin(2.0*(pos[1]-lonp)) 89 | 90 | dr[0] = dp*ep[0] + du*eu[0] 91 | dr[1] = dp*ep[1] + du*eu[1] 92 | dr[2] = dp*ep[2] + du*eu[2] 93 | 94 | Trace(5, "tide_pl : dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]) 95 | } 96 | 97 | /* displacement by solid earth tide (ref [2] 7) ------------------------------*/ 98 | func Tide_solid(rsun, rmoon, pos, E []float64, gmst float64, opt int, dr []float64) { 99 | var ( 100 | dr1, dr2, eu [3]float64 101 | du, dn, sinl, sin2l float64 102 | ) 103 | 104 | Trace(3, "tide_solid: pos=%.3f %.3f opt=%d\n", pos[0]*R2D, pos[1]*R2D, opt) 105 | 106 | /* step1: time domain */ 107 | eu[0] = E[2] 108 | eu[1] = E[5] 109 | eu[2] = E[8] 110 | Tide_pl(eu[:], rsun, GMS, pos, dr1[:]) 111 | Tide_pl(eu[:], rmoon, GMM, pos, dr2[:]) 112 | 113 | /* step2: frequency domain, only K1 radial */ 114 | sin2l = math.Sin(2.0 * pos[0]) 115 | du = -0.012 * sin2l * math.Sin(gmst+pos[1]) 116 | 117 | dr[0] = dr1[0] + dr2[0] + du*E[2] 118 | dr[1] = dr1[1] + dr2[1] + du*E[5] 119 | dr[2] = dr1[2] + dr2[2] + du*E[8] 120 | 121 | /* eliminate permanent deformation */ 122 | if opt&8 > 0 { 123 | sinl = math.Sin(pos[0]) 124 | du = 0.1196 * (1.5*sinl*sinl - 0.5) 125 | dn = 0.0247 * sin2l 126 | dr[0] += du*E[2] + dn*E[1] 127 | dr[1] += du*E[5] + dn*E[4] 128 | dr[2] += du*E[8] + dn*E[7] 129 | } 130 | Trace(5, "tide_solid: dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]) 131 | } 132 | 133 | // #endif /* !IERS_MODEL */ 134 | 135 | /* displacement by ocean tide loading (ref [2] 7) ----------------------------*/ 136 | func Tide_oload(tut Gtime, odisp, denu []float64) { 137 | var ( 138 | args [][5]float64 = [][5]float64{ 139 | {1.40519e-4, 2.0, -2.0, 0.0, 0.00}, /* M2 */ 140 | {1.45444e-4, 0.0, 0.0, 0.0, 0.00}, /* S2 */ 141 | {1.37880e-4, 2.0, -3.0, 1.0, 0.00}, /* N2 */ 142 | {1.45842e-4, 2.0, 0.0, 0.0, 0.00}, /* K2 */ 143 | {0.72921e-4, 1.0, 0.0, 0.0, 0.25}, /* K1 */ 144 | {0.67598e-4, 1.0, -2.0, 0.0, -0.25}, /* O1 */ 145 | {0.72523e-4, -1.0, 0.0, 0.0, -0.25}, /* P1 */ 146 | {0.64959e-4, 1.0, -3.0, 1.0, -0.25}, /* Q1 */ 147 | {0.53234e-5, 0.0, 2.0, 0.0, 0.00}, /* Mf */ 148 | {0.26392e-5, 0.0, 1.0, -1.0, 0.00}, /* Mm */ 149 | {0.03982e-5, 2.0, 0.0, 0.0, 0.00} /* Ssa */} 150 | ep1975 []float64 = []float64{1975, 1, 1, 0, 0, 0} 151 | fday, days, t, t2, t3, ang float64 152 | ep [6]float64 153 | a [5]float64 154 | dp [3]float64 155 | i, j int 156 | ) 157 | 158 | Trace(3, "tide_oload:\n") 159 | 160 | /* angular argument: see subroutine arg.f for reference [1] */ 161 | Time2Epoch(tut, ep[:]) 162 | fday = ep[3]*3600.0 + ep[4]*60.0 + ep[5] 163 | ep[3], ep[4], ep[5] = 0.0, 0.0, 0.0 164 | days = TimeDiff(Epoch2Time(ep[:]), Epoch2Time(ep1975))/86400.0 + 1.0 165 | t = (27392.500528 + 1.000000035*days) / 36525.0 166 | t2 = t * t 167 | t3 = t2 * t 168 | 169 | a[0] = fday 170 | a[1] = (279.69668 + 36000.768930485*t + 3.03e-4*t2) * D2R /* H0 */ 171 | a[2] = (270.434358 + 481267.88314137*t - 0.001133*t2 + 1.9e-6*t3) * D2R /* S0 */ 172 | a[3] = (334.329653 + 4069.0340329577*t - 0.010325*t2 - 1.2e-5*t3) * D2R /* P0 */ 173 | a[4] = 2.0 * PI 174 | 175 | /* displacements by 11 constituents */ 176 | for i = 0; i < 11; i++ { 177 | ang = 0.0 178 | for j = 0; j < 5; j++ { 179 | ang += a[j] * args[i][j] 180 | } 181 | for j = 0; j < 3; j++ { 182 | dp[j] += odisp[j+i*6] * math.Cos(ang-odisp[j+3+i*6]*D2R) 183 | } 184 | } 185 | denu[0] = -dp[1] 186 | denu[1] = -dp[2] 187 | denu[2] = dp[0] 188 | 189 | Trace(5, "tide_oload: denu=%.3f %.3f %.3f\n", denu[0], denu[1], denu[2]) 190 | } 191 | 192 | /* iers mean pole (ref [7] eq.7.25) ------------------------------------------*/ 193 | func Iers_mean_pole(tut Gtime, xp_bar, yp_bar *float64) { 194 | var ( 195 | ep2000 []float64 = []float64{2000, 1, 1, 0, 0, 0} 196 | y, y2, y3 float64 197 | ) 198 | y = TimeDiff(tut, Epoch2Time(ep2000)) / 86400.0 / 365.25 199 | 200 | if y < 3653.0/365.25 { /* until 2010.0 */ 201 | y2 = y * y 202 | y3 = y2 * y 203 | *xp_bar = 55.974 + 1.8243*y + 0.18413*y2 + 0.007024*y3 /* (mas) */ 204 | *yp_bar = 346.346 + 1.7896*y - 0.10729*y2 - 0.000908*y3 205 | } else { /* after 2010.0 */ 206 | *xp_bar = 23.513 + 7.6141*y /* (mas) */ 207 | *yp_bar = 358.891 - 0.6287*y 208 | } 209 | } 210 | 211 | /* displacement by pole tide (ref [7] eq.7.26) --------------------------------*/ 212 | func Tide_pole(tut Gtime, pos, erpv, denu []float64) { 213 | var xp_bar, yp_bar, m1, m2, cosl, sinl float64 214 | 215 | Trace(3, "tide_pole: pos=%.3f %.3f\n", pos[0]*R2D, pos[1]*R2D) 216 | 217 | /* iers mean pole (mas) */ 218 | Iers_mean_pole(tut, &xp_bar, &yp_bar) 219 | 220 | /* ref [7] eq.7.24 */ 221 | m1 = erpv[0]/AS2R - xp_bar*1e-3 /* (as) */ 222 | m2 = -erpv[1]/AS2R + yp_bar*1e-3 223 | 224 | /* sin(2*theta) = sin(2*phi), cos(2*theta)=-cos(2*phi) */ 225 | cosl = math.Cos(pos[1]) 226 | sinl = math.Sin(pos[1]) 227 | denu[0] = 9e-3 * math.Sin(pos[0]) * (m1*sinl - m2*cosl) /* de= Slambda (m) */ 228 | denu[1] = -9e-3 * math.Cos(2.0*pos[0]) * (m1*cosl + m2*sinl) /* dn=-Stheta (m) */ 229 | denu[2] = -33e-3 * math.Sin(2.0*pos[0]) * (m1*cosl + m2*sinl) /* du= Sr (m) */ 230 | 231 | Trace(5, "tide_pole : denu=%.3f %.3f %.3f\n", denu[0], denu[1], denu[2]) 232 | } 233 | 234 | /* tidal displacement ---------------------------------------------------------- 235 | * displacements by earth tides 236 | * args : gtime_t tutc I time in utc 237 | * double *rr I site position (ecef) (m) 238 | * int opt I options (or of the followings) 239 | * 1: solid earth tide 240 | * 2: ocean tide loading 241 | * 4: pole tide 242 | * 8: elimate permanent deformation 243 | * double *erp I earth rotation parameters (NULL: not used) 244 | * double *odisp I ocean loading parameters (NULL: not used) 245 | * odisp[0+i*6]: consituent i amplitude radial(m) 246 | * odisp[1+i*6]: consituent i amplitude west (m) 247 | * odisp[2+i*6]: consituent i amplitude south (m) 248 | * odisp[3+i*6]: consituent i phase radial (deg) 249 | * odisp[4+i*6]: consituent i phase west (deg) 250 | * odisp[5+i*6]: consituent i phase south (deg) 251 | * (i=0:M2,1:S2,2:N2,3:K2,4:K1,5:O1,6:P1,7:Q1, 252 | * 8:Mf,9:Mm,10:Ssa) 253 | * double *dr O displacement by earth tides (ecef) (m) 254 | * return : none 255 | * notes : see ref [1], [2] chap 7 256 | * see ref [4] 5.2.1, 5.2.2, 5.2.3 257 | * ver.2.4.0 does not use ocean loading and pole tide corrections 258 | *-----------------------------------------------------------------------------*/ 259 | func TideDisp(tutc Gtime, rr []float64, opt int, erp *Erp, odisp, dr []float64) { 260 | var ( 261 | tut Gtime 262 | pos [2]float64 263 | E [9]float64 264 | drt, denu, rs, rm [3]float64 265 | gmst float64 266 | erpv [5]float64 267 | i int 268 | ) 269 | // #ifdef IERS_MODEL 270 | // double ep[6],fhr; 271 | // int year,mon,day; 272 | // #endif 273 | 274 | Trace(3, "tidedisp: tutc=%s\n", TimeStr(tutc, 0)) 275 | 276 | if erp != nil { 277 | GetErp(erp, Utc2GpsT(tutc), erpv[:]) 278 | } 279 | tut = TimeAdd(tutc, erpv[2]) 280 | 281 | dr[0], dr[1], dr[2] = 0.0, 0.0, 0.0 282 | 283 | if Norm(rr, 3) <= 0.0 { 284 | return 285 | } 286 | 287 | pos[0] = math.Asin(rr[2] / Norm(rr, 3)) 288 | pos[1] = math.Atan2(rr[1], rr[0]) 289 | XYZ2Enu(pos[:], E[:]) 290 | 291 | if opt&1 > 0 { /* solid earth tides */ 292 | 293 | /* sun and moon position in ecef */ 294 | SunMoonPos(tutc, erpv[:], rs[:], rm[:], &gmst) 295 | 296 | // #ifdef IERS_MODEL 297 | // time2epoch(tutc,ep); 298 | // year=(int)ep[0]; 299 | // mon =(int)ep[1]; 300 | // day =(int)ep[2]; 301 | // fhr =ep[3]+ep[4]/60.0+ep[5]/3600.0; 302 | 303 | // /* call DEHANTTIDEINEL */ 304 | // dehanttideinel_((double *)rr,&year,&mon,&day,&fhr,rs,rm,drt); 305 | // #else 306 | Tide_solid(rs[:], rm[:], pos[:], E[:], gmst, opt, drt[:]) 307 | //#endif 308 | for i = 0; i < 3; i++ { 309 | dr[i] += drt[i] 310 | } 311 | } 312 | if (opt&2 > 0) && odisp != nil { /* ocean tide loading */ 313 | Tide_oload(tut, odisp, denu[:]) 314 | MatMul("TN", 3, 1, 3, 1.0, E[:], denu[:], 0.0, drt[:]) 315 | for i = 0; i < 3; i++ { 316 | dr[i] += drt[i] 317 | } 318 | } 319 | if (opt&4 > 0) && erp != nil { /* pole tide */ 320 | Tide_pole(tut, pos[:], erpv[:], denu[:]) 321 | MatMul("TN", 3, 1, 3, 1.0, E[:], denu[:], 0.0, drt[:]) 322 | for i = 0; i < 3; i++ { 323 | dr[i] += drt[i] 324 | } 325 | } 326 | Trace(5, "tidedisp: dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]) 327 | } 328 | -------------------------------------------------------------------------------- /src/workspace.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".." 5 | } 6 | ], 7 | "settings": {} 8 | } -------------------------------------------------------------------------------- /unittest/atmos_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : atomospheric models 3 | *-----------------------------------------------------------------------------*/ 4 | 5 | package gnss_test 6 | 7 | import ( 8 | "gnssgo" 9 | "math" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | /* ionmodel() */ 16 | func Test_atmosutest1(t *testing.T) { 17 | var e1 []float64 = []float64{2007, 1, 16, 1, 0, 0} 18 | var e2 []float64 = []float64{2007, 1, 16, 13, 0, 0} 19 | var e3 []float64 = []float64{2007, 1, 16, 22, 0, 0} 20 | var ion1 []float64 = []float64{ 21 | 0.2e-7, -0.8e-8, -0.5e-7, 0.1e-6, 0.2e+6, 0.2e+6, -0.1e+6, -0.1e+7} 22 | var ion2 []float64 = []float64{ 23 | 0.2e-7, -0.8e-8, -0.5e-7, 0.1e-6, 0.2e+6, 0.2e+6, -0.1e+6, -0.1e+7} 24 | D2R := gnssgo.D2R 25 | var pos1 []float64 = []float64{35 * D2R, 140 * D2R, 100.0} 26 | var pos2 []float64 = []float64{-80 * D2R, -170 * D2R, 1000.0} 27 | var pos3 []float64 = []float64{10 * D2R, 30 * D2R, 0.0} 28 | var azel1 []float64 = []float64{60 * D2R, 75 * D2R} 29 | var azel2 []float64 = []float64{190 * D2R, 3 * D2R} 30 | var azel3 []float64 = []float64{350 * D2R, 60 * D2R} 31 | var azel4 []float64 = []float64{0 * D2R, 90 * D2R} 32 | t1 := gnssgo.Epoch2Time(e1) 33 | t2 := gnssgo.Epoch2Time(e2) 34 | t3 := gnssgo.Epoch2Time(e3) 35 | var dion float64 36 | assert := assert.New(t) 37 | 38 | dion = gnssgo.IonModel(t1, ion1, pos1, azel1) 39 | assert.True(math.Abs(dion-6.73590532099438) < 1e-8) 40 | 41 | dion = gnssgo.IonModel(t1, ion1, pos2, azel1) 42 | assert.True(math.Abs(dion-3.56895382197387) < 1e-8) 43 | 44 | dion = gnssgo.IonModel(t1, ion1, pos3, azel1) 45 | assert.True(math.Abs(dion-3.80716435655161) < 1e-8) 46 | 47 | dion = gnssgo.IonModel(t2, ion1, pos1, azel1) 48 | assert.True(math.Abs(dion-5.21796954585452) < 1e-8) 49 | 50 | dion = gnssgo.IonModel(t3, ion1, pos1, azel1) 51 | assert.True(math.Abs(dion-5.90190539264777) < 1e-8) 52 | 53 | dion = gnssgo.IonModel(t1, ion1, pos1, azel2) 54 | assert.True(math.Abs(dion-21.6345415123632) < 1e-8) 55 | 56 | dion = gnssgo.IonModel(t1, ion1, pos1, azel3) 57 | assert.True(math.Abs(dion-7.33844278822561) < 1e-8) 58 | 59 | dion = gnssgo.IonModel(t1, ion1, pos1, azel4) 60 | assert.True(math.Abs(dion-6.58339711400694) < 1e-8) 61 | 62 | dion = gnssgo.IonModel(t1, ion2, pos1, azel1) 63 | assert.True(math.Abs(dion-6.73590532099438) < 1e-8) 64 | 65 | } 66 | 67 | /* gnssgo.TropModel */ 68 | func Test_atmosutest3(t *testing.T) { 69 | var time gnssgo.Gtime 70 | D2R := gnssgo.D2R 71 | var pos1 []float64 = []float64{35 * D2R, 140 * D2R, 100.0} 72 | var pos2 []float64 = []float64{-80 * D2R, -170 * D2R, 1000.0} 73 | var pos3 []float64 = []float64{-80 * D2R, -170 * D2R, 100000.0} 74 | var pos4 []float64 = []float64{-80 * D2R, -170 * D2R, -200.0} 75 | var azel1 []float64 = []float64{60 * D2R, 75 * D2R} 76 | var azel2 []float64 = []float64{190 * D2R, 3 * D2R} 77 | var azel3 []float64 = []float64{190 * D2R, -10 * D2R} 78 | var dtrp float64 79 | assert := assert.New(t) 80 | 81 | dtrp = gnssgo.TropModel(time, pos1, azel1, 0.5) 82 | assert.True(math.Abs(dtrp-2.44799870144088) < 1e-8) 83 | 84 | dtrp = gnssgo.TropModel(time, pos1, azel2, 0.5) 85 | assert.True(math.Abs(dtrp-45.1808916506163) < 1e-8) 86 | 87 | dtrp = gnssgo.TropModel(time, pos2, azel1, 0.5) 88 | assert.True(math.Abs(dtrp-2.17295817298152) < 1e-8) 89 | 90 | dtrp = gnssgo.TropModel(time, pos1, azel3, 0.0) 91 | assert.True(math.Abs(dtrp-0.00000000000000) < 1e-8) 92 | 93 | dtrp = gnssgo.TropModel(time, pos3, azel1, 0.0) 94 | assert.True(math.Abs(dtrp-0.00000000000000) < 1e-8) 95 | 96 | dtrp = gnssgo.TropModel(time, pos4, azel1, 0.0) 97 | assert.True(math.Abs(dtrp-0.00000000000000) < 1e-8) 98 | } 99 | 100 | func Test_atmosutest4(t *testing.T) { 101 | var mapfd, mapfw float64 102 | var e1 []float64 = []float64{2007, 1, 16, 6, 0, 0} 103 | var e2 []float64 = []float64{2030, 12, 31, 23, 59, 59} 104 | D2R := gnssgo.D2R 105 | var pos1 []float64 = []float64{35 * D2R, 140 * D2R, 100.0} 106 | var pos2 []float64 = []float64{-80 * D2R, -170 * D2R, 1000.0} 107 | var pos3 []float64 = []float64{10 * D2R, 30 * D2R, 0.0} 108 | var azel1 []float64 = []float64{60 * D2R, 75 * D2R} 109 | var azel2 []float64 = []float64{190 * D2R, 3 * D2R} 110 | var azel3 []float64 = []float64{350 * D2R, 60 * D2R} 111 | var azel4 []float64 = []float64{0 * D2R, 90 * D2R} 112 | assert := assert.New(t) 113 | t1 := gnssgo.Epoch2Time(e1) 114 | t2 := gnssgo.Epoch2Time(e2) 115 | 116 | mapfd = gnssgo.TropMapFunc(t1, pos1, azel1, &mapfw) 117 | assert.True(math.Abs(mapfd-1.035184526466435) < 1e-8) 118 | assert.True(math.Abs(mapfw-1.035233787448654) < 1e-8) 119 | 120 | mapfd = gnssgo.TropMapFunc(t1, pos1, azel2, &mapfw) 121 | assert.True(math.Abs(mapfd-14.643271711748200) < 1e-8) 122 | assert.True(math.Abs(mapfw-16.455045694559484) < 1e-8) 123 | 124 | mapfd = gnssgo.TropMapFunc(t1, pos1, azel3, &mapfw) 125 | assert.True(math.Abs(mapfd-1.154226397147367) < 1e-8) 126 | assert.True(math.Abs(mapfw-1.154481126139610) < 1e-8) 127 | 128 | mapfd = gnssgo.TropMapFunc(t1, pos1, azel4, &mapfw) 129 | assert.True(math.Abs(mapfd-1.000000000000000) < 1e-8) 130 | assert.True(math.Abs(mapfw-1.000000000000000) < 1e-8) 131 | 132 | mapfd = gnssgo.TropMapFunc(t2, pos1, azel1, &mapfw) 133 | assert.True(math.Abs(mapfd-1.035184415128022) < 1e-8) 134 | assert.True(math.Abs(mapfw-1.035233787448654) < 1e-8) 135 | 136 | mapfd = gnssgo.TropMapFunc(t1, pos2, azel1, &mapfw) 137 | assert.True(math.Abs(mapfd-1.035186155749051) < 1e-8) 138 | assert.True(math.Abs(mapfw-1.035230548304367) < 1e-8) 139 | 140 | mapfd = gnssgo.TropMapFunc(t1, pos3, azel1, &mapfw) 141 | assert.True(math.Abs(mapfd-1.035181919429758) < 1e-8) 142 | assert.True(math.Abs(mapfw-1.035233200318210) < 1e-8) 143 | 144 | mapfd = gnssgo.TropMapFunc(t1, pos1, azel1, nil) 145 | assert.True(math.Abs(mapfd-1.035184526466435) < 1e-8) 146 | } 147 | -------------------------------------------------------------------------------- /unittest/coord_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : coordinates functions 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "gnssgo" 8 | "math" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | /* gnssgo.Ecef2Pos() */ 15 | func Test_coordutest1(t *testing.T) { 16 | var r1 []float64 = []float64{0.0, 0.0, 0.0} 17 | var r2 []float64 = []float64{10000000.0, 0.0, 0.0} 18 | var r3 []float64 = []float64{0.0, 10000000.0, 0.0} 19 | var r4 []float64 = []float64{0.0, 0.0, 10000000.0} 20 | var r5 []float64 = []float64{0.0, 0.0, -10000000.0} 21 | var r6 []float64 = []float64{-3.5173197701e+06, 4.1316679161e+06, 3.3412651227e+06} 22 | var r7 []float64 = []float64{-3.5173197701e+06, 4.1316679161e+06, -3.3412651227e+06} 23 | var pos [3]float64 24 | PI := gnssgo.PI 25 | R2D := gnssgo.R2D 26 | assert := assert.New(t) 27 | gnssgo.Ecef2Pos(r1, pos[:]) 28 | assert.True(pos[2] < 0.0) 29 | gnssgo.Ecef2Pos(r2, pos[:]) 30 | assert.True(pos[0] == 0 && pos[1] == 0 && pos[2] > 0.0) 31 | gnssgo.Ecef2Pos(r3, pos[:]) 32 | assert.True(pos[0] == 0 && math.Abs(pos[1]-PI/2) < 1e-6 && pos[2] > 0.0) 33 | gnssgo.Ecef2Pos(r4, pos[:]) 34 | assert.True(math.Abs(pos[0]-PI/2) < 1e-6 && pos[2] > 0.0) 35 | gnssgo.Ecef2Pos(r5, pos[:]) 36 | assert.True(math.Abs(pos[0]+PI/2) < 1e-6 && pos[2] > 0.0) 37 | gnssgo.Ecef2Pos(r6, pos[:]) 38 | assert.True(math.Abs(pos[0]*R2D-3.1796021375e+01) < 1e-7 && 39 | math.Abs(pos[1]*R2D-1.3040799917e+02) < 1e-7 && 40 | math.Abs(pos[2]-6.8863206206e+01) < 1e-4) 41 | gnssgo.Ecef2Pos(r7, pos[:]) 42 | assert.True(math.Abs(pos[0]*R2D+3.1796021375e+01) < 1e-7 && 43 | math.Abs(pos[1]*R2D-1.3040799917e+02) < 1e-7 && 44 | math.Abs(pos[2]-6.8863206206e+01) < 1e-4) 45 | } 46 | 47 | /* pos2ecef() */ 48 | func Test_coordutest2(t *testing.T) { 49 | var lat, lon, h float64 50 | var pos, posi, r [3]float64 51 | assert := assert.New(t) 52 | D2R := gnssgo.D2R 53 | R2D := gnssgo.R2D 54 | for lat = -90.0; lat <= 90.0; lat += 5.0 { 55 | for lon = -180.0; lon < 180.0; lon += 5.0 { 56 | for h = -10.0; h < 10000.0; h += 100.0 { 57 | pos[0] = lat * D2R 58 | pos[1] = lon * D2R 59 | pos[2] = h 60 | gnssgo.Pos2Ecef(pos[:], r[:]) 61 | gnssgo.Ecef2Pos(r[:], posi[:]) 62 | b := math.Abs(lon-posi[1]*R2D) < 1e-7 63 | if lat == 90.0 { 64 | b = true 65 | } 66 | assert.True(math.Abs(lat-posi[0]*R2D) < 1e-7) 67 | assert.True(lat == -90.0 || b) 68 | assert.True(math.Abs(h-posi[2]) < 1e-4) 69 | } 70 | } 71 | } 72 | } 73 | 74 | /* ecef2enu(), enu2ecef() */ 75 | func Test_coordutest3(t *testing.T) { 76 | D2R := gnssgo.D2R 77 | var pos1 []float64 = []float64{0.000 * D2R, 0.000 * D2R, 0.0} 78 | var pos2 []float64 = []float64{35.000 * D2R, 140.000 * D2R, 0.0} 79 | var r1 []float64 = []float64{1.0, 0.0, 0.0} 80 | var r2 []float64 = []float64{0.0, 1.0, 0.0} 81 | var r3 []float64 = []float64{0.0, 0.0, 1.0} 82 | var r4 []float64 = []float64{0.3, 0.4, 0.5} 83 | var e, r [3]float64 84 | assert := assert.New(t) 85 | gnssgo.Ecef2Enu(pos1, r1, e[:]) 86 | assert.True(e[0] == 0.0 && e[1] == 0.0 && e[2] == 1.0) 87 | gnssgo.Ecef2Enu(pos1, r2, e[:]) 88 | assert.True(e[0] == 1.0 && e[1] == 0.0 && e[2] == 0.0) 89 | gnssgo.Ecef2Enu(pos1, r3, e[:]) 90 | assert.True(e[0] == 0.0 && e[1] == 1.0 && e[2] == 0.0) 91 | gnssgo.Ecef2Enu(pos2, r4, e[:]) 92 | assert.True(math.Abs(e[0]+0.499254) < 1e-6 && 93 | math.Abs(e[1]-0.393916) < 1e-6 && 94 | math.Abs(e[2]-0.309152) < 1e-6) 95 | gnssgo.Enu2Ecef(pos2, e[:], r[:]) 96 | assert.True(math.Abs(r[0]-r4[0]) < 1e-6 && 97 | math.Abs(r[1]-r4[1]) < 1e-6 && 98 | math.Abs(r[2]-r4[2]) < 1e-6) 99 | } 100 | -------------------------------------------------------------------------------- /unittest/geoid_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : geoid functions 3 | *-----------------------------------------------------------------------------*/ 4 | 5 | package gnss_test 6 | 7 | import ( 8 | "gnssgo" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | /* latitude, longitude, geoid height (m) */ 15 | /* reference : http://sps.unavco.org/geoid */ 16 | var D2R float64 = gnssgo.D2R 17 | var poss [][3]float64 = [][3]float64{ 18 | {90.001 * D2R, 80.000 * D2R, 0.000}, 19 | {-90.001 * D2R, 80.000 * D2R, 0.000}, 20 | {30.000 * D2R, 360.000 * D2R, 0.000}, 21 | {-30.000 * D2R, -360.001 * D2R, 0.000}, 22 | {-90.000 * D2R, 359.999 * D2R, -29.534}, 23 | {90.000 * D2R, 80.000 * D2R, 13.606}, 24 | {-90.000 * D2R, -60.000 * D2R, -29.534}, 25 | {30.000 * D2R, -360.000 * D2R, 35.387}, 26 | {-30.000 * D2R, 359.999 * D2R, 21.409}, 27 | {10.000 * D2R, 45.000 * D2R, -20.486}, 28 | {-60.123 * D2R, 135.123 * D2R, -33.152}, 29 | {19.999 * D2R, 135.000 * D2R, 41.602}, 30 | {50.001 * D2R, 135.000 * D2R, 20.555}, 31 | {35.000 * D2R, 119.999 * D2R, 4.386}, 32 | {35.000 * D2R, 150.001 * D2R, 14.779}, 33 | {20.000 * D2R, 120.000 * D2R, 21.269}, 34 | {50.000 * D2R, 150.000 * D2R, 20.277}, 35 | {35.000 * D2R, 135.000 * D2R, 36.355}, 36 | {45.402 * D2R, 141.750 * D2R, 27.229}, /* wakkanai */ 37 | {24.454 * D2R, 122.942 * D2R, 21.652}, /* ishigaki */ 38 | {33.120 * D2R, 139.797 * D2R, 43.170}, /* hachijo */ 39 | {30.000 * D2R, 135.000 * D2R, 36.017}, /* taiheiyo */ 40 | {0, 0, 0}} 41 | var DATADIR string = "../../../../data/geoiddata/" 42 | var file1 string = DATADIR + "WW15MGH.DAC" 43 | var file2 string = DATADIR + "Und_min1x1_egm2008_isw=82_WGS84_TideFree_SE" 44 | var file3 string = DATADIR + "Und_min2.5x2.5_egm2008_isw=82_WGS84_TideFree_SE" 45 | var file4 string = DATADIR + "gsigeome.ver4" 46 | 47 | /* opengeoid(), closegeoid() */ 48 | func Test_geoidutest1(t *testing.T) { 49 | var ret int 50 | assert := assert.New(t) 51 | 52 | ret = gnssgo.OpenGeoid(10, file1) 53 | assert.True(ret == 0) /* no model */ 54 | ret = gnssgo.OpenGeoid(gnssgo.GEOID_EGM96_M150, "../../../geoiddata/WW15MGH.DAA") 55 | assert.True(ret == 0) /* no file */ 56 | ret = gnssgo.OpenGeoid(gnssgo.GEOID_EMBEDDED, "") 57 | assert.True(ret == 1) 58 | gnssgo.CloseGeoid() 59 | ret = gnssgo.OpenGeoid(gnssgo.GEOID_EGM96_M150, file1) 60 | assert.True(ret == 1) 61 | gnssgo.CloseGeoid() 62 | ret = gnssgo.OpenGeoid(gnssgo.GEOID_EGM2008_M10, file2) 63 | assert.True(ret == 1) 64 | gnssgo.CloseGeoid() 65 | ret = gnssgo.OpenGeoid(gnssgo.GEOID_EGM2008_M25, file3) 66 | assert.True(ret == 1) 67 | gnssgo.CloseGeoid() 68 | ret = gnssgo.OpenGeoid(gnssgo.GEOID_GSI2000_M15, file4) 69 | assert.True(ret == 1) 70 | gnssgo.CloseGeoid() 71 | } 72 | -------------------------------------------------------------------------------- /unittest/gloeph_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : glonass ephemeris function 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "os" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func dumpgeph(geph []gnssgo.GEph, n int) { 16 | var s1, s2 string 17 | var i int 18 | for i = 0; i < n; i++ { 19 | gnssgo.Time2Str(geph[i].Toe, &s1, 0) 20 | gnssgo.Time2Str(geph[i].Tof, &s2, 0) 21 | fmt.Printf("(%3d) sat=%2d frq=%2d svh=%d age=%d toe=%s %s pos=%13.3f %13.3f %13.3f vel=%9.3f %9.3f %9.3f acc=%10.3E %10.3E %10.3E taun=%12.5E gamn=%12.5E\n", 22 | i+1, geph[i].Sat, geph[i].Frq, geph[i].Svh, geph[i].Age, s1, s2, 23 | geph[i].Pos[0], geph[i].Pos[1], geph[i].Pos[2], 24 | geph[i].Vel[0], geph[i].Vel[1], geph[i].Vel[2], 25 | geph[i].Acc[0], geph[i].Acc[1], geph[i].Acc[2], 26 | geph[i].Taun, geph[i].Gamn) 27 | } 28 | } 29 | 30 | /* readrnx() */ 31 | func Test_gloephutest1(t *testing.T) { 32 | var file1 string = "../data/rinex/brdd0910.09g" 33 | var file2 string = "../data/rinex/brdc0910.09g" 34 | var nav gnssgo.Nav 35 | assert := assert.New(t) 36 | 37 | gnssgo.ReadRnx(file1, 1, "", nil, &nav, nil) 38 | assert.True(nav.Ng() == 0) 39 | gnssgo.ReadRnx(file2, 1, "", nil, &nav, nil) 40 | assert.True(nav.Ng() > 0) 41 | dumpgeph(nav.Geph, nav.Ng()) 42 | } 43 | 44 | /* readsp3() */ 45 | func Test_gloephutest2(t *testing.T) { 46 | var file1 string = "../data/sp3/igl15253.sp4" 47 | var file2 string = "../data/sp3/igl15253.sp3" 48 | var nav gnssgo.Nav 49 | var tow float64 50 | var pos []float64 51 | var i, week, sat int 52 | assert := assert.New(t) 53 | 54 | sat = gnssgo.SatNo(gnssgo.SYS_GLO, 13) 55 | 56 | nav.ReadSp3(file1, 0) 57 | assert.True(nav.Ne() <= 0) 58 | nav.ReadSp3(file2, 0) 59 | assert.True(nav.Ne() > 0) 60 | 61 | for i = 0; i < nav.Ne(); i++ { 62 | tow = gnssgo.Time2GpsT(nav.Peph[i].Time, &week) 63 | pos = nav.Peph[i].Pos[sat-1][:] 64 | fmt.Printf("%4d %6.0f %2d %13.3f %13.3f %13.3f %10.3f\n", 65 | week, tow, sat, pos[0], pos[1], pos[2], pos[3]*1e9) 66 | assert.True(gnssgo.Norm(pos, 4) > 0.0) 67 | } 68 | fmt.Printf("\n") 69 | } 70 | 71 | /* broadcast ephemeris */ 72 | func Test_gloephutest3(t *testing.T) { 73 | var time gnssgo.Gtime 74 | var file string = "../data/rinex/brdc0910.09g" 75 | var nav gnssgo.Nav 76 | var ep []float64 = []float64{2009, 4, 1, 0, 0, 0} 77 | var tspan float64 = 86400.0 78 | var tint float64 = 30.0 79 | var tow float64 80 | var rs [6]float64 81 | var dts [2]float64 82 | var fvar float64 83 | var i, sat, week, svh int 84 | assert := assert.New(t) 85 | 86 | sat = gnssgo.SatNo(gnssgo.SYS_GLO, 7) 87 | 88 | gnssgo.ReadRnx(file, 1, "", nil, &nav, nil) 89 | 90 | for i = 0; i < int(tspan/tint); i++ { 91 | time = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep), tint*float64(i)) 92 | nav.SatPos(time, time, sat, gnssgo.EPHOPT_BRDC, rs[:], dts[:], &fvar, &svh) 93 | tow = gnssgo.Time2GpsT(time, &week) 94 | fmt.Printf("%4d %6.0f %2d %13.3f %13.3f %13.3f %10.3f\n", 95 | week, tow, sat, rs[0], rs[1], rs[2], dts[0]*1e9) 96 | assert.True(gnssgo.Norm(rs[:], 3) > 0.0) 97 | assert.True(gnssgo.Norm(rs[3:], 3) > 0.0) 98 | assert.True(dts[0] != 0.0) 99 | assert.True(dts[1] != 0.0) 100 | } 101 | fmt.Printf("\n") 102 | } 103 | 104 | /* precise ephemeris */ 105 | func Test_gloephutest4(t *testing.T) { 106 | var time gnssgo.Gtime 107 | var file string = "../data/sp3/igl15253.sp3" 108 | var nav gnssgo.Nav 109 | var ep []float64 = []float64{2009, 4, 1, 0, 0, 0} 110 | var tspan float64 = 86400.0 111 | var tint float64 = 30.0 112 | var tow float64 113 | var rs [6]float64 114 | var dts [2]float64 115 | var fvar float64 116 | var i, sat, week, svh int 117 | assert := assert.New(t) 118 | 119 | sat = gnssgo.SatNo(gnssgo.SYS_GLO, 7) 120 | 121 | nav.ReadSp3(file, 0) 122 | 123 | for i = 0; i < int(tspan/tint); i++ { 124 | time = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep), tint*float64(i)) 125 | nav.SatPos(time, time, sat, gnssgo.EPHOPT_PREC, rs[:], dts[:], &fvar, &svh) 126 | tow = gnssgo.Time2GpsT(time, &week) 127 | fmt.Printf("%4d %6.0f %2d %13.3f %13.3f %13.3f %10.3f\n", 128 | week, tow, sat, rs[0], rs[1], rs[2], dts[0]*1e9) 129 | assert.True(gnssgo.Norm(rs[:], 3) > 0.0) 130 | assert.True(gnssgo.Norm(rs[3:], 3) > 0.0) 131 | assert.True(dts[0] != 0.0) 132 | } 133 | fmt.Printf("\n") 134 | } 135 | 136 | /* readsap() */ 137 | func Test_gloephutest5(t *testing.T) { 138 | var file string = "../data/igs05.atx" 139 | var id string 140 | var ep []float64 = []float64{2009, 4, 1, 0, 0, 0} 141 | time := gnssgo.Epoch2Time(ep) 142 | var nav gnssgo.Nav 143 | var i, stat int 144 | assert := assert.New(t) 145 | 146 | stat = nav.ReadSAP(file, time) 147 | assert.True(stat != 0) 148 | for i = 0; i < gnssgo.MAXSAT; i++ { 149 | gnssgo.SatNo2Id(i+1, &id) 150 | fmt.Printf("%2d %-4s %8.3f %8.3f %8.3f\n", i+1, id, 151 | nav.Pcvs[i].Offset[0][0], nav.Pcvs[i].Offset[0][1], nav.Pcvs[i].Offset[0][2]) 152 | } 153 | fmt.Printf("\n") 154 | } 155 | 156 | /* satpos() */ 157 | func Test_gloephutest6(t *testing.T) { 158 | var fp *os.File 159 | var file1 string = "../data/rinex/brdc0910.09g" 160 | var file2 string = "../data/sp3/igl15253.sp3" 161 | var file3 string = "../data/igs05.atx" 162 | /* 163 | char *file4="../data/esa15253.sp3"; 164 | char *file5="../data/esa15253.clk"; 165 | */ 166 | var outfile string = "../out/testgloeph.out" 167 | var ep []float64 = []float64{2009, 4, 1, 0, 0, 0} 168 | var tspan float64 = 86400.0 169 | var tint float64 = 30.0 170 | var tow, ddts float64 171 | var rs1, rs2 [6]float64 172 | var dts1, dts2 [2]float64 173 | var dr [3]float64 174 | var var1, var2 float64 175 | time := gnssgo.Epoch2Time(ep) 176 | var nav gnssgo.Nav 177 | var i, j, sat, week, svh1, svh2 int 178 | assert := assert.New(t) 179 | 180 | gnssgo.ReadRnx(file1, 1, "", nil, &nav, nil) 181 | nav.ReadSp3(file2, 0) 182 | /* 183 | readsp3(file4,&nav,0); 184 | readrnxc(file5,&nav); 185 | */ 186 | nav.ReadSAP(file3, time) 187 | 188 | /* 189 | sat=satno(SYS_GLO,21); 190 | */ 191 | sat = gnssgo.SatNo(gnssgo.SYS_GLO, 22) 192 | 193 | fp, _ = os.OpenFile(outfile, os.O_CREATE|os.O_WRONLY, os.ModePerm|os.ModeAppend) 194 | 195 | for i = 0; i < int(tspan/tint); i++ { 196 | time = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep), tint*float64(i)) 197 | tow = gnssgo.Time2GpsT(time, &week) 198 | nav.SatPos(time, time, sat, gnssgo.EPHOPT_BRDC, rs1[:], dts1[:], &var1, &svh1) 199 | nav.SatPos(time, time, sat, gnssgo.EPHOPT_PREC, rs2[:], dts2[:], &var2, &svh2) 200 | 201 | if gnssgo.Norm(rs1[:], 3) <= 0.0 || gnssgo.Norm(rs2[:], 3) <= 0.0 { 202 | continue 203 | } 204 | 205 | for j = 0; j < 3; j++ { 206 | dr[j] = rs1[j] - rs2[j] 207 | } 208 | ddts = dts1[0] - dts2[0] 209 | fp.WriteString(fmt.Sprintf("%4d %6.0f %2d %8.3f %8.3f %8.3f %10.3f\n", week, tow, sat, 210 | dr[0], dr[1], dr[2], ddts*1e9)) 211 | 212 | assert.True(gnssgo.Norm(dr[:], 3) < 10.0) 213 | } 214 | fp.Close() 215 | fmt.Printf("output to: %s\n", outfile) 216 | } 217 | -------------------------------------------------------------------------------- /unittest/go.mod: -------------------------------------------------------------------------------- 1 | module gnssgo_unittest 2 | 3 | go 1.18 4 | 5 | //require github.com/stretchr/testify/assert v1.2.3 6 | 7 | // require ( 8 | // github.com/davecgh/go-spew v1.1.1 // indirect 9 | // github.com/pmezard/go-difflib v1.0.0 // indirect 10 | // github.com/stretchr/objx v0.4.0 // indirect 11 | // github.com/stretchr/testify v1.7.2 // indirect 12 | // gopkg.in/yaml.v3 v3.0.1 // indirect 13 | // github.com/stretchr/testify/assert v1.7.2 // indirect 14 | // ) 15 | 16 | require ( 17 | github.com/davecgh/go-spew v1.1.0 // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | github.com/stretchr/testify v1.7.2 // direct 20 | gopkg.in/yaml.v3 v3.0.1 // indirect 21 | ) 22 | -------------------------------------------------------------------------------- /unittest/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 8 | github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= 9 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 10 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 11 | github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= 12 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 16 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 17 | -------------------------------------------------------------------------------- /unittest/grammar_test.go: -------------------------------------------------------------------------------- 1 | package gnss_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | "time" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func Test_String2Byte(t *testing.T) { 13 | var s string = "hello world" 14 | var b [64]byte 15 | assert := assert.New(t) 16 | 17 | copy(b[:], []byte(s)) 18 | 19 | b[25] = 'a' 20 | s = string(b[:]) 21 | 22 | assert.True(s == "hello world") 23 | } 24 | 25 | func Test_Fprintf(t *testing.T) { 26 | 27 | for { 28 | for _, r := range "-\\|/" { 29 | fmt.Printf("\r%c", r) 30 | time.Sleep(1) 31 | } 32 | } 33 | for i := 0; i < 100; i++ { 34 | fmt.Fprintf(os.Stdout, "\rthis is a output %2d", i) 35 | 36 | //fmt.Fprintf(os.Stderr, "\r") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /unittest/ionex_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : ionex function 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "math" 10 | "os" 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func dumptec(tec []gnssgo.Tec, n, level int, t *testing.T) { 17 | var p *gnssgo.Tec 18 | var s string 19 | var i, j, k, m int 20 | 21 | for i = 0; i < n; i++ { 22 | p = &tec[i] 23 | gnssgo.Time2Str(p.Time, &s, 3) 24 | fmt.Printf("(%2d) time =%s ndata=%d %d %d\n", i+1, s, p.Ndata[0], p.Ndata[1], p.Ndata[2]) 25 | if level < 1 { 26 | continue 27 | } 28 | fmt.Printf("lats =%6.1f %6.1f %6.1f\n", p.Lats[0], p.Lats[1], p.Lats[2]) 29 | fmt.Printf("lons =%6.1f %6.1f %6.1f\n", p.Lons[0], p.Lons[1], p.Lons[2]) 30 | fmt.Printf("hgts =%6.1f %6.1f %6.1f\n", p.Hgts[0], p.Hgts[1], p.Hgts[2]) 31 | fmt.Printf("data =\n") 32 | for j = 0; j < p.Ndata[2]; j++ { /* hgt */ 33 | for k = 0; k < p.Ndata[0]; k++ { /* lat */ 34 | fmt.Printf("lat=%.1f lon=%.1f:%.1f hgt=%.1f\n", p.Lats[0]+float64(k)*p.Lats[2], 35 | p.Lons[0], p.Lons[1], p.Hgts[0]+float64(j)*p.Hgts[2]) 36 | for m = 0; m < p.Ndata[1]; m++ { /* lon */ 37 | if m > 0 && m%16 == 0 { 38 | fmt.Printf("\n") 39 | } 40 | fmt.Printf("%5.1f ", p.Data[k+p.Ndata[0]*(m+p.Ndata[1]*j)]) 41 | } 42 | fmt.Printf("\n") 43 | } 44 | fmt.Printf("\n") 45 | } 46 | fmt.Printf("rms =\n") 47 | for j = 0; j < p.Ndata[2]; j++ { /* hgt */ 48 | for k = 0; k < p.Ndata[0]; k++ { /* lat */ 49 | fmt.Printf("lat=%.1f lon=%.1f:%.1f hgt=%.1f\n", p.Lats[0]+float64(k)*p.Lats[2], 50 | p.Lons[0], p.Lons[1], p.Hgts[0]+float64(j)*p.Hgts[2]) 51 | for m = 0; m < p.Ndata[1]; m++ { /* lon */ 52 | if m > 0 && m%16 == 0 { 53 | fmt.Printf("\n") 54 | } 55 | fmt.Printf("%5.1f ", p.Rms[k+p.Ndata[0]*(m+p.Ndata[1]*j)]) 56 | } 57 | fmt.Printf("\n") 58 | } 59 | fmt.Printf("\n") 60 | } 61 | } 62 | } 63 | func dumpdcb(nav *gnssgo.Nav, t *testing.T) { 64 | var i int 65 | fmt.Printf("dcbs=\n") 66 | for i = 0; i < len(nav.CBias); i++ { 67 | fmt.Printf("%3d: P1-P2=%6.3f\n", i+1, nav.CBias[i][0]/gnssgo.CLIGHT*1e9) /* ns */ 68 | } 69 | } 70 | 71 | /* readtec() */ 72 | func Test_ionexutest1(t *testing.T) { 73 | var file1 string = "../data/sp3/igrg3380.10j" 74 | var file2 string = "../data/sp3/igrg3380.10i" 75 | var file3 string = "../data/sp3/igrg33*0.10i" 76 | var nav gnssgo.Nav 77 | assert := assert.New(t) 78 | 79 | fmt.Printf("file=%s\n", file1) 80 | nav.ReadTec(file1, 0) 81 | assert.True(nav.Nt() == 0) 82 | 83 | fmt.Printf("file=%s\n", file2) 84 | nav.ReadTec(file2, 0) 85 | assert.True(nav.Nt() == 13) 86 | dumptec(nav.Tec, nav.Nt(), 1, t) 87 | 88 | fmt.Printf("file=%s\n", file3) 89 | nav.ReadTec(file3, 0) 90 | assert.True(nav.Nt() == 25) 91 | dumptec(nav.Tec, nav.Nt(), 0, t) 92 | 93 | dumptec(nav.Tec, 1, 1, t) 94 | dumptec(nav.Tec[12:], 1, 1, t) 95 | dumpdcb(&nav, t) 96 | } 97 | 98 | /* nav.IonTec() 1 */ 99 | func Test_ionexutest2(t *testing.T) { 100 | var file3 string = "../data/sp3/igrg33*0.10i" 101 | var nav gnssgo.Nav 102 | var time1, time2, time3, time4 gnssgo.Gtime 103 | var ep1 []float64 = []float64{2010, 12, 4, 0, 0, 0} 104 | var ep2 []float64 = []float64{2010, 12, 5, 23, 59, 59} 105 | var ep3 []float64 = []float64{2010, 12, 3, 23, 59, 59} /* error */ 106 | var ep4 []float64 = []float64{2010, 12, 6, 0, 0, 0} /* error */ 107 | D2R := gnssgo.D2R 108 | var pos1 []float64 = []float64{45.1 * D2R, 135.7 * D2R, 0.0} 109 | var pos2 []float64 = []float64{-45.1 * D2R, -170.7 * D2R, 0.0} 110 | var pos3 []float64 = []float64{-45.1 * D2R, 189.3 * D2R, 0.0} 111 | var pos4 []float64 = []float64{87.6 * D2R, 0.0 * D2R, 0.0} /* out of grid */ 112 | var pos5 []float64 = []float64{-87.6 * D2R, 0.0 * D2R, 0.0} /* out of grid */ 113 | var azel1 []float64 = []float64{0.0, 90.0 * D2R} 114 | var azel2 []float64 = []float64{120.0, 30.0 * D2R} 115 | var azel3 []float64 = []float64{0.0, -0.1 * D2R} /* error */ 116 | var delay1, var1, delay2, var2 float64 117 | var stat int 118 | assert := assert.New(t) 119 | 120 | time1 = gnssgo.Epoch2Time(ep1) 121 | time2 = gnssgo.Epoch2Time(ep2) 122 | time3 = gnssgo.Epoch2Time(ep3) 123 | time4 = gnssgo.Epoch2Time(ep4) 124 | 125 | nav.ReadTec(file3, 0) 126 | stat = nav.IonTec(time1, pos1, azel1, 1, &delay1, &var1) 127 | assert.True(stat == 1) 128 | stat = nav.IonTec(time2, pos1, azel1, 1, &delay1, &var1) 129 | assert.True(stat == 1) 130 | stat = nav.IonTec(time3, pos1, azel1, 1, &delay1, &var1) 131 | assert.True(stat == 0) 132 | stat = nav.IonTec(time4, pos1, azel1, 1, &delay1, &var1) 133 | assert.True(stat == 0) 134 | stat = nav.IonTec(time1, pos2, azel1, 1, &delay1, &var1) 135 | assert.True(stat == 1) 136 | stat = nav.IonTec(time1, pos3, azel1, 1, &delay2, &var2) 137 | assert.True(stat == 1) 138 | assert.True(math.Abs(delay1-delay2) < 1e-4) 139 | assert.True(math.Abs(var1-var2) < 1e-8) 140 | stat = nav.IonTec(time1, pos4, azel1, 1, &delay1, &var1) 141 | assert.True(stat == 1) 142 | stat = nav.IonTec(time1, pos5, azel1, 1, &delay1, &var1) 143 | assert.True(stat == 1) 144 | stat = nav.IonTec(time1, pos1, azel2, 1, &delay1, &var1) 145 | assert.True(stat == 1) 146 | stat = nav.IonTec(time1, pos1, azel3, 1, &delay1, &var1) 147 | assert.True(stat == 1 && delay1 == 0.0) 148 | } 149 | 150 | /* iontec() 2 */ 151 | func Test_ionexutest3(t *testing.T) { 152 | var fp *os.File 153 | var file3 string = "../data/sp3/igrg33*0.10i" 154 | var nav gnssgo.Nav 155 | var time1 gnssgo.Gtime 156 | var ep1 []float64 = []float64{2010, 12, 5, 0, 0, 0} 157 | var delay, fvar float64 158 | var pos [3]float64 159 | var azel []float64 = []float64{0.0, gnssgo.PI / 2} 160 | var i, j int 161 | var err error 162 | assert := assert.New(t) 163 | D2R := gnssgo.D2R 164 | 165 | time1 = gnssgo.Epoch2Time(ep1) 166 | nav.ReadTec(file3, 0) 167 | 168 | fp, err = os.OpenFile("../data/testionex3.m", os.O_CREATE|os.O_WRONLY, os.ModeAppend|os.ModePerm) 169 | if err != nil { 170 | t.Log(err) 171 | } 172 | assert.NotEmpty(fp) 173 | 174 | fp.WriteString("tec=[\n") 175 | for i = 90; i >= -90; i -= 2 { 176 | for j = 0; j <= 360; j += 2 { 177 | pos[0] = float64(i) * D2R 178 | pos[1] = float64(j) * D2R 179 | if nav.IonTec(time1, pos[:], azel, 1, &delay, &fvar) != 0 { 180 | fp.WriteString(fmt.Sprintf("%4.2f ", delay)) 181 | } else { 182 | fp.WriteString(fmt.Sprintf(" nan ")) 183 | } 184 | } 185 | fp.WriteString(fmt.Sprintf("\n")) 186 | } 187 | fp.WriteString(fmt.Sprintf("];\n")) 188 | fp.Close() 189 | 190 | fp, _ = os.OpenFile("../data/testionex3.m", os.O_APPEND, 0666) 191 | assert.NotEmpty(fp) 192 | 193 | fp.WriteString(fmt.Sprintf("rms=[\n")) 194 | for i = 90; i >= -90; i -= 2 { 195 | for j = 0; j <= 360; j += 2 { 196 | pos[0] = float64(i) * D2R 197 | pos[1] = float64(j) * D2R 198 | if nav.IonTec(time1, pos[:], azel, 1, &delay, &fvar) != 0 { 199 | fp.WriteString(fmt.Sprintf("%4.2f ", math.Sqrt(fvar))) 200 | } else { 201 | fp.WriteString(fmt.Sprintf(" nan ")) 202 | } 203 | } 204 | fp.WriteString(fmt.Sprintf("\n")) 205 | } 206 | fp.WriteString(fmt.Sprintf("];\n")) 207 | fp.Close() 208 | } 209 | 210 | /* iontec() 3 */ 211 | func Test_ionexutest4(t *testing.T) { 212 | var fp *os.File 213 | var file3 string = "../data/sp3/igrg33*0.10i" 214 | var nav gnssgo.Nav 215 | var time1 gnssgo.Gtime 216 | var ep1 []float64 = []float64{2010, 12, 3, 12, 0, 0} 217 | var delay, fvar float64 218 | D2R := gnssgo.D2R 219 | var pos [3]float64 = [3]float64{25 * D2R, 135 * D2R, 0} 220 | var azel []float64 = []float64{75 * D2R, 90 * D2R} 221 | var i int 222 | assert := assert.New(t) 223 | 224 | time1 = gnssgo.Epoch2Time(ep1) 225 | nav.ReadTec(file3, 0) 226 | 227 | fp, _ = os.OpenFile("../data/testionex4.m", os.O_CREATE|os.O_WRONLY, os.ModeAppend|os.ModePerm) 228 | assert.NotEmpty(fp) 229 | 230 | fp.WriteString(fmt.Sprintf("tec=[\n")) 231 | for i = 0; i <= 86400*3; i += 30 { 232 | if nav.IonTec(gnssgo.TimeAdd(time1, float64(i)), pos[:], azel, 1, &delay, &fvar) != 0 { 233 | fp.WriteString(fmt.Sprintf("%6d %5.3f %5.3f\n", i, delay, math.Sqrt(fvar))) 234 | } else { 235 | fp.WriteString(fmt.Sprintf("%6d nan nan\n", i)) 236 | } 237 | } 238 | fp.WriteString(fmt.Sprintf("];\n")) 239 | fp.Close() 240 | } 241 | -------------------------------------------------------------------------------- /unittest/lambda_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : lambda/mlambda integer least square 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "gnssgo" 8 | "math" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | var a1 []float64 = []float64{ 15 | 1585184.171, 16 | -6716599.430, 17 | 3915742.905, 18 | 7627233.455, 19 | 9565990.879, 20 | 989457273.200} 21 | var Q1 []float64 = []float64{ 22 | 0.227134, 0.112202, 0.112202, 0.112202, 0.112202, 0.103473, 23 | 0.112202, 0.227134, 0.112202, 0.112202, 0.112202, 0.103473, 24 | 0.112202, 0.112202, 0.227134, 0.112202, 0.112202, 0.103473, 25 | 0.112202, 0.112202, 0.112202, 0.227134, 0.112202, 0.103473, 26 | 0.112202, 0.112202, 0.112202, 0.112202, 0.227134, 0.103473, 27 | 0.103473, 0.103473, 0.103473, 0.103473, 0.103473, 0.434339} 28 | var F1 []float64 = []float64{ 29 | 1585184.000000, 1585184.000000, 30 | -6716599.000000, -6716600.000000, 31 | 3915743.000000, 3915743.000000, 32 | 7627234.000000, 7627233.000000, 33 | 9565991.000000, 9565991.000000, 34 | 989457273.000000, 989457273.000000} 35 | var s1 []float64 = []float64{ 36 | 3.507984, 3.708456} 37 | var a2 []float64 = []float64{ 38 | -13324172.755747, 39 | -10668894.713608, 40 | -7157225.010770, 41 | -6149367.974367, 42 | -7454133.571066, 43 | -5969200.494550, 44 | 8336734.058423, 45 | 6186974.084502, 46 | -17549093.883655, 47 | -13970158.922370} 48 | var Q2 []float64 = []float64{ 49 | 0.446320, 0.223160, 0.223160, 0.223160, 0.223160, 0.572775, 0.286388, 0.286388, 0.286388, 0.286388, 50 | 0.223160, 0.446320, 0.223160, 0.223160, 0.223160, 0.286388, 0.572775, 0.286388, 0.286388, 0.286388, 51 | 0.223160, 0.223160, 0.446320, 0.223160, 0.223160, 0.286388, 0.286388, 0.572775, 0.286388, 0.286388, 52 | 0.223160, 0.223160, 0.223160, 0.446320, 0.223160, 0.286388, 0.286388, 0.286388, 0.572775, 0.286388, 53 | 0.223160, 0.223160, 0.223160, 0.223160, 0.446320, 0.286388, 0.286388, 0.286388, 0.286388, 0.572775, 54 | 0.572775, 0.286388, 0.286388, 0.286388, 0.286388, 0.735063, 0.367531, 0.367531, 0.367531, 0.367531, 55 | 0.286388, 0.572775, 0.286388, 0.286388, 0.286388, 0.367531, 0.735063, 0.367531, 0.367531, 0.367531, 56 | 0.286388, 0.286388, 0.572775, 0.286388, 0.286388, 0.367531, 0.367531, 0.735063, 0.367531, 0.367531, 57 | 0.286388, 0.286388, 0.286388, 0.572775, 0.286388, 0.367531, 0.367531, 0.367531, 0.735063, 0.367531, 58 | 0.286388, 0.286388, 0.286388, 0.286388, 0.572775, 0.367531, 0.367531, 0.367531, 0.367531, 0.735063} 59 | var F2 []float64 = []float64{ 60 | -13324188.000000, -13324188.000000, 61 | -10668901.000000, -10668908.000000, 62 | -7157236.000000, -7157236.000000, 63 | -6149379.000000, -6149379.000000, 64 | -7454143.000000, -7454143.000000, 65 | -5969220.000000, -5969220.000000, 66 | 8336726.000000, 8336717.000000, 67 | 6186960.000000, 6186960.000000, 68 | -17549108.000000, -17549108.000000, 69 | -13970171.000000, -13970171.000000} 70 | var s2 []float64 = []float64{ 71 | 1506.435789, 1612.811795} 72 | 73 | func Test_lambdautest1(t *testing.T) { 74 | var i, j, n, m, info int 75 | var F [6 * 2]float64 76 | var s [2]float64 77 | assert := assert.New(t) 78 | 79 | n = 6 80 | m = 2 81 | info = gnssgo.Lambda(n, m, a1, Q1, F[:], s[:]) 82 | 83 | assert.True(info == 0) 84 | 85 | for j = 0; j < m; j++ { 86 | for i = 0; i < n; i++ { 87 | assert.True(math.Abs(F[i+j*n]-F1[j+i*m]) < 1e-4) 88 | } 89 | assert.True(math.Abs(s[j]-s1[j]) < 1e-4) 90 | } 91 | } 92 | func Test_lambdautest2(t *testing.T) { 93 | var i, j, n, m, info int 94 | var F [10 * 2]float64 95 | var s [2]float64 96 | assert := assert.New(t) 97 | 98 | n = 10 99 | m = 2 100 | info = gnssgo.Lambda(n, m, a2, Q2, F[:], s[:]) 101 | assert.True(info == 0) 102 | 103 | for j = 0; j < m; j++ { 104 | for i = 0; i < n; i++ { 105 | assert.True(math.Abs(F[i+j*n]-F2[j+i*m]) < 1e-4) 106 | } 107 | assert.True(math.Abs(s[j]-s2[j]) < 1e-4) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /unittest/matrix_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * gnssgo unit test driver : matrix and vector functions 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "math" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func dbout1(x, y, P, H, R []float64, n, m int) { 16 | fmt.Printf("x=[\n") 17 | gnssgo.MatPrint(x, n, 1, 8, 4) 18 | fmt.Printf("];\n") 19 | fmt.Printf("y=[\n") 20 | gnssgo.MatPrint(y, m, 1, 8, 4) 21 | fmt.Printf("];\n") 22 | fmt.Printf("P=[\n") 23 | gnssgo.MatPrint(P, n, n, 8, 4) 24 | fmt.Printf("];\n") 25 | fmt.Printf("H=[\n") 26 | gnssgo.MatPrint(H, m, n, 8, 4) 27 | fmt.Printf("];\n") 28 | fmt.Printf("R=[\n") 29 | gnssgo.MatPrint(R, m, m, 8, 4) 30 | fmt.Printf("];\n") 31 | } 32 | 33 | func dbout2(x, P []float64, n int) { 34 | fmt.Printf("xu=[\n") 35 | gnssgo.MatPrint(x, n, 1, 8, 4) 36 | fmt.Printf("];\n") 37 | fmt.Printf("Pu=[\n") 38 | gnssgo.MatPrint(P, n, n, 8, 4) 39 | fmt.Printf("];\n") 40 | fmt.Printf("K=P*H'/(H*P*H'+R);\n") 41 | 42 | fmt.Printf("xd=x+K*y;\n") 43 | fmt.Printf("Pd=P-K*H*P\n") 44 | fmt.Printf("xu-xd,Pu-Pd\n") 45 | } 46 | 47 | /* mat(),gnssgo.IMat(),gnssgo.Zeros(),gnssgo.Eye() */ 48 | func Test_matrixutest1(t *testing.T) { 49 | var i, j int 50 | var n, m = 100, 200 51 | var b []int 52 | var a []float64 53 | assert := assert.New(t) 54 | a = gnssgo.Mat(0, 0) 55 | assert.True(a == nil) 56 | a = gnssgo.Mat(0, 1) 57 | assert.True(a == nil) 58 | a = gnssgo.Mat(1, 0) 59 | assert.True(a == nil) 60 | a = gnssgo.Mat(1, 1) 61 | assert.True(a != nil) 62 | a = nil 63 | /* a=gnssgo.Mat(1000000,1000000); assert.True(a==nil); */ 64 | a = gnssgo.Zeros(0, m) 65 | assert.True(a == nil) 66 | a = gnssgo.Zeros(n, 0) 67 | assert.True(a == nil) 68 | a = gnssgo.Zeros(n, m) 69 | assert.True(a != nil) 70 | for i = 0; i < n; i++ { 71 | for j = 0; j < m; j++ { 72 | assert.True(a[i+j*n] == 0.0) 73 | } 74 | } 75 | a = nil 76 | /* a=gnssgo.Zeros(10000000,1000000); assert.True(a==nil); */ 77 | a = gnssgo.Eye(0) 78 | assert.True(a == nil) 79 | a = gnssgo.Eye(n) 80 | assert.True(a != nil) 81 | for i = 0; i < n; i++ { 82 | for j = 0; j < n; j++ { 83 | if i == j { 84 | assert.True(a[i+j*n] == 1.0) 85 | } else { 86 | assert.True(a[i+j*n] == 0.0) 87 | } 88 | } 89 | } 90 | a = nil 91 | /* a=gnssgo.Eye(1000000); assert.True(a==nil); */ 92 | b = gnssgo.IMat(0, m) 93 | assert.True(b == nil) 94 | b = gnssgo.IMat(n, 0) 95 | assert.True(b == nil) 96 | b = gnssgo.IMat(n, m) 97 | assert.True(b != nil) 98 | b = nil 99 | /* 100 | a=gnssgo.IMat(1000000,1000000); assert.True(a==nil); 101 | */ 102 | 103 | } 104 | 105 | /* gnssgo.Dot() */ 106 | func Test_matrixutest2(t *testing.T) { 107 | var i int 108 | var a []float64 = []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0} 109 | var b []float64 = []float64{7.0, 8.0, 9.0, 1.4, 1.6, 7.8} 110 | var c, d float64 111 | assert := assert.New(t) 112 | for i, d = 0, 0.0; i < 6; i++ { 113 | d += a[i] * b[i] 114 | } 115 | c = gnssgo.Dot(a, b, 0) 116 | assert.True(c == 0.0) 117 | c = gnssgo.Dot(a, b, 6) 118 | assert.True(math.Abs(c-d) < 1e-14) 119 | for i, d = 0, 0.0; i < 6; i++ { 120 | d += a[i] * a[i] 121 | } 122 | d = math.Sqrt(d) 123 | c = gnssgo.Norm(a, 6) 124 | assert.True(math.Abs(c-d) < 1e-14) 125 | for i, d = 0, 0.0; i < 6; i++ { 126 | d += b[i] * b[i] 127 | } 128 | d = math.Sqrt(d) 129 | c = gnssgo.Norm(b, 6) 130 | assert.True(math.Abs(c-d) < 1e-14) 131 | } 132 | 133 | var A []float64 = []float64{ 134 | 0.935469699107605, 0.893649530913534, 135 | 0.916904439913408, 0.0578913047842686, 136 | 0.410270206990945, 0.352868132217} 137 | var B []float64 = []float64{ 138 | 0.813166497303758, 0.13889088195695, 139 | 0.00986130066092356, 0.202765218560273} 140 | var AB []float64 = []float64{ 141 | 0.769505165266963, 0.311129254005026, 142 | 0.74616685532878, 0.139088009397138, 143 | 0.337097725912365, 0.128532174841568} 144 | var ABT []float64 = []float64{ 145 | 0.884812390066127, 0.190425990414052, 146 | 0.753636546145776, 0.0207802134266434, 147 | 0.382628153265035, 0.0755951818152924} 148 | var invB []float64 = []float64{ 149 | 1.24006142464565, -0.849421938204008, 150 | -0.0603092514252338, 4.97312316323555} 151 | 152 | /* gnssgo.MatMul() */ 153 | func Test_matrixutest3(t *testing.T) { 154 | var i, j int 155 | var C [6]float64 156 | assert := assert.New(t) 157 | gnssgo.MatMul("TT", 3, 2, 2, 1.0, A, B, 0.0, C[:]) 158 | for i = 0; i < 3; i++ { 159 | for j = 0; j < 2; j++ { 160 | assert.True(math.Abs(C[i+j*3]-AB[j+i*2]) < 1e-9) 161 | } 162 | } 163 | 164 | gnssgo.MatMul("NN", 2, 3, 2, 1.0, B, A, 0.0, C[:]) 165 | for i = 0; i < 2; i++ { 166 | for j = 0; j < 3; j++ { 167 | assert.True(math.Abs(C[i+j*2]-AB[i+j*2]) < 1e-9) 168 | } 169 | } 170 | 171 | gnssgo.MatMul("TN", 3, 2, 2, 1.0, A, B, 0.0, C[:]) 172 | for i = 0; i < 3; i++ { 173 | for j = 0; j < 2; j++ { 174 | assert.True(math.Abs(C[i+j*3]-ABT[j+i*2]) < 1e-9) 175 | } 176 | } 177 | 178 | gnssgo.MatMul("TN", 2, 3, 2, 1.0, B, A, 0.0, C[:]) 179 | for i = 0; i < 2; i++ { 180 | for j = 0; j < 3; j++ { 181 | assert.True(math.Abs(C[i+j*2]-ABT[i+j*2]) < 1e-9) 182 | } 183 | } 184 | 185 | } 186 | 187 | /* matinv() */ 188 | func Test_matrixutest4(t *testing.T) { 189 | var i, j int 190 | var C [4]float64 191 | assert := assert.New(t) 192 | copy(C[:], B[:4]) 193 | gnssgo.MatInv(B, 2) 194 | for i = 0; i < 2; i++ { 195 | for j = 0; j < 2; j++ { 196 | assert.True(math.Abs(B[i+j*2]-invB[i+j*2]) < 1e-9) 197 | } 198 | } 199 | gnssgo.MatInv(B, 2) 200 | for i = 0; i < 2; i++ { 201 | for j = 0; j < 2; j++ { 202 | assert.True(math.Abs(B[i+j*2]-C[i+j*2]) < 1e-9) 203 | } 204 | } 205 | } 206 | 207 | var H []float64 = []float64{ 208 | 0.123, 0.345, 0.567, 209 | 0.890, -0.135, 0.791, 210 | 1.020, 2.489, 0.111, 211 | 0.321, -1.002, 5.678} 212 | var y []float64 = []float64{ 213 | 0.3456, 214 | 1.5678, 215 | 0.1047, 216 | 0.1047} 217 | var xs []float64 = []float64{ 218 | 1.77586016656388, 219 | -0.64484683008484, 220 | -0.18684144028875} 221 | var Qs []float64 = []float64{ 222 | 1.41343666098904, -0.56122396983116, -0.20536436422033, 223 | -0.56122396983117, 0.37710272892140, 0.10628198948746, 224 | -0.20536436422033, 0.10628198948746, 0.06392702788446} 225 | 226 | /* lsq() */ 227 | func Test_matrixutest5(t *testing.T) { 228 | var i int 229 | var x [3]float64 230 | var Q [9]float64 231 | assert := assert.New(t) 232 | gnssgo.LSQ(H, y, 3, 4, x[:], Q[:]) 233 | for i = 0; i < 3; i++ { 234 | assert.True(math.Abs(x[i]-xs[i]) < 1e-9) 235 | } 236 | for i = 0; i < 9; i++ { 237 | assert.True(math.Abs(Q[i]-Qs[i]) < 1e-9) 238 | } 239 | } 240 | 241 | /* matcpy() */ 242 | func Test_matrixutest6(t *testing.T) { 243 | assert := assert.New(t) 244 | a := gnssgo.Mat(100, 200) 245 | b := gnssgo.Zeros(100, 200) 246 | c := 0.0 247 | var i, j int 248 | for i = 0; i < 100; i++ { 249 | for j = 0; j < 200; j++ { 250 | a[i+j*100] = c 251 | c += 1.0 252 | } 253 | } 254 | gnssgo.MatCpy(b, a, 100, 200) 255 | for i, c = 0, 0.0; i < 100; i++ { 256 | for j = 0; j < 200; j++ { 257 | assert.True(a[i+j*100] == b[i+j*100]) 258 | } 259 | } 260 | 261 | } 262 | -------------------------------------------------------------------------------- /unittest/misc_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * gnssgo unit test driver : misc functions 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "strings" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | /* expath() */ 16 | func utest11(path string) { 17 | var paths [32]string 18 | var i, n int 19 | n = gnssgo.ExPath(path, paths[:], 32) 20 | fmt.Printf("\npath =%s\n", path) 21 | fmt.Printf("paths=\n") 22 | for i = 0; i < n; i++ { 23 | fmt.Printf("%s\n", paths[i]) 24 | } 25 | } 26 | func Test_miscutest1(t *testing.T) { 27 | utest11("") 28 | utest11("*") 29 | utest11("*.*") 30 | utest11("*.go") 31 | utest11("*.g*") 32 | utest11("*_test.*") 33 | utest11("misc_test.go") 34 | utest11("m*_test.go") 35 | utest11("misc_t*t.go") 36 | utest11("m*sc*_t*t.go") 37 | utest11("m*sc*t*") 38 | utest11("*.") 39 | utest11(".*") 40 | utest11("misc_test") 41 | utest11("_test.go") 42 | utest11("c:\\*") 43 | utest11("c:\\windows*") 44 | utest11("c:\\windows\\*") 45 | } 46 | 47 | /* reppath() */ 48 | func Test_miscutest2(t *testing.T) { 49 | var t0, t1, t2 gnssgo.Gtime 50 | var ep1 []float64 = []float64{1990, 1, 1, 0, 0, 0.00000} 51 | var ep2 []float64 = []float64{2010, 12, 31, 23, 59, 59.99999} 52 | var path0 string = "01234567890123456789" 53 | var path1 string = "abcde_%Y/%m/%d_%h:%M:%S_%Y%m%d%h%M%S" 54 | var path2 string = "abcde_%y%n_%W%D%H_%ha%hb%hc" 55 | var path3 string = "rover %r %r base %b %b" 56 | var path4 string = "%a %b %c" 57 | var rpath string 58 | var rov string = "RRRRRRRR" 59 | var base string = "BBBBBBBB" 60 | var stat int 61 | 62 | assert := assert.New(t) 63 | t1 = gnssgo.Epoch2Time(ep1) 64 | t2 = gnssgo.Epoch2Time(ep2) 65 | 66 | stat = gnssgo.RepPath(path0, &rpath, t1, "", "") 67 | assert.True(stat == 0) 68 | stat = strings.Compare(rpath, path0) 69 | assert.True(stat == 0) 70 | stat = gnssgo.RepPath(path0, &rpath, t0, rov, base) 71 | assert.True(stat == 0) 72 | stat = strings.Compare(rpath, path0) 73 | assert.True(stat == 0) 74 | stat = gnssgo.RepPath(path0, &rpath, t1, rov, base) 75 | assert.True(stat == 0) 76 | stat = strings.Compare(rpath, path0) 77 | assert.True(stat == 0) 78 | stat = gnssgo.RepPath(path1, &rpath, t1, "", "") 79 | assert.True(stat == 1) 80 | stat = strings.Compare(rpath, "abcde_1990/01/01_00:00:00_19900101000000") 81 | assert.True(stat == 0) 82 | stat = gnssgo.RepPath(path2, &rpath, t2, rov, base) 83 | assert.True(stat == 1) 84 | stat = strings.Compare(rpath, "abcde_10365_16165x_211812") 85 | assert.True(stat == 0) 86 | stat = gnssgo.RepPath(path3, &rpath, t0, rov, base) 87 | assert.True(stat == 1) 88 | stat = strings.Compare(rpath, "rover RRRRRRRR RRRRRRRR base BBBBBBBB BBBBBBBB") 89 | assert.True(stat == 0) 90 | stat = gnssgo.RepPath(path4, &rpath, t1, rov, "") 91 | assert.True(stat == 0) 92 | stat = strings.Compare(rpath, "%a %b %c") 93 | assert.True(stat == 0) 94 | } 95 | 96 | /* gnssgo.RepPaths() */ 97 | func Test_miscutest3(t *testing.T) { 98 | var t0, t1, t2, t3, t4 gnssgo.Gtime 99 | var ep1 []float64 = []float64{2010, 7, 31, 21, 36, 50.00000} 100 | var ep2 []float64 = []float64{2010, 8, 1, 4, 0, 0.00000} 101 | var ep3 []float64 = []float64{2010, 8, 31, 0, 0, 0.00000} 102 | var ep4 []float64 = []float64{2012, 1, 31, 0, 0, 0.00000} 103 | var path0 string = "01234567890123456789" 104 | var path1 string = "abcde_%Y/%m/%d_%h:%M:%S_%Y%m%d%h%M%S" 105 | var path2 string = "%r_%b_%r_%b_%y%n_%W%D%H_%ha%hb%hc" 106 | var path4 string = "YEAR=%Y GPSWEEK=%W" 107 | var paths [100]string 108 | var i, n, stat int 109 | assert := assert.New(t) 110 | 111 | t1 = gnssgo.Epoch2Time(ep1) 112 | t2 = gnssgo.Epoch2Time(ep2) 113 | t3 = gnssgo.Epoch2Time(ep3) 114 | t4 = gnssgo.Epoch2Time(ep4) 115 | 116 | n = gnssgo.RepPaths(path1, paths[:], 10, t0, t1, "ROV", "BASE") 117 | assert.True(n == 0) 118 | n = gnssgo.RepPaths(path1, paths[:], 10, t1, t0, "ROV", "BASE") 119 | assert.True(n == 0) 120 | n = gnssgo.RepPaths(path1, paths[:], 0, t1, t2, "ROV", "BASE") 121 | assert.True(n == 0) 122 | n = gnssgo.RepPaths(path1, paths[:], 10, t2, t1, "ROV", "BASE") 123 | assert.True(n == 0) 124 | n = gnssgo.RepPaths(path0, paths[:], 10, t1, t2, "ROV", "BASE") 125 | assert.True(n == 1) 126 | stat = strings.Compare(paths[0], path0) 127 | assert.True(stat == 0) 128 | n = gnssgo.RepPaths(path1, paths[:], 100, t1, t2, "ROV", "BASE") 129 | for i = 0; i < n; i++ { 130 | fmt.Printf("paths[%2d]=%s\n", i, paths[i]) 131 | } 132 | fmt.Printf("\n") 133 | assert.True(n == 27) 134 | stat = strings.Compare(paths[0], "abcde_2010/07/31_21:30:00_20100731213000") 135 | assert.True(stat == 0) 136 | stat = strings.Compare(paths[26], "abcde_2010/08/01_04:00:00_20100801040000") 137 | assert.True(stat == 0) 138 | n = gnssgo.RepPaths(path2, paths[:], 100, t1, t3, "ROV", "BASE") 139 | for i = 0; i < n; i++ { 140 | fmt.Printf("paths[%2d]=%s\n", i, paths[i]) 141 | } 142 | fmt.Printf("\n") 143 | assert.True(n == 100) 144 | stat = strings.Compare(paths[0], "ROV_BASE_ROV_BASE_10212_15946v_211812") 145 | assert.True(stat == 0) 146 | stat = strings.Compare(paths[99], "ROV_BASE_ROV_BASE_10217_15954a_000000") 147 | assert.True(stat == 0) 148 | n = gnssgo.RepPaths(path4, paths[:], 100, t1, t4, "ROV", "BASE") 149 | for i = 0; i < n; i++ { 150 | fmt.Printf("paths[%2d]=%s\n", i, paths[i]) 151 | } 152 | fmt.Printf("\n") 153 | assert.True(n == 81) 154 | stat = strings.Compare(paths[0], "YEAR=2010 GPSWEEK=1594") 155 | assert.True(stat == 0) 156 | stat = strings.Compare(paths[80], "YEAR=2012 GPSWEEK=1673") 157 | assert.True(stat == 0) 158 | } 159 | 160 | /* gnssgo.GetBitU(),gnssgo.GetBits(),gnssgo.SetBitU(),gnssgo.SetBits() */ 161 | func Test_miscutest4(t *testing.T) { 162 | var buff [1024]uint8 163 | var vu uint32 164 | var vs uint32 165 | var vui int32 166 | var vsi int32 167 | assert := assert.New(t) 168 | 169 | gnssgo.SetBitU(buff[:], 0, 8, 1) 170 | vu = gnssgo.GetBitU(buff[:], 0, 8) 171 | assert.True(vu == 1) 172 | gnssgo.SetBitU(buff[:], 4, 8, 255) 173 | vu = gnssgo.GetBitU(buff[:], 4, 8) 174 | assert.True(vu == 255) 175 | gnssgo.SetBitU(buff[:], 13, 8, 1) 176 | vu = gnssgo.GetBitU(buff[:], 13, 8) 177 | assert.True(vu == 1) 178 | gnssgo.SetBitU(buff[:], 29, 8, 255) 179 | vu = gnssgo.GetBitU(buff[:], 29, 8) 180 | assert.True(vu == 255) 181 | gnssgo.SetBitU(buff[:], 99, 10, 1023) 182 | vu = gnssgo.GetBitU(buff[:], 99, 10) 183 | assert.True(vu == 1023) 184 | gnssgo.SetBitU(buff[:], 666, 31, 123456) 185 | vu = gnssgo.GetBitU(buff[:], 666, 31) 186 | assert.True(vu == 123456) 187 | gnssgo.SetBitU(buff[:], 777, 32, 789012) 188 | vu = gnssgo.GetBitU(buff[:], 777, 32) 189 | assert.True(vu == 789012) 190 | 191 | gnssgo.SetBits(buff[:], 100, 8, 1) 192 | vs = gnssgo.GetBitU(buff[:], 100, 8) 193 | assert.True(vs == 1) 194 | gnssgo.SetBits(buff[:], 104, 8, 127) 195 | vs = gnssgo.GetBitU(buff[:], 104, 8) 196 | assert.True(vs == 127) 197 | gnssgo.SetBits(buff[:], 113, 8, 1) 198 | vs = gnssgo.GetBitU(buff[:], 113, 8) 199 | assert.True(vs == 1) 200 | gnssgo.SetBits(buff[:], 129, 8, 127) 201 | vs = gnssgo.GetBitU(buff[:], 129, 8) 202 | assert.True(vs == 127) 203 | gnssgo.SetBits(buff[:], 199, 10, 511) 204 | vs = gnssgo.GetBitU(buff[:], 199, 10) 205 | assert.True(vs == 511) 206 | gnssgo.SetBits(buff[:], 766, 31, 123456) 207 | vs = gnssgo.GetBitU(buff[:], 766, 31) 208 | assert.True(vs == 123456) 209 | gnssgo.SetBits(buff[:], 877, 32, 789012) 210 | vs = gnssgo.GetBitU(buff[:], 877, 32) 211 | assert.True(vs == 789012) 212 | 213 | gnssgo.SetBits(buff[:], 200, 8, -1) 214 | vsi = gnssgo.GetBits(buff[:], 200, 8) 215 | assert.True(vsi == -1) 216 | gnssgo.SetBits(buff[:], 204, 8, -127) 217 | vsi = gnssgo.GetBits(buff[:], 204, 8) 218 | assert.True(vsi == -127) 219 | gnssgo.SetBits(buff[:], 213, 8, -3) 220 | vui = gnssgo.GetBits(buff[:], 213, 8) 221 | assert.True(vui == -3) 222 | gnssgo.SetBits(buff[:], 229, 8, -126) 223 | vui = gnssgo.GetBits(buff[:], 229, 8) 224 | assert.True(vui == -126) 225 | gnssgo.SetBits(buff[:], 299, 24, -99999) 226 | vui = gnssgo.GetBits(buff[:], 299, 24) 227 | assert.True(vui == -99999) 228 | gnssgo.SetBits(buff[:], 866, 31, -12345) 229 | vsi = gnssgo.GetBits(buff[:], 866, 31) 230 | assert.True(vsi == -12345) 231 | gnssgo.SetBits(buff[:], 977, 32, -67890) 232 | vsi = gnssgo.GetBits(buff[:], 977, 32) 233 | assert.True(vsi == -67890) 234 | 235 | } 236 | -------------------------------------------------------------------------------- /unittest/ppp_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : ppp functions 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "math" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | /* eci2ecef() */ 16 | func Test_ppputest1(t *testing.T) { 17 | var ep1 []float64 = []float64{1999, 3, 4, 0, 0, 0} 18 | var gmst float64 19 | var U [9]float64 20 | D2R := gnssgo.D2R 21 | var U1 []float64 = []float64{ 22 | -0.947378027425279, 0.320116956820115, -8.43090456427539e-005, 23 | -0.32011695222455, -0.947378030590727, -6.36592598714651e-005, 24 | -0.00010025094616549, -3.33206293083182e-005, 0.999999994419742} 25 | var erpv [5]float64 = [5]float64{0.06740 * D2R / 3600, 0.24713 * D2R / 3600, 0.649232} 26 | var i, j int 27 | assert := assert.New(t) 28 | 29 | gnssgo.Eci2Ecef(gnssgo.Epoch2Time(ep1), erpv[:], U[:], &gmst) 30 | 31 | for i = 0; i < 3; i++ { 32 | for j = 0; j < 3; j++ { 33 | fmt.Printf("U(%d,%d)=%15.12f %15.12f %15.12f\n", i, j, 34 | U[i+j*3], U1[j+i*3], U[i+j*3]-U1[j+i*3]) 35 | assert.True(math.Abs(U[i+j*3]-U1[j+i*3]) < 1e-11) 36 | } 37 | } 38 | } 39 | 40 | /* sunmoonpos() */ 41 | func Test_ppputest2(t *testing.T) { 42 | var ep1 []float64 = []float64{2010, 12, 31, 8, 9, 10} /* utc */ 43 | var rs []float64 = []float64{70842740307.0837, 115293403265.153, -57704700666.9715} /* de405 */ 44 | var rm []float64 = []float64{350588081.147922, 29854134.6432052, -136870369.169738} 45 | var rsun, rmoon [3]float64 46 | var erpv [5]float64 47 | var i int 48 | assert := assert.New(t) 49 | 50 | gnssgo.SunMoonPos(gnssgo.Epoch2Time(ep1), erpv[:], rsun[:], rmoon[:], nil) 51 | fmt.Printf("X_sun =%15.0f %15.0f %7.4f\n", rsun[0], rs[0], (rsun[0]-rs[0])/rsun[0]) 52 | fmt.Printf("Y_sun =%15.0f %15.0f %7.4f\n", rsun[1], rs[1], (rsun[1]-rs[1])/rsun[1]) 53 | fmt.Printf("Z_sun =%15.0f %15.0f %7.4f\n", rsun[2], rs[2], (rsun[2]-rs[2])/rsun[2]) 54 | fmt.Printf("X_moon=%15.0f %15.0f %7.4f\n", rmoon[0], rm[0], (rmoon[0]-rm[0])/rmoon[0]) 55 | fmt.Printf("Y_moon=%15.0f %15.0f %7.4f\n", rmoon[1], rm[1], (rmoon[1]-rm[1])/rmoon[1]) 56 | fmt.Printf("Z_moon=%15.0f %15.0f %7.4f\n", rmoon[2], rm[2], (rmoon[2]-rm[2])/rmoon[2]) 57 | 58 | for i = 0; i < 3; i++ { 59 | assert.True(math.Abs((rsun[i]-rs[i])/rsun[i]) < 0.03) 60 | assert.True(math.Abs((rmoon[i]-rm[i])/rmoon[i]) < 0.03) 61 | } 62 | } 63 | 64 | /* tidedisp() */ 65 | func Test_ppputest3(t *testing.T) { 66 | var ep1 []float64 = []float64{2010, 6, 7, 1, 2, 3} 67 | var rr []float64 = []float64{-3957198.431, 3310198.621, 3737713.474} /* TSKB */ 68 | var dp []float64 = []float64{-0.05294, 0.075607, 0.03644} 69 | var dr [3]float64 = [3]float64{0} 70 | var i int 71 | assert := assert.New(t) 72 | 73 | gnssgo.TideDisp(gnssgo.Epoch2Time(ep1), rr, 1, nil, nil, dr[:]) 74 | 75 | fmt.Printf("X_disp=%8.5f %8.5f %8.5f\n", dr[0], dp[0], dr[0]-dp[0]) 76 | fmt.Printf("Y_disp=%8.5f %8.5f %8.5f\n", dr[1], dp[1], dr[1]-dp[1]) 77 | fmt.Printf("Z_disp=%8.5f %8.5f %8.5f\n", dr[2], dp[2], dr[2]-dp[2]) 78 | 79 | for i = 0; i < 3; i++ { 80 | assert.True(math.Abs(dr[i]-dp[i]) < 0.001) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /unittest/preceph_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : precise ephemeris function 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "os" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func dumpeph(peph []gnssgo.PEph, n int) { 16 | var s string 17 | var i, j int 18 | for i = 0; i < n; i++ { 19 | gnssgo.Time2Str(peph[i].Time, &s, 3) 20 | fmt.Printf("time=%s\n", s) 21 | for j = 0; j < gnssgo.MAXSAT; j++ { 22 | fmt.Printf("%03d: %14.3f %14.3f %14.3f : %5.3f %5.3f %5.3f\n", 23 | j+1, peph[i].Pos[j][0], peph[i].Pos[j][1], peph[i].Pos[j][2], 24 | peph[i].Std[j][0], peph[i].Std[j][1], peph[i].Std[j][2]) 25 | } 26 | } 27 | } 28 | func dumpclk(pclk []gnssgo.PClk, n int) { 29 | var s string 30 | var i, j int 31 | for i = 0; i < n; i++ { 32 | gnssgo.Time2Str(pclk[i].Time, &s, 3) 33 | fmt.Printf("time=%s\n", s) 34 | for j = 0; j < gnssgo.MAXSAT; j++ { 35 | fmt.Printf("%03d: %14.3f : %5.3f\n", 36 | j+1, pclk[i].Clk[j][0]*1e9, pclk[i].Std[j][0]*1e9) 37 | } 38 | } 39 | } 40 | 41 | /* readsp3() */ 42 | func Test_precephutest1(t *testing.T) { 43 | var file1 string = "../data/sp3/igs15904.sp4" 44 | var file2 string = "../data/sp3/igs15904.sp3" 45 | var file3 string = "../data/sp3/igs1590*.sp3" 46 | var nav gnssgo.Nav 47 | assert := assert.New(t) 48 | 49 | fmt.Printf("file=%s\n", file1) 50 | nav.ReadSp3(file1, 0) 51 | assert.True(nav.Ne() == 0) 52 | 53 | fmt.Printf("file=%s\n", file2) 54 | nav.ReadSp3(file2, 0) 55 | assert.True(nav.Ne() == 96) 56 | dumpeph(nav.Peph, nav.Ne()) 57 | 58 | fmt.Printf("file=%s\n", file3) 59 | nav.ReadSp3(file3, 0) 60 | assert.True(nav.Ne() == 192) 61 | dumpeph(nav.Peph, nav.Ne()) 62 | } 63 | 64 | /* readsap() */ 65 | func Test_precephutest2(t *testing.T) { 66 | var ep1 []float64 = []float64{2008, 3, 1, 0, 0, 0} 67 | var ep2 []float64 = []float64{2006, 11, 4, 23, 59, 59} 68 | var file1 string = "../data/sp3/igs06.atx" 69 | var file2 string = "../data/igs05.atx" 70 | var pcvs gnssgo.Pcvs 71 | var pcv *gnssgo.Pcv 72 | var time gnssgo.Gtime 73 | var i, stat int 74 | assert := assert.New(t) 75 | 76 | fmt.Printf("file=%s\n", file1) 77 | stat = gnssgo.ReadPcv(file1, &pcvs) 78 | assert.True(stat == 0) 79 | stat = gnssgo.ReadPcv(file2, &pcvs) 80 | assert.True(stat != 0) 81 | 82 | time = gnssgo.Epoch2Time(ep1) 83 | for i = 0; i < gnssgo.MAXSAT; i++ { 84 | if pcv = gnssgo.SearchPcv(i+1, "", time, &pcvs); pcv == nil { 85 | continue 86 | } 87 | fmt.Printf("PRN%02d : %7.4f %7.4f %7.4f\n", i+1, pcv.Offset[0][0], pcv.Offset[0][1], pcv.Offset[0][2]) 88 | } 89 | time = gnssgo.Epoch2Time(ep2) 90 | for i = 0; i < gnssgo.MAXSAT; i++ { 91 | if pcv = gnssgo.SearchPcv(i+1, "", time, &pcvs); pcv == nil { 92 | continue 93 | } 94 | fmt.Printf("PRN%02d : %7.4f %7.4f %7.4f\n", i+1, pcv.Offset[0][0], pcv.Offset[0][1], pcv.Offset[0][2]) 95 | } 96 | } 97 | 98 | /* readrnxc() */ 99 | func Test_precephutest3(t *testing.T) { 100 | var file1 string = "../data/sp3/igs15904.cls" 101 | var file2 string = "../data/sp3/igs15904.clk" 102 | var file3 string = "../data/sp3/igs1590*.clk" 103 | var nav gnssgo.Nav 104 | assert := assert.New(t) 105 | 106 | fmt.Printf("file=%s\n", file1) 107 | nav.ReadRnxC(file1) 108 | assert.True(nav.Nc() == 0) 109 | 110 | fmt.Printf("file=%s\n", file2) 111 | nav.ReadRnxC(file2) 112 | assert.True(nav.Nc() > 0) 113 | dumpclk(nav.Pclk, nav.Nc()) 114 | nav.Pclk = nil 115 | 116 | fmt.Printf("file=%s\n", file3) 117 | nav.ReadRnxC(file3) 118 | assert.True(nav.Nc() > 0) 119 | dumpclk(nav.Pclk, nav.Nc()) 120 | nav.Pclk = nil 121 | } 122 | 123 | /* peph2pos() */ 124 | func Test_precephutest4(t *testing.T) { 125 | var fp *os.File 126 | var file1 string = "../data/sp3/igs1590*.sp3" /* 2010/7/1 */ 127 | var file2 string = "../data/sp3/igs1590*.clk" /* 2010/7/1 */ 128 | var nav gnssgo.Nav 129 | var i, j, stat, sat int 130 | var ep []float64 = []float64{2010, 7, 1, 0, 0, 0} 131 | var rs [6]float64 132 | var dts [2]float64 133 | var fvar float64 134 | var tm, time gnssgo.Gtime 135 | assert := assert.New(t) 136 | 137 | time = gnssgo.Epoch2Time(ep) 138 | 139 | nav.ReadSp3(file1, 0) 140 | assert.True(nav.Ne() > 0) 141 | nav.ReadRnxC(file2) 142 | assert.True(nav.Nc() > 0) 143 | stat = nav.PEph2Pos(time, 0, 0, rs[:], dts[:], &fvar) 144 | assert.True(stat == 0) 145 | stat = nav.PEph2Pos(time, 160, 0, rs[:], dts[:], &fvar) 146 | assert.True(stat == 0) 147 | 148 | fp, _ = os.OpenFile("../out/testpeph1.out", os.O_CREATE|os.O_WRONLY, os.ModePerm|os.ModeAppend) 149 | 150 | sat = 4 151 | 152 | for i = 0; i < 86400*2; i += 30 { 153 | tm = gnssgo.TimeAdd(time, float64(i)) 154 | for j = 0; j < 6; j++ { 155 | rs[j] = 0.0 156 | } 157 | for j = 0; j < 2; j++ { 158 | dts[j] = 0.0 159 | } 160 | nav.PEph2Pos(tm, sat, 0, rs[:], dts[:], &fvar) 161 | fp.WriteString(fmt.Sprintf("%02d %6d %14.3f %14.3f %14.3f %14.3f %10.3f %10.3f %10.3f %10.3f\n", 162 | sat, i, rs[0], rs[1], rs[2], dts[0]*1e9, rs[3], rs[4], rs[5], dts[1]*1e9)) 163 | } 164 | fp.Close() 165 | } 166 | 167 | /* satpos() */ 168 | func Test_precephutest5(t *testing.T) { 169 | var fp *os.File 170 | var file1 string = "../data/sp3/igs1590*.sp3" /* 2010/7/1 */ 171 | var file2 string = "../data/sp3/igs1590*.clk" /* 2010/7/1 */ 172 | var file3 string = "../data/igs05.atx" 173 | var file4 string = "../data/rinex/brdc*.10n" 174 | var pcvs gnssgo.Pcvs 175 | var pcv *gnssgo.Pcv 176 | var nav gnssgo.Nav 177 | var i, stat, sat, svh int 178 | var ep []float64 = []float64{2010, 7, 1, 0, 0, 0} 179 | var rs1, rs2 [6]float64 180 | var dts1, dts2 [2]float64 181 | var fvar float64 182 | var tm, time gnssgo.Gtime 183 | assert := assert.New(t) 184 | 185 | time = gnssgo.Epoch2Time(ep) 186 | 187 | nav.ReadSp3(file1, 0) 188 | assert.True(nav.Ne() > 0) 189 | nav.ReadRnxC(file2) 190 | assert.True(nav.Nc() > 0) 191 | stat = gnssgo.ReadPcv(file3, &pcvs) 192 | assert.True(stat != 0) 193 | gnssgo.ReadRnx(file4, 1, "", nil, &nav, nil) 194 | assert.True(nav.N() > 0) 195 | for i = 0; i < gnssgo.MAXSAT; i++ { 196 | if pcv = gnssgo.SearchPcv(i+1, "", time, &pcvs); pcv == nil { 197 | continue 198 | } 199 | nav.Pcvs[i] = *pcv 200 | } 201 | fp, _ = os.OpenFile("../out/testpeph2.out", os.O_CREATE|os.O_WRONLY, os.ModePerm|os.ModeAppend) 202 | 203 | sat = 3 204 | 205 | for i = 0; i < 86400*2; i += 30 { 206 | tm = gnssgo.TimeAdd(time, float64(i)) 207 | nav.SatPos(tm, tm, sat, gnssgo.EPHOPT_BRDC, rs1[:], dts1[:], &fvar, &svh) 208 | nav.SatPos(tm, tm, sat, gnssgo.EPHOPT_PREC, rs2[:], dts2[:], &fvar, &svh) 209 | fp.WriteString(fmt.Sprintf("%02d %6d %14.3f %14.3f %14.3f %14.3f %14.3f %14.3f %14.3f %14.3f\n", 210 | sat, i, 211 | rs1[0], rs1[1], rs1[2], dts1[0]*1e9, rs2[0], rs2[1], rs2[2], dts2[0]*1e9)) 212 | } 213 | fp.Close() 214 | } 215 | -------------------------------------------------------------------------------- /unittest/renix_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * gnssgo unit test driver : rinex function 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "os" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func dumpobs(obs *gnssgo.Obs, t *testing.T) { 16 | var time gnssgo.Gtime 17 | var i int 18 | var str string 19 | assert := assert.New(t) 20 | fmt.Printf("obs : n=%d\n", obs.N()) 21 | for i = 0; i < obs.N(); i++ { 22 | gnssgo.Time2Str(obs.Data[i].Time, &str, 3) 23 | fmt.Printf("%s : %2d %2d %13.3f %13.3f %13.3f %13.3f %d %d\n", str, obs.Data[i].Sat, 24 | obs.Data[i].Rcv, obs.Data[i].L[0], obs.Data[i].L[1], 25 | obs.Data[i].P[0], obs.Data[i].P[1], obs.Data[i].LLI[0], obs.Data[i].LLI[1]) 26 | 27 | assert.True(1 <= obs.Data[i].Sat && obs.Data[i].Sat <= 32) 28 | assert.True(gnssgo.TimeDiff(obs.Data[i].Time, time) >= float64(-gnssgo.DTTOL)) 29 | 30 | time = obs.Data[i].Time 31 | } 32 | } 33 | 34 | func dumpnav(nav *gnssgo.Nav, t *testing.T) { 35 | var i int 36 | var str, s1, s2 string 37 | assert := assert.New(t) 38 | fmt.Printf("nav : n=%d\n", nav.N()) 39 | for i = 0; i < nav.N(); i++ { 40 | gnssgo.Time2Str(nav.Ephs[i].Toe, &str, 3) 41 | gnssgo.Time2Str(nav.Ephs[i].Toc, &s1, 0) 42 | gnssgo.Time2Str(nav.Ephs[i].Ttr, &s2, 0) 43 | fmt.Printf("%s : %2d %s %s %3d %3d %2d\n", str, nav.Ephs[i].Sat, s1, s2, 44 | nav.Ephs[i].Iode, nav.Ephs[i].Iodc, nav.Ephs[i].Svh) 45 | 46 | assert.True(nav.Ephs[i].Iode == (nav.Ephs[i].Iodc & 0xFF)) 47 | } 48 | } 49 | 50 | func dumpsta(sta *gnssgo.Sta) { 51 | fmt.Printf("name = %s\n", sta.Name) 52 | fmt.Printf("marker = %s\n", sta.Marker) 53 | fmt.Printf("antdes = %s\n", sta.AntDes) 54 | fmt.Printf("antsno = %s\n", sta.AntSno) 55 | fmt.Printf("rectype = %s\n", sta.Type) 56 | fmt.Printf("recver = %s\n", sta.RecVer) 57 | fmt.Printf("recsno = %s\n", sta.RecSN) 58 | fmt.Printf("antsetup= %d\n", sta.AntSetup) 59 | fmt.Printf("itrf = %d\n", sta.Itrf) 60 | fmt.Printf("deltype = %d\n", sta.DelType) 61 | fmt.Printf("pos = %.3f %.3f %.3f\n", sta.Pos[0], sta.Pos[1], sta.Pos[2]) 62 | fmt.Printf("del = %.3f %.3f %.3f\n", sta.Del[0], sta.Del[1], sta.Del[2]) 63 | fmt.Printf("hgt = %.3f\n", sta.Hgt) 64 | } 65 | 66 | /* gnssgo.ReadRnx(), sortobs(), uniqnav() */ 67 | func Test_renixutest1(t *testing.T) { 68 | var file1 string = "abc.00o" 69 | var file2 string = "bcd.00n" 70 | var file3 string = "../data/rinex/07590920.05o" 71 | var file4 string = "../data/rinex/07590920.05n" 72 | var file5 string = "../data/rinex/30400920.05o" 73 | var file6 string = "../data/rinex/30400920.05n" 74 | var obs gnssgo.Obs 75 | var nav gnssgo.Nav 76 | var sta gnssgo.Sta 77 | var n, stat int 78 | assert := assert.New(t) 79 | 80 | stat = gnssgo.ReadRnx(file1, 1, "", &obs, &nav, &sta) 81 | assert.True(stat == 0 && obs.N() == 0 && nav.N() == 0 && nav.Ng() == 0 && nav.Ns() == 0) 82 | stat = gnssgo.ReadRnx(file2, 1, "", &obs, &nav, &sta) 83 | assert.True(stat == 0 && obs.N() == 0 && nav.N() == 0 && nav.Ng() == 0 && nav.Ns() == 0) 84 | stat = gnssgo.ReadRnx(file3, 1, "", &obs, &nav, &sta) 85 | assert.True(stat == 1) 86 | stat = gnssgo.ReadRnx(file4, 1, "", &obs, &nav, &sta) 87 | assert.True(stat == 1) 88 | stat = gnssgo.ReadRnx(file5, 2, "", &obs, &nav, &sta) 89 | assert.True(stat == 1) 90 | stat = gnssgo.ReadRnx(file6, 2, "", &obs, &nav, &sta) 91 | assert.True(stat == 1) 92 | n = obs.SortObs() 93 | assert.True(n == 120) 94 | nav.UniqNav() 95 | assert.True(nav.N() == 167) 96 | dumpobs(&obs, t) 97 | dumpnav(&nav, t) 98 | dumpsta(&sta) 99 | assert.True(obs.Data != nil && obs.N() > 0 && nav.Ephs != nil && nav.N() > 0) 100 | } 101 | 102 | /* readrnxt() */ 103 | func Test_renixutest2(t *testing.T) { 104 | var t0, ts, te gnssgo.Gtime 105 | var ep1 []float64 = []float64{2005, 4, 2, 1, 0, 0} 106 | var ep2 []float64 = []float64{2005, 4, 2, 2, 0, 0} 107 | var file1 string = "../data/rinex/07590920.05o" 108 | var file2 string = "../data/rinex/07590920.05n" 109 | var n int 110 | var obs gnssgo.Obs 111 | var nav gnssgo.Nav 112 | var sta gnssgo.Sta 113 | 114 | ts = gnssgo.Epoch2Time(ep1) 115 | te = gnssgo.Epoch2Time(ep2) 116 | n = gnssgo.ReadRnxT(file1, 1, ts, te, 0.0, "", &obs, &nav, &sta) 117 | fmt.Printf("\n\nn=%d\n", n) 118 | n = gnssgo.ReadRnxT(file2, 1, ts, te, 0.0, "", &obs, &nav, &sta) 119 | dumpobs(&obs, t) 120 | obs.Data = nil 121 | n = gnssgo.ReadRnxT(file1, 1, t0, t0, 240.0, "", &obs, &nav, &sta) 122 | fmt.Printf("\n\nn=%d\n", n) 123 | dumpobs(&obs, t) 124 | obs.Data = nil 125 | } 126 | 127 | var opt1 gnssgo.RnxOpt = gnssgo.RnxOpt{} 128 | 129 | // var opt2 gnssgo.RnxOpt = gnssgo.RnxOpt{} 130 | 131 | var opt2 gnssgo.RnxOpt = gnssgo.RnxOpt{ 132 | 133 | TInt: 0.0, 134 | TTol: 0.0, 135 | TUnit: 0.0, 136 | RnxVer: 310, 137 | NavSys: gnssgo.SYS_ALL, 138 | ObsType: gnssgo.OBSTYPE_ALL, 139 | FreqType: gnssgo.FREQTYPE_ALL, 140 | Staid: "STAID", 141 | Prog: "RROG567890123456789012345678901", 142 | RunBy: "RUNBY67890123456789012345678901", 143 | Marker: "MARKER789012345678901234567890123456789012345678901234567890123", 144 | MarkerNo: "MARKNO7890123456789012345678901", 145 | MarkerType: "MARKTY7890123456789012345678901", 146 | Name: [2]string{"OBSERVER90123456789012345678901", "AGENCY7890123456789012345678901"}, 147 | Rec: [3]string{"RCV1567890123456789012345678901", "RCV2567890123456789012345678901", "RCV3567890123456789012345678901"}, 148 | Ant: [3]string{"ANT1567890123456789012345678901", "ANT2567890123456789012345678901", "ANT3567890123456789012345678901"}, 149 | AppPos: [3]float64{12345678.123, 99999999.999, 100000000.000}, 150 | AntDel: [3]float64{123.0345, 890123.9012, 34567.0001}, 151 | Comment: [100]string{"COMMENT1 012345678901234567890123456789012345678901234567890123", "COMMENT2 012345678901234567890123456789012345678901234567890123", "COMMENT3 012345678901234567890123456789012345678901234567890123", "COMMENT4 012345678901234567890123456789012345678901234567890123", "COMMENT5 012345678901234567890123456789012345678901234567890123"}, 152 | RcvOpt: "", 153 | Outiono: 1, 154 | OutputTime: 1, 155 | Outleaps: 1, 156 | AutoPos: 1, 157 | PhShift: 1} 158 | 159 | /* outrneobsh() */ 160 | func Test_renixutest3(t *testing.T) { 161 | var nav gnssgo.Nav 162 | 163 | opt1.OutRnxObsHeader(os.Stdout, &nav) 164 | opt2.OutRnxObsHeader(os.Stdout, &nav) 165 | } 166 | 167 | /* outrneobsb() */ 168 | func Test_renixutest4(t *testing.T) { 169 | var file string = "../data/rinex/07590920.05o" 170 | var obs gnssgo.Obs 171 | var i, j int 172 | 173 | gnssgo.ReadRnx(file, 1, "", &obs, nil, nil) 174 | opt2.OutRnxObsBody(os.Stdout, obs.Data, 8, 9) 175 | opt2.OutRnxObsBody(os.Stdout, obs.Data, 8, 0) 176 | 177 | for i, j = 0, 0; i < obs.N(); i = j { 178 | for j < obs.N() && gnssgo.TimeDiff(obs.Data[j].Time, obs.Data[i].Time) <= 0.0 { 179 | j++ 180 | } 181 | opt2.OutRnxObsBody(os.Stdout, obs.Data[i:], j-i, 0) 182 | } 183 | } 184 | 185 | /* outrnxnavh() */ 186 | func Test_renixutest5(t *testing.T) { 187 | var file1 string = "../data/rinex/07590920.05n" 188 | var ion []float64 = []float64{1e9, 2e-4, 3e8, 4e3, -4e-3, -5e99, -6e-33, -9e-123} 189 | var utc []float64 = []float64{1e9, 2e4, 3e2, -9999} 190 | var nav gnssgo.Nav 191 | var i int 192 | for i = 0; i < 8; i++ { 193 | nav.Ion_gps[i] = ion[i] 194 | } 195 | for i = 0; i < 4; i++ { 196 | nav.Utc_gps[i] = utc[i] 197 | } 198 | // nav.Leaps=14; 199 | 200 | gnssgo.ReadRnx(file1, 1, "", nil, &nav, nil) 201 | 202 | opt1.OutRnxNavHeader(os.Stdout, &nav) 203 | opt2.OutRnxNavHeader(os.Stdout, &nav) 204 | } 205 | 206 | /* outrnxnavb() */ 207 | func Test_renixutest6(t *testing.T) { 208 | var file string = "../data/rinex/07590920.05n" 209 | var nav gnssgo.Nav 210 | var i int 211 | gnssgo.ReadRnx(file, 1, "", nil, &nav, nil) 212 | for i = 0; i < nav.N(); i++ { 213 | opt2.OutRnxNavBody(os.Stdout, &nav.Ephs[i]) 214 | } 215 | } 216 | 217 | func Test_renixutest7(t *testing.T) { 218 | var file1 string = "../data/rinex/025/brdm0250.19p" 219 | var file2 string = "../data/rinex/025/brdm0250.nav" 220 | // var ion []float64 = []float64{1e9, 2e-4, 3e8, 4e3, -4e-3, -5e99, -6e-33, -9e-123} 221 | // var utc []float64 = []float64{1e9, 2e4, 3e2, -9999} 222 | var nav gnssgo.Nav 223 | var i int 224 | // for i = 0; i < 8; i++ { 225 | // nav.Ion_gps[i] = ion[i] 226 | // } 227 | // for i = 0; i < 4; i++ { 228 | // nav.Utc_gps[i] = utc[i] 229 | // } 230 | // nav.Leaps=14; 231 | 232 | gnssgo.ReadRnx(file1, 1, "", nil, &nav, nil) 233 | 234 | opt2.OutRnxNavHeader(os.Stdout, &nav) 235 | fp, _ := os.OpenFile(file2, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModeAppend|os.ModePerm) 236 | defer fp.Close() 237 | for i = 0; i < nav.N(); i++ { 238 | opt2.OutRnxNavBody(fp, &nav.Ephs[i]) 239 | } 240 | 241 | for i = 0; i < nav.Ng(); i++ { 242 | opt2.OutRnxGnavBody(fp, &nav.Geph[i]) 243 | } 244 | for i = 0; i < nav.Ns(); i++ { 245 | opt2.OutRnxHnavBody(fp, &nav.Seph[i]) 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /unittest/time_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * gnssgo unit test driver : time and string functions 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "gnssgo" 8 | "math" 9 | "strings" 10 | "testing" 11 | "time" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | /* str2num() */ 17 | func Test_str2num(t *testing.T) { 18 | var a float64 19 | var s1 string = "123456789012345678901234567890" 20 | var s2 string = "....3D45......................" 21 | var s3 string = "... 3456.789 ................" 22 | assert := assert.New(t) 23 | assert.Less(gnssgo.Str2Num(s1, 0, 0)-0.0, 1e-15) 24 | a = gnssgo.Str2Num(s1, 30, 10) 25 | assert.Less(math.Abs(a-0.0), 1e-15) 26 | a = gnssgo.Str2Num(s1, 10, 0) 27 | assert.Less(math.Abs(a-0.0), 1e-15) 28 | a = gnssgo.Str2Num(s1, -1, 10) 29 | assert.Less(math.Abs(a-0.0), 1e-15) 30 | a = gnssgo.Str2Num(s1, 0, 3) 31 | assert.Less(math.Abs(a-123.0), 1e-13) 32 | a = gnssgo.Str2Num(s1, 10, 6) 33 | assert.Less(math.Abs(a-123456.0), 1e-10) 34 | a = gnssgo.Str2Num(s1, 28, 10) 35 | assert.Less(math.Abs(a-90.0), 1e-14) 36 | a = gnssgo.Str2Num(s2, 4, 4) 37 | assert.Less(math.Abs(a-3e45), 1e+30) 38 | a = gnssgo.Str2Num(s3, 4, 8) 39 | assert.Less(math.Abs(a-3456.78), 1e-12) 40 | } 41 | 42 | /* str2time() */ 43 | func Test_utest2(t *testing.T) { 44 | var s1 string = "....2004 1 1 0 1 2.345........" 45 | var s2 string = ".... 00 2 3 23 59 59.999....." 46 | var s3 string = ".... 80 10 30 6 58 9........." 47 | var s4 string = ".... 37 12 31 1 2 3 ........." 48 | var s int 49 | var time gnssgo.Gtime 50 | var ep [6]float64 51 | assert := assert.New(t) 52 | s = gnssgo.Str2Time(s1, 0, 0, &time) 53 | assert.Less(s, 0) 54 | s = gnssgo.Str2Time(s1, 30, 10, &time) 55 | assert.Less(s, 0) 56 | s = gnssgo.Str2Time(s1, 10, 0, &time) 57 | assert.Less(s, 0) 58 | s = gnssgo.Str2Time(s1, -1, 10, &time) 59 | assert.Less(s, 0) 60 | s = gnssgo.Str2Time(s1, 4, 17, &time) 61 | gnssgo.Time2Epoch(time, ep[:]) 62 | assert.True(s == 0 && ep[0] == 2004 && ep[1] == 1 && ep[2] == 1 && ep[3] == 0 && ep[4] == 1 && math.Abs(ep[5]-2.34) < 1e-15) 63 | s = gnssgo.Str2Time(s2, 4, 21, &time) 64 | gnssgo.Time2Epoch(time, ep[:]) 65 | assert.True(s == 0 && ep[0] == 2000 && ep[1] == 2 && ep[2] == 3 && ep[3] == 23 && ep[4] == 59 && math.Abs(ep[5]-59.999) < 1e-14) 66 | s = gnssgo.Str2Time(s3, 4, 20, &time) 67 | gnssgo.Time2Epoch(time, ep[:]) 68 | assert.True(s == 0 && ep[0] == 1980 && ep[1] == 10 && ep[2] == 30 && ep[3] == 6 && ep[4] == 58 && ep[5] == 9) 69 | s = gnssgo.Str2Time(s4, 4, 20, &time) 70 | gnssgo.Time2Epoch(time, ep[:]) 71 | assert.True(s == 0 && ep[0] == 2037 && ep[1] == 12 && ep[2] == 31 && ep[3] == 1 && ep[4] == 2 && ep[5] == 3) 72 | } 73 | 74 | /* epoch2time(),time2epoch() */ 75 | func Test_utest3(t *testing.T) { 76 | var ep0 []float64 = []float64{1980, 1, 6, 0, 0, 0.000000} 77 | var ep1 []float64 = []float64{2004, 2, 28, 2, 0, 59.999999} 78 | var ep2 []float64 = []float64{2004, 2, 29, 2, 0, 30.000000} 79 | var ep3 []float64 = []float64{2004, 12, 31, 23, 59, 59.999999} 80 | var ep4 []float64 = []float64{2037, 10, 1, 0, 0, 0.000000} 81 | //#ifdef TIME_64BIT 82 | var ep5 []float64 = []float64{2049, 2, 3, 4, 5, 6.000000} /* 64bit time_t */ 83 | var ep6 []float64 = []float64{2099, 12, 31, 23, 59, 59.999999} /* 64bit time_t */ 84 | //#endif 85 | var year, month, day int 86 | var mday []int = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 87 | var time gnssgo.Gtime 88 | var ep [6]float64 89 | assert := assert.New(t) 90 | time = gnssgo.Epoch2Time(ep0) 91 | gnssgo.Time2Epoch(time, ep[:]) 92 | assert.True(ep[0] == 1980 && ep[1] == 1 && ep[2] == 6 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 93 | time = gnssgo.Epoch2Time(ep1) 94 | gnssgo.Time2Epoch(time, ep[:]) 95 | assert.True(ep[0] == 2004 && ep[1] == 2 && ep[2] == 28 && ep[3] == 2 && ep[4] == 0 && math.Abs(ep[5]-59.999999) < 1e-14) 96 | time = gnssgo.Epoch2Time(ep2) 97 | gnssgo.Time2Epoch(time, ep[:]) 98 | assert.True(ep[0] == 2004 && ep[1] == 2 && ep[2] == 29 && ep[3] == 2 && ep[4] == 0 && ep[5] == 30.0) 99 | time = gnssgo.Epoch2Time(ep3) 100 | gnssgo.Time2Epoch(time, ep[:]) 101 | assert.True(ep[0] == 2004 && ep[1] == 12 && ep[2] == 31 && ep[3] == 23 && ep[4] == 59 && math.Abs(ep[5]-59.999999) < 1e-14) 102 | time = gnssgo.Epoch2Time(ep4) 103 | gnssgo.Time2Epoch(time, ep[:]) 104 | assert.True(ep[0] == 2037 && ep[1] == 10 && ep[2] == 1 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 105 | //#ifdef TIME_64BIT 106 | time = gnssgo.Epoch2Time(ep5) 107 | gnssgo.Time2Epoch(time, ep[:]) 108 | assert.True(ep[0] == 2049 && ep[1] == 2 && ep[2] == 3 && ep[3] == 4 && ep[4] == 5 && ep[5] == 6.0) 109 | time = gnssgo.Epoch2Time(ep6) 110 | gnssgo.Time2Epoch(time, ep[:]) 111 | assert.True(ep[0] == 2099 && ep[1] == 12 && ep[2] == 31 && ep[3] == 23 && ep[4] == 59 && math.Abs(ep[5]-59.999999) < 1e-14) 112 | // #endif 113 | 114 | // #ifdef TIME_64BIT 115 | for year = 1970; year <= 2099; year++ { 116 | // #else 117 | // for (year=1970;year<=2037;year++) { 118 | // #endif 119 | if year%4 == 0 { 120 | mday[1] = 29 121 | } else { 122 | mday[1] = 28 123 | } 124 | for month = 1; month <= 12; month++ { 125 | for day = 1; day <= mday[month-1]; day++ { 126 | if year == 1970 && month == 1 && day == 1 { 127 | continue 128 | } 129 | ep0[0] = float64(year) 130 | ep0[1] = float64(month) 131 | ep0[2] = float64(day) 132 | time = gnssgo.Epoch2Time(ep0) 133 | gnssgo.Time2Epoch(time, ep[:]) 134 | /* fprintf(stderr,"ep=%.0f %2.0f %2.0f : %.0f %2.0f %2.0f\n", 135 | ep0[0],ep0[1],ep0[2],ep[0],ep[1],ep[2]); */ 136 | assert.True(ep[0] == ep0[0] && ep[1] == ep0[1] && ep[2] == ep0[2]) 137 | assert.True(ep[3] == 0.0 && ep[4] == 0.0 && ep[5] == 0.0) 138 | } 139 | } 140 | } 141 | } 142 | 143 | /* gnssgo.GpsT2Time(), time2gpst() */ 144 | func Test_utest4(t *testing.T) { 145 | var tm gnssgo.Gtime 146 | var ep [6]float64 147 | var w, week int 148 | var time, tt float64 149 | assert := assert.New(t) 150 | tm = gnssgo.GpsT2Time(0, 0.0) 151 | gnssgo.Time2Epoch(tm, ep[:]) 152 | assert.True(ep[0] == 1980 && ep[1] == 1 && ep[2] == 6 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 153 | tm = gnssgo.GpsT2Time(1400, 86400.0) 154 | gnssgo.Time2Epoch(tm, ep[:]) 155 | assert.True(ep[0] == 2006 && ep[1] == 11 && ep[2] == 6 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 156 | tm = gnssgo.GpsT2Time(1400, 86400.0*7-1.0) 157 | gnssgo.Time2Epoch(tm, ep[:]) 158 | assert.True(ep[0] == 2006 && ep[1] == 11 && ep[2] == 11 && ep[3] == 23 && ep[4] == 59 && ep[5] == 59.0) 159 | tm = gnssgo.GpsT2Time(1400, 86400.0*7) 160 | gnssgo.Time2Epoch(tm, ep[:]) 161 | assert.True(ep[0] == 2006 && ep[1] == 11 && ep[2] == 12 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 162 | tm = gnssgo.GpsT2Time(1401, 0.0) 163 | gnssgo.Time2Epoch(tm, ep[:]) 164 | assert.True(ep[0] == 2006 && ep[1] == 11 && ep[2] == 12 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 165 | tm = gnssgo.GpsT2Time(4000, 0.0) 166 | gnssgo.Time2Epoch(tm, ep[:]) 167 | assert.True(ep[0] == 2056 && ep[1] == 9 && ep[2] == 3 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 168 | tm = gnssgo.GpsT2Time(6260, 345600.0) 169 | gnssgo.Time2Epoch(tm, ep[:]) 170 | assert.True(ep[0] == 2099 && ep[1] == 12 && ep[2] == 31 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 171 | 172 | for w = 1000; w <= 6260; w++ { 173 | 174 | for time = 0.0; time < 86400.0*7; time += 3600.0 { 175 | tm = gnssgo.GpsT2Time(w, time) 176 | tt = gnssgo.Time2GpsT(tm, &week) 177 | assert.True(tt == time && week == w) 178 | } 179 | } 180 | } 181 | 182 | /* gnssgo.TimeAdd() */ 183 | func Test_utest5(t *testing.T) { 184 | var ep0 []float64 = []float64{2003, 12, 31, 23, 59, 59.000000} 185 | var ep1 []float64 = []float64{2004, 1, 1, 0, 0, 1.000000} 186 | var ep2 []float64 = []float64{2004, 2, 28, 0, 0, 0.000000} 187 | var ep3 []float64 = []float64{2004, 2, 29, 0, 0, 0.000000} 188 | var tm gnssgo.Gtime 189 | var ep [6]float64 190 | assert := assert.New(t) 191 | tm = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep0), 3.0) 192 | gnssgo.Time2Epoch(tm, ep[:]) 193 | assert.True(ep[0] == 2004 && ep[1] == 1 && ep[2] == 1 && ep[3] == 0 && ep[4] == 0 && ep[5] == 2.0) 194 | tm = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep1), -3.0) 195 | gnssgo.Time2Epoch(tm, ep[:]) 196 | assert.True(ep[0] == 2003 && ep[1] == 12 && ep[2] == 31 && ep[3] == 23 && ep[4] == 59 && ep[5] == 58.0) 197 | tm = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep2), 86400.0) 198 | gnssgo.Time2Epoch(tm, ep[:]) 199 | assert.True(ep[0] == 2004 && ep[1] == 2 && ep[2] == 29 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 200 | tm = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep2), 86400.0*2) 201 | gnssgo.Time2Epoch(tm, ep[:]) 202 | assert.True(ep[0] == 2004 && ep[1] == 3 && ep[2] == 1 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 203 | tm = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep3), 86400.0*2) 204 | gnssgo.Time2Epoch(tm, ep[:]) 205 | assert.True(ep[0] == 2004 && ep[1] == 3 && ep[2] == 2 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 206 | } 207 | 208 | /* timediff() */ 209 | func Test_utest6(t *testing.T) { 210 | var ep0 []float64 = []float64{2003, 12, 31, 23, 59, 59.000000} 211 | var ep1 []float64 = []float64{2004, 1, 1, 0, 0, 1.000000} 212 | var ep2 []float64 = []float64{2004, 2, 28, 0, 0, 0.000000} 213 | var ep3 []float64 = []float64{2004, 2, 29, 0, 0, 0.000000} 214 | var ep4 []float64 = []float64{2004, 3, 1, 0, 0, 0.000000} 215 | var sec float64 216 | assert := assert.New(t) 217 | sec = gnssgo.TimeDiff(gnssgo.Epoch2Time(ep1), gnssgo.Epoch2Time(ep0)) 218 | assert.True(sec == 2.0) 219 | sec = gnssgo.TimeDiff(gnssgo.Epoch2Time(ep0), gnssgo.Epoch2Time(ep1)) 220 | assert.True(sec == -2.0) 221 | sec = gnssgo.TimeDiff(gnssgo.Epoch2Time(ep3), gnssgo.Epoch2Time(ep2)) 222 | assert.True(sec == 86400.0) 223 | sec = gnssgo.TimeDiff(gnssgo.Epoch2Time(ep4), gnssgo.Epoch2Time(ep2)) 224 | assert.True(sec == 86400.0*2) 225 | sec = gnssgo.TimeDiff(gnssgo.Epoch2Time(ep3), gnssgo.Epoch2Time(ep4)) 226 | assert.True(sec == -86400.0) 227 | } 228 | 229 | /* gnssgo.GpsT2Utc() */ 230 | func Test_utest7(t *testing.T) { 231 | var ep0 []float64 = []float64{1980, 1, 6, 0, 0, 0.000000} 232 | var ep1 []float64 = []float64{1992, 7, 1, 0, 0, 6.999999} 233 | var ep2 []float64 = []float64{1992, 7, 1, 0, 0, 7.000000} 234 | var ep3 []float64 = []float64{1992, 7, 1, 0, 0, 8.000000} 235 | var ep4 []float64 = []float64{2004, 12, 31, 23, 59, 59.999999} 236 | var ep5 []float64 = []float64{2006, 1, 1, 0, 0, 0.000000} 237 | var ep6 []float64 = []float64{2038, 1, 1, 0, 0, 0.000000} 238 | var tm gnssgo.Gtime 239 | var ep [6]float64 240 | assert := assert.New(t) 241 | tm = gnssgo.GpsT2Utc(gnssgo.Epoch2Time(ep0)) 242 | gnssgo.Time2Epoch(tm, ep[:]) 243 | assert.True(ep[0] == 1980 && ep[1] == 1 && ep[2] == 6 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 244 | tm = gnssgo.GpsT2Utc(gnssgo.Epoch2Time(ep1)) 245 | gnssgo.Time2Epoch(tm, ep[:]) 246 | assert.True(ep[0] == 1992 && ep[1] == 6 && ep[2] == 30 && ep[3] == 23 && ep[4] == 59 && math.Abs(ep[5]-59.999999) < 1e-14) 247 | tm = gnssgo.GpsT2Utc(gnssgo.Epoch2Time(ep2)) 248 | gnssgo.Time2Epoch(tm, ep[:]) 249 | assert.True(ep[0] == 1992 && ep[1] == 7 && ep[2] == 1 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 250 | tm = gnssgo.GpsT2Utc(gnssgo.Epoch2Time(ep3)) 251 | gnssgo.Time2Epoch(tm, ep[:]) 252 | assert.True(ep[0] == 1992 && ep[1] == 7 && ep[2] == 1 && ep[3] == 0 && ep[4] == 0 && ep[5] == 0.0) 253 | tm = gnssgo.GpsT2Utc(gnssgo.Epoch2Time(ep4)) 254 | gnssgo.Time2Epoch(tm, ep[:]) 255 | assert.True(ep[0] == 2004 && ep[1] == 12 && ep[2] == 31 && ep[3] == 23 && ep[4] == 59 && math.Abs(ep[5]-46.999999) < 1e-14) 256 | tm = gnssgo.GpsT2Utc(gnssgo.Epoch2Time(ep5)) 257 | gnssgo.Time2Epoch(tm, ep[:]) 258 | assert.True(ep[0] == 2005 && ep[1] == 12 && ep[2] == 31 && ep[3] == 23 && ep[4] == 59 && ep[5] == 47.0) 259 | tm = gnssgo.GpsT2Utc(gnssgo.Epoch2Time(ep6)) 260 | gnssgo.Time2Epoch(tm, ep[:]) 261 | assert.True(ep[0] == 2037 && ep[1] == 12 && ep[2] == 31 && ep[3] == 23 && ep[4] == 59 && ep[5] == 42.0) 262 | } 263 | 264 | /* utc2gpst(), gpst2utc() */ 265 | func Test_utest8(t *testing.T) { 266 | var ep0 []float64 = []float64{1980, 1, 6, 0, 0, 0.000000} 267 | var ep1 []float64 = []float64{2010, 12, 31, 23, 59, 59.999999} 268 | var t0, t1, t2, t3 gnssgo.Gtime 269 | assert := assert.New(t) 270 | t0 = gnssgo.Epoch2Time(ep0) 271 | t1 = gnssgo.Epoch2Time(ep1) 272 | for t0.Time < t1.Time { 273 | t2 = gnssgo.Utc2GpsT(t0) 274 | t3 = gnssgo.GpsT2Utc(t2) 275 | assert.True(t0.Time == t3.Time && t0.Sec == t3.Sec) 276 | t0 = gnssgo.TimeAdd(t0, 86400.0) 277 | } 278 | } 279 | 280 | /* gnssgo.Time2Str() */ 281 | func Test_utest9(t *testing.T) { 282 | var ep0 []float64 = []float64{1970, 12, 31, 23, 59, 59.1234567890123456} 283 | var ep1 []float64 = []float64{2004, 1, 1, 0, 0, 0.0000000000000000} 284 | var ep2 []float64 = []float64{2006, 2, 28, 23, 59, 59.9999995000000000} 285 | var s string 286 | var ret int 287 | assert := assert.New(t) 288 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep0), &s, 0) 289 | ret = strings.Compare(s, "1970/12/31 23:59:59") 290 | assert.True(ret == 0) 291 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep0), &s, -1) 292 | ret = strings.Compare(s, "1970/12/31 23:59:59") 293 | assert.True(ret == 0) 294 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep0), &s, 10) 295 | ret = strings.Compare(s, "1970/12/31 23:59:59.1234567890") 296 | assert.True(ret == 0) 297 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep1), &s, 0) 298 | ret = strings.Compare(s, "2004/01/01 00:00:00") 299 | assert.True(ret == 0) 300 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep1), &s, 16) 301 | ret = strings.Compare(s, "2004/01/01 00:00:00.000000000000") 302 | assert.True(ret == 0) 303 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep2), &s, 0) 304 | ret = strings.Compare(s, "2006/03/01 00:00:00") 305 | assert.True(ret == 0) 306 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep2), &s, 6) 307 | ret = strings.Compare(s, "2006/03/01 00:00:00.000000") 308 | assert.True(ret == 0) 309 | gnssgo.Time2Str(gnssgo.Epoch2Time(ep2), &s, 7) 310 | ret = strings.Compare(s, "2006/02/28 23:59:59.9999995") 311 | assert.True(ret == 0) 312 | } 313 | 314 | /* timeget() */ 315 | func Test_utest10(t *testing.T) { 316 | var s1, s2 string 317 | var time1, time2 gnssgo.Gtime 318 | assert := assert.New(t) 319 | time1 = gnssgo.TimeGet() 320 | time.Sleep(time.Duration(2) * time.Second) 321 | time2 = gnssgo.TimeGet() 322 | gnssgo.Time2Str(time1, &s1, 6) 323 | gnssgo.Time2Str(time2, &s2, 6) 324 | assert.True(gnssgo.TimeDiff(time1, time2) <= 0.0) 325 | } 326 | 327 | /* time2doy() */ 328 | func Test_utest11(t *testing.T) { 329 | var ep1 []float64 = []float64{2004, 1, 1, 0, 0, 0} 330 | var ep2 []float64 = []float64{2004, 12, 31, 0, 0, 0} 331 | var ep3 []float64 = []float64{2005, 12, 31, 12, 0, 0} 332 | var doy1, doy2, doy3 float64 333 | assert := assert.New(t) 334 | doy1 = gnssgo.Time2DayOfYeay(gnssgo.Epoch2Time(ep1)) 335 | doy2 = gnssgo.Time2DayOfYeay(gnssgo.Epoch2Time(ep2)) 336 | doy3 = gnssgo.Time2DayOfYeay(gnssgo.Epoch2Time(ep3)) 337 | assert.True(math.Abs(doy1-1.0) < 1e-6) 338 | assert.True(math.Abs(doy2-366.0) < 1e-6) 339 | assert.True(math.Abs(doy3-365.5) < 1e-6) 340 | } 341 | -------------------------------------------------------------------------------- /unittest/tle_test.go: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtklib unit test driver : norad two line element function 3 | *-----------------------------------------------------------------------------*/ 4 | package gnss_test 5 | 6 | import ( 7 | "fmt" 8 | "gnssgo" 9 | "os" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | /* dump tle ------------------------------------------------------------------*/ 16 | func dumptle(fp *os.File, tle *gnssgo.Tle) { 17 | var i int 18 | 19 | for i = 0; i < tle.N; i++ { 20 | fp.WriteString(fmt.Sprintf("(%2d) name = %s\n", i+1, tle.Data[i].Name)) 21 | fp.WriteString(fmt.Sprintf("(%2d) satno= %s\n", i+1, tle.Data[i].SatNo)) 22 | fp.WriteString(fmt.Sprintf("(%2d) class= %c\n", i+1, tle.Data[i].SatClass)) 23 | fp.WriteString(fmt.Sprintf("(%2d) desig= %s\n", i+1, tle.Data[i].Desig)) 24 | fp.WriteString(fmt.Sprintf("(%2d) epoch= %s\n", i+1, gnssgo.TimeStr(tle.Data[i].Epoch, 0))) 25 | fp.WriteString(fmt.Sprintf("(%2d) etype= %d\n", i+1, tle.Data[i].EType)) 26 | fp.WriteString(fmt.Sprintf("(%2d) eleno= %d\n", i+1, tle.Data[i].EleNo)) 27 | fp.WriteString(fmt.Sprintf("(%2d) ndot = %19.12e\n", i+1, tle.Data[i].Ndot)) 28 | fp.WriteString(fmt.Sprintf("(%2d) nddot= %19.12e\n", i+1, tle.Data[i].NDdot)) 29 | fp.WriteString(fmt.Sprintf("(%2d) bstar= %19.12e\n", i+1, tle.Data[i].BStar)) 30 | fp.WriteString(fmt.Sprintf("(%2d) inc = %19.12e\n", i+1, tle.Data[i].Inc)) 31 | fp.WriteString(fmt.Sprintf("(%2d) OMG = %19.12e\n", i+1, tle.Data[i].OMG)) 32 | fp.WriteString(fmt.Sprintf("(%2d) ecc = %19.12e\n", i+1, tle.Data[i].Ecc)) 33 | fp.WriteString(fmt.Sprintf("(%2d) omg = %19.12e\n", i+1, tle.Data[i].Omg)) 34 | fp.WriteString(fmt.Sprintf("(%2d) M = %19.12e\n", i+1, tle.Data[i].M)) 35 | fp.WriteString(fmt.Sprintf("(%2d) n = %19.12e\n", i+1, tle.Data[i].N)) 36 | fp.WriteString(fmt.Sprintf("(%2d) rev = %d\n", i+1, tle.Data[i].RevNo)) 37 | } 38 | } 39 | 40 | /* tle_read() ----------------------------------------------------------------*/ 41 | func Test_tleutest1(t *testing.T) { 42 | var file1 string = "../data/tle/tle_sgp4.err" 43 | var file2 string = "../data/tle/tle_sgp4.txt" 44 | var file3 string = "../data/tle/tle_nav.txt" 45 | var tle gnssgo.Tle 46 | var stat int 47 | assert := assert.New(t) 48 | 49 | stat = tle.TleRead(file1) 50 | assert.True(stat == 0) 51 | 52 | stat = tle.TleRead(file2) 53 | assert.True(stat != 0) 54 | assert.True(tle.N == 1) 55 | 56 | stat = tle.TleRead(file3) 57 | assert.Greater(stat, 0) 58 | assert.True(tle.N == 114) 59 | 60 | dumptle(os.Stdout, &tle) 61 | } 62 | 63 | /* tle_pos() -----------------------------------------------------------------*/ 64 | func Test_tleutest2(t *testing.T) { 65 | var file2 string = "../data/tle/tle_sgp4.txt" 66 | var ep0 [6]float64 = [6]float64{1980, 1, 1} 67 | var tle gnssgo.Tle 68 | var epoch gnssgo.Gtime 69 | var min float64 70 | var rs [6]float64 71 | var i, stat int 72 | assert := assert.New(t) 73 | 74 | epoch = gnssgo.Utc2GpsT(gnssgo.TimeAdd(gnssgo.Epoch2Time(ep0[:]), 274.98708465*86400.0)) 75 | 76 | stat = tle.TleRead(file2) 77 | assert.Greater(stat, 0) 78 | 79 | stat = tle.TlePos(epoch, "TEST_ERR", "", "", nil, rs[:]) 80 | assert.Equal(stat, 0) 81 | 82 | for i = 0; i < 5; i++ { 83 | min = 360.0 * float64(i) 84 | 85 | stat = tle.TlePos(gnssgo.TimeAdd(epoch, min*60.0), "TEST_SAT", "", "", nil, rs[:]) 86 | assert.Greater(stat, 0) 87 | 88 | fmt.Printf("%4.0f: %14.8f %14.8f %14.8f %11.8f %11.8f %11.8f\n", min, 89 | rs[0]/1e3, rs[1]/1e3, rs[2]/1e3, rs[3]/1e3, rs[4]/1e3, rs[5]/1e3) 90 | } 91 | } 92 | 93 | /* tle_pos() accuracy --------------------------------------------------------*/ 94 | func Test_tleutest3(t *testing.T) { 95 | var file1 string = "../data/tle/brdc3050.12*" 96 | var file2 string = "../data/tle/TLE_GNSS_20121101.txt" 97 | var file3 string = "../data/tle/igs17127.erp" 98 | var ep [6]float64 = [6]float64{2012, 10, 31, 0, 0, 0} 99 | var nav gnssgo.Nav 100 | var erp gnssgo.Erp 101 | var tle gnssgo.Tle 102 | var time gnssgo.Gtime 103 | var sat string 104 | var rs1, rs2, ds [6]float64 105 | var dts [2]float64 106 | var fvar float64 107 | var i, j, k, stat, svh int 108 | assert := assert.New(t) 109 | 110 | gnssgo.ReadRnx(file1, 0, "", nil, &nav, nil) 111 | assert.True(nav.N() > 0) 112 | 113 | stat = gnssgo.ReadErp(file3, &erp) 114 | assert.True(stat != 0) 115 | 116 | stat = tle.TleRead(file2) 117 | assert.True(stat != 0) 118 | 119 | for i = 0; i < gnssgo.MAXSAT; i++ { 120 | gnssgo.SatNo2Id(i+1, &sat) 121 | 122 | fmt.Printf("SAT=%s\n", sat) 123 | 124 | for j = 0; j < 96; j++ { 125 | time = gnssgo.TimeAdd(gnssgo.Epoch2Time(ep[:]), 900.0*float64(j)) 126 | 127 | if nav.SatPos(time, time, i+1, int(gnssgo.EPHOPT_BRDC), rs1[:], dts[:], &fvar, &svh) == 0 { 128 | continue 129 | } 130 | 131 | if gnssgo.SatSys(i+1, nil) == gnssgo.SYS_QZS { 132 | svh &= 0xFE 133 | } 134 | 135 | if svh != 0 { 136 | continue 137 | } 138 | 139 | stat = tle.TlePos(time, sat, "", "", &erp, rs2[:]) 140 | assert.True(stat != 0) 141 | 142 | for k = 0; k < 3; k++ { 143 | ds[k] = rs2[k] - rs1[k] 144 | } 145 | 146 | fmt.Printf("%6.0f %11.3f %11.3f %11.3f %11.3f\n", 900.0*float64(j), 147 | ds[0]/1e3, ds[1]/1e3, ds[2]/1e3, gnssgo.Norm(ds[:], 3)/1e3) 148 | 149 | if gnssgo.Norm(ds[:], 3)/1e3 > 300.0 { 150 | fmt.Printf("warning") 151 | } 152 | assert.True(gnssgo.Norm(ds[:], 3)/1e3 < 300.0) 153 | } 154 | fmt.Printf("\n") 155 | } 156 | } 157 | --------------------------------------------------------------------------------