Add copyright and examples.

fisb_service
Christopher Young 2016-04-01 10:28:07 -04:00
rodzic 522d74c22e
commit cfd23d54eb
13 zmienionych plików z 217 dodań i 76 usunięć

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (
@ -7,6 +17,25 @@ import (
"uatparse"
)
/*
Examples:
METAR KIND 261654Z 10005KT 10SM SCT250 11/02 A3015 RMK AO2 SLP212
T01060017=
SPECI KTDZ 261738Z AUTO 04006KT 8SM SCT020 07/00 A3025 RMK AO2
T00670000=
TAF KCMI 261131Z 2612/2712 12007KT P6SM SCT250
FM261600 13013KT P6SM SCT100
FM270000 15006KT P6SM BKN200=
TAF.AMD KMKG 261725Z 2617/2718 VRB05KT P6SM SCT250
FM270100 11006KT P6SM BKN150
FM271200 13008KT P6SM VCSH BKN150=
WINDS COU 271200Z FT 3000 6000 9000 12000 18000 24000 30000 34000 39000
2109 2019+05 2134+01 2347-04 2353-21 2454-33 257949 259857 257955
PIREP HNN 261618Z CRW UA /OV HNN/TM 1618/FL360/TP B737/TB OCNL LGT CHOP 360/RM OVER HNN AWC-WEB:SWA
*/
const (
FISB_METAR = iota
FISB_SPECI

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (
@ -25,7 +35,7 @@ func decodeUplink(frame []byte) {
if lon > 180 {
lon = lon - 360
}
fmt.Printf("%.04f, %.04f\n", lat, lon)
}

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (

Wyświetl plik

@ -1,27 +1,35 @@
package main
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (
"fmt"
// "time"
// "time"
"../uatparse"
"os"
"bufio"
"strings"
"unicode"
"strconv"
"github.com/gonum/plot"
"github.com/gonum/plot/plotter"
"github.com/gonum/plot/plotutil"
"github.com/gonum/plot/vg"
"os"
"sort"
"strconv"
"strings"
"unicode"
)
const (
UPLINK_FRAME_DATA_BYTES = 432
)
/*
From AC 00-45G [http://www.faa.gov/documentLibrary/media/Advisory_Circular/AC_00-45G_CHG_1-2.pdf]
@ -51,29 +59,28 @@ Winds Aloft 12 hours 10 minutes
*/
func append_metars(rawUplinkMessage string, curMetars []string) []string {
func append_metars(rawUplinkMessage string, curMetars []string) []string {
ret := curMetars
uatMsg, err := uatparse.New(rawUplinkMessage)
if err != nil {
return ret
}
//fmt.Printf("*************************\n")
//fmt.Printf("*************************\n")
metars, _ := uatMsg.GetTextReports()
for _, v := range metars {
//fmt.Printf("EE: %s\n", v)
//fmt.Printf("EE: %s\n", v)
vSplit := strings.Split(v, " ")
if vSplit[0] != "METAR" || len(vSplit) < 3 { // Only looking for METARs.
continue
}
ret = append(ret, v)
}
//fmt.Printf("=========================\n")
//fmt.Printf("=========================\n")
return ret
}
/*
Average number of METARs received for an airport for which you first received a METAR in the first 5 minutes, over 10 minutes. Divided by two.
*/
@ -97,7 +104,7 @@ func metar_qos_one_period(a, b []string) float64 {
ret += float64(num)
}
if len(numMetarByIdent) > 0 {
ret = ret / float64(2 * len(numMetarByIdent))
ret = ret / float64(2*len(numMetarByIdent))
}
return ret
}
@ -124,7 +131,7 @@ func main() {
if err != nil {
break
}
buf = strings.TrimFunc(buf, func(r rune) bool {return unicode.IsControl(r)})
buf = strings.TrimFunc(buf, func(r rune) bool { return unicode.IsControl(r) })
linesplit := strings.Split(buf, ",")
if len(linesplit) < 2 { // Blank line or invalid.
continue
@ -132,9 +139,9 @@ func main() {
if linesplit[0] == "START" { // Reset ticker, new start.
//TODO: Support multiple sessions.
// Reset the counters, new session.
// qos = make(map[uint]float64)
// curWindowMetars = make([]string, 0)
// curWindow = 0
// qos = make(map[uint]float64)
// curWindowMetars = make([]string, 0)
// curWindow = 0
windowOffset = curWindow
} else { // If it's not "START", then it's a tick count.
i, err := strconv.ParseInt(linesplit[0], 10, 64)
@ -145,17 +152,17 @@ func main() {
// Window number in current session.
wnum := int64(i / (5 * 60 * 1000000000))
// fmt.Printf("%d\n", curWindow)
if wnum + windowOffset != curWindow { // Switched over.
// fmt.Printf("%d\n", curWindow)
if wnum+windowOffset != curWindow { // Switched over.
curWindow = wnum + windowOffset
beforeLastWindowMetars, ok := metarsByWindow[curWindow - 2]
lastWindowMetars, ok2 := metarsByWindow[curWindow - 1]
beforeLastWindowMetars, ok := metarsByWindow[curWindow-2]
lastWindowMetars, ok2 := metarsByWindow[curWindow-1]
if ok && ok2 {
// fmt.Printf("%v\n\n\nheyy\n\n%v\n", beforeLastWindowMetars, lastWindowMetars)
qos[curWindow - 1] = metar_qos_one_period(beforeLastWindowMetars, lastWindowMetars)
fmt.Printf("qos=%f\n", qos[curWindow - 1])
delete(metarsByWindow, curWindow - 2)
delete(metarsByWindow, curWindow - 1)
// fmt.Printf("%v\n\n\nheyy\n\n%v\n", beforeLastWindowMetars, lastWindowMetars)
qos[curWindow-1] = metar_qos_one_period(beforeLastWindowMetars, lastWindowMetars)
fmt.Printf("qos=%f\n", qos[curWindow-1])
delete(metarsByWindow, curWindow-2)
delete(metarsByWindow, curWindow-1)
}
}
metarsByWindow[curWindow] = append_metars(linesplit[1], metarsByWindow[curWindow])
@ -180,7 +187,7 @@ func main() {
pts := make(plotter.XYs, len(qos))
i := 0
for _,k := range keys {
for _, k := range keys {
v := qos[int64(k)]
fmt.Printf("%d, %f\n", k, v)
pts[i].X = float64(k)
@ -192,7 +199,7 @@ func main() {
if err != nil {
panic(err)
}
if err := p.Save(4 * vg.Inch, 4 * vg.Inch, "qos.png"); err != nil {
if err := p.Save(4*vg.Inch, 4*vg.Inch, "qos.png"); err != nil {
panic(err)
}
}

Wyświetl plik

@ -1,40 +1,48 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (
"fmt"
"../uatparse"
"strconv"
"os"
"bufio"
"fmt"
"github.com/kellydunn/golang-geo"
"math"
)
"os"
"strconv"
)
// Most adapted from extract_nexrad.c
const (
BLOCK_WIDTH = float64(48.0/60.0)
WIDE_BLOCK_WIDTH = float64(96.0/60.0)
BLOCK_HEIGHT = float64(4.0/60.0)
BLOCK_THRESHOLD = 405000
BLOCKS_PER_RING = 450
BLOCK_WIDTH = float64(48.0 / 60.0)
WIDE_BLOCK_WIDTH = float64(96.0 / 60.0)
BLOCK_HEIGHT = float64(4.0 / 60.0)
BLOCK_THRESHOLD = 405000
BLOCKS_PER_RING = 450
WARN_DIST = float64(18.52) // kilometers (10 nm).
)
type NEXRADFrame struct {
radar_type uint32
ts string
scale int
latNorth float64
lonWest float64
height float64
width float64
intensity []uint8 // Really only 4-bit values.
ts string
scale int
latNorth float64
lonWest float64
height float64
width float64
intensity []uint8 // Really only 4-bit values.
}
func block_location(block_num int, ns_flag bool, scale_factor int) (float64, float64, float64, float64) {
var realScale float64
if scale_factor == 1 {
@ -49,8 +57,8 @@ func block_location(block_num int, ns_flag bool, scale_factor int) (float64, flo
block_num = block_num & ^1
}
raw_lat := float64(BLOCK_HEIGHT * float64(int(float64(block_num) / float64(BLOCKS_PER_RING))))
raw_lon := float64(block_num % BLOCKS_PER_RING) * BLOCK_WIDTH
raw_lat := float64(BLOCK_HEIGHT * float64(int(float64(block_num)/float64(BLOCKS_PER_RING))))
raw_lon := float64(block_num%BLOCKS_PER_RING) * BLOCK_WIDTH
var lonSize float64
if block_num >= BLOCK_THRESHOLD {
@ -66,7 +74,7 @@ func block_location(block_num int, ns_flag bool, scale_factor int) (float64, flo
} else {
raw_lat = raw_lat + BLOCK_HEIGHT
}
if raw_lon > 180.0 {
raw_lon = raw_lon - 360.0
}
@ -97,7 +105,7 @@ func decode_nexrad(f *uatparse.UATFrame) []NEXRADFrame {
intensityData := f.FISB_data[3:]
for _, v := range intensityData {
intensity := uint8(v) & 0x7;
intensity := uint8(v) & 0x7
runlength := (uint8(v) >> 3) + 1
for runlength > 0 {
tmp.intensity = append(tmp.intensity, intensity)
@ -128,7 +136,7 @@ func decode_nexrad(f *uatparse.UATFrame) []NEXRADFrame {
}
for j := 0; j < 8; j++ {
if bb & (1 << uint(j)) != 0 {
if bb&(1<<uint(j)) != 0 {
row_x := (row_offset + 8*i + j - 3) % row_size
bn := row_start + row_x
lat, lon, h, w := block_location(bn, ns_flag, scale_factor)
@ -236,9 +244,9 @@ func scanNEXRAD(poly *geo.Polygon, frame NEXRADFrame) (*geo.Point, uint8) {
var maxIntensity uint8
for y := 0; y < 4; y++ {
for x := 0; x < 32; x++ {
intensity := frame.intensity[x + 32*y]
lat := frame.latNorth - (float64(y) * (frame.height)/float64(4.0))
lon := frame.lonWest + (float64(x) * (frame.width)/float64(32.0))
intensity := frame.intensity[x+32*y]
lat := frame.latNorth - (float64(y) * (frame.height) / float64(4.0))
lon := frame.lonWest + (float64(x) * (frame.width) / float64(32.0))
pt := geo.NewPoint(lat, lon)
if !poly.Contains(pt) { // Doesn't contain this point - skip.
continue
@ -303,12 +311,12 @@ func main() {
nineOClock := fixHeading(hdgFloat - 90.0)
threeOClock := fixHeading(hdgFloat + 90.0)
// fmt.Printf("myPos=%v\n", myPos)
// fmt.Printf("myPos=%v\n", myPos)
leftBottom := myPos.PointAtDistanceAndBearing(WARN_DIST, nineOClock)
rightBottom := myPos.PointAtDistanceAndBearing(WARN_DIST, threeOClock)
// fmt.Printf("nineOClock=%f [leftBottom=%v], threeOClock=%f [rightBottom=%v]\n", nineOClock, leftBottom, threeOClock, rightBottom)
// fmt.Printf("nineOClock=%f [leftBottom=%v], threeOClock=%f [rightBottom=%v]\n", nineOClock, leftBottom, threeOClock, rightBottom)
hypDist := math.Sqrt2 * WARN_DIST
leftTopHdg := fixHeading(hdgFloat - 45.0)
@ -317,12 +325,11 @@ func main() {
leftTop := myPos.PointAtDistanceAndBearing(hypDist, leftTopHdg)
rightTop := myPos.PointAtDistanceAndBearing(hypDist, rightTopHdg)
// fmt.Printf("leftTopHdg=%f [leftTop=%v], rightTopHdg=%f [rightTop=%v]\n", leftTopHdg, leftTop, rightTopHdg, rightTop)
// fmt.Printf("leftTopHdg=%f [leftTop=%v], rightTopHdg=%f [rightTop=%v]\n", leftTopHdg, leftTop, rightTopHdg, rightTop)
points := []*geo.Point{leftTop, rightTop, rightBottom, leftBottom, leftTop}
poly := geo.NewPolygon(points)
var maxpt *geo.Point
var maxIntensity uint8
@ -335,14 +342,13 @@ func main() {
}
}
// fmt.Printf("maxes: %d %v\n", maxIntensity, maxpt)
// fmt.Printf("maxes: %d %v\n", maxIntensity, maxpt)
if maxIntensity > 0 && maxpt != nil {
desc := intensityToText(maxIntensity)
direction := fixHeading(myPos.BearingTo(maxpt))
relativeDirection := fixHeading(direction - hdgFloat)
// fmt.Printf("direction=%f, relativeDirection=%f\n", direction, relativeDirection)
// fmt.Printf("direction=%f, relativeDirection=%f\n", direction, relativeDirection)
directionDesc := oclock(relativeDirection)
dist := myPos.GreatCircleDistance(maxpt) * float64(0.539957) // Convert km -> nm.
fmt.Printf("%s precip %d o'clock, %0.1f nm.\n", desc, directionDesc, dist)

Wyświetl plik

@ -1,19 +1,28 @@
package main
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (
"fmt"
// "time"
"os"
// "time"
"bufio"
"strings"
"unicode"
"strconv"
"github.com/gonum/plot"
"github.com/gonum/plot/plotter"
"github.com/gonum/plot/plotutil"
"github.com/gonum/plot/vg"
"os"
"sort"
"strconv"
"strings"
"unicode"
)
func main() {
@ -37,7 +46,7 @@ func main() {
if err != nil {
break
}
buf = strings.TrimFunc(buf, func(r rune) bool {return unicode.IsControl(r)})
buf = strings.TrimFunc(buf, func(r rune) bool { return unicode.IsControl(r) })
linesplit := strings.Split(buf, ",")
if len(linesplit) < 2 { // Blank line or invalid.
continue
@ -53,10 +62,10 @@ func main() {
// Window number in current session.
wnum := int64(i / (60 * 1000000000))
// fmt.Printf("%d\n", curWindow)
if wnum + windowOffset != curWindow { // Switched over.
// fmt.Printf("%d\n", curWindow)
if wnum+windowOffset != curWindow { // Switched over.
curWindow = wnum + windowOffset
fmt.Printf("ppm=%d\n", ppm[curWindow - 1])
fmt.Printf("ppm=%d\n", ppm[curWindow-1])
}
ppm[curWindow]++
}
@ -80,7 +89,7 @@ func main() {
pts := make(plotter.XYs, len(ppm))
i := 0
for _,k := range keys {
for _, k := range keys {
v := ppm[int64(k)]
fmt.Printf("%d, %d\n", k, v)
pts[i].X = float64(k)
@ -92,7 +101,7 @@ func main() {
if err != nil {
panic(err)
}
if err := p.Save(4 * vg.Inch, 4 * vg.Inch, "ppm.png"); err != nil {
if err := p.Save(4*vg.Inch, 4*vg.Inch, "ppm.png"); err != nil {
panic(err)
}
}
}

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
// +build ignore
package main

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package main
import (

Wyświetl plik

@ -1,3 +1,13 @@
/*
Copyright (c) 2015-2016 Christopher Young
Distributable under the terms of The "BSD New"" License
that can be found in the LICENSE file, herein included
as part of this header.
gen_gdl90.go: Input demodulated UAT and 1090ES information, output GDL90. Heartbeat,
ownship, status messages, stats collection.
*/
package uatparse
import (