Derp. Forgot to git-add the KML parser. Also added an LPF to the main app. Some other cleanups in prep for release.
This commit is contained in:
parent
01a0b635c6
commit
839596a4b2
6
AUTHORS
6
AUTHORS
@ -1 +1,7 @@
|
||||
Mode S receiver:
|
||||
Nick Foster <bistromath@gmail.com>
|
||||
|
||||
Parts of the ECC algorithm are from Eric Cottrell's gr-air program.
|
||||
|
||||
gr-howto-write-a-block:
|
||||
Eric Blossom <eb@comsec.com>
|
||||
|
@ -181,6 +181,9 @@ bruteResultTypeDef modes_ec_brute(modes_packet &err_packet)
|
||||
//here we basically crib EC's air_ms_ec_brute algorithm, because wherever he got it, it's perfect, and that comparison thing is fast to boot.
|
||||
//we assume that the syndrome result has already been calculated
|
||||
//how many bits shall we attempt to flip? let's say a max of 8 bits, to start. remember we're only going after long packets here.
|
||||
|
||||
//well, in practice, you almost never successfully recover a packet with more than 4 LCBs. so let's put the limit there to save wasting CPU time
|
||||
//on hopeless packets.
|
||||
|
||||
//want to speed things up? instead of going through the "search codes" in numeric order, let's find a way to order them probablistically.
|
||||
//that is, right now, EC's algorithm uses a "search order" which starts with ALL possible low-confidence bits flipped, and goes down counting in binary.
|
||||
|
148
src/python/modes_kml.py
Normal file
148
src/python/modes_kml.py
Normal file
@ -0,0 +1,148 @@
|
||||
#
|
||||
# Copyright 2010 Nick Foster
|
||||
#
|
||||
# This file is part of gr-air-modes
|
||||
#
|
||||
# gr-air-modes is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# gr-air-modes is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gr-air-modes; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import sqlite3
|
||||
import string, math, threading, time
|
||||
|
||||
class modes_kml(threading.Thread):
|
||||
def __init__(self, dbfile, filename, timeout=5):
|
||||
threading.Thread.__init__(self)
|
||||
self._filename = filename
|
||||
self._dbfile = dbfile
|
||||
self.my_coords = [37.76225, -122.44254] #there has got to be a better way of getting your coords in here
|
||||
self._timeout = timeout
|
||||
self.done = False
|
||||
self.setDaemon(1)
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while self.done is False:
|
||||
self.output()
|
||||
time.sleep(self._timeout)
|
||||
|
||||
self.done = True
|
||||
|
||||
def output(self):
|
||||
self._db = sqlite3.connect(self._dbfile)
|
||||
kmlstr = self.genkml()
|
||||
if kmlstr is not None:
|
||||
f = open(self._filename, 'w')
|
||||
f.write(kmlstr)
|
||||
f.close()
|
||||
self._db.close()
|
||||
|
||||
def draw_circle(self, center, rng):
|
||||
retstr = ""
|
||||
steps=30
|
||||
#so we're going to do this by computing a bearing angle based on the steps, and then compute the coordinate of a line extended from the center point to that range.
|
||||
[center_lat, center_lon] = center
|
||||
esquared = (1/298.257223563)*(2-(1/298.257223563))
|
||||
earth_radius_mi = 3963.19059
|
||||
|
||||
#here we figure out the circumference of the latitude ring
|
||||
#which tells us how wide one line of longitude is at our latitude
|
||||
lat_circ = earth_radius_mi * math.cos(center_lat)
|
||||
#the circumference of the longitude ring will be equal to the circumference of the earth
|
||||
|
||||
lat_rad = math.radians(center_lat)
|
||||
lon_rad = math.radians(center_lon)
|
||||
|
||||
tmp0 = rng / earth_radius_mi
|
||||
|
||||
for i in range(0, steps+1):
|
||||
bearing = i*(2*math.pi/steps) #in radians
|
||||
lat_out = math.degrees(math.asin(math.sin(lat_rad)*math.cos(tmp0) + math.cos(lat_rad)*math.sin(tmp0)*math.cos(bearing)))
|
||||
lon_out = center_lon + math.degrees(math.atan2(math.sin(bearing)*math.sin(tmp0)*math.cos(lat_rad), math.cos(tmp0)-math.sin(lat_rad)*math.sin(math.radians(lat_out))))
|
||||
retstr += " %.8f, %.8f, 0" % (lon_out, lat_out,)
|
||||
|
||||
retstr = string.lstrip(retstr)
|
||||
return retstr
|
||||
|
||||
def genkml(self):
|
||||
#first let's draw the static content
|
||||
retstr="""<?xml version="1.0" encoding="UTF-8"?>\n<kml xmlns="http://www.opengis.net/kml/2.2">\n<Document>\n\t<Style id="airplane">\n\t\t<IconStyle>\n\t\t\t<Icon><href>airports.png</href></Icon>\n\t\t</IconStyle>\n\t</Style>\n\t<Style id="rangering">\n\t<LineStyle>\n\t\t<color>9f4f4faf</color>\n\t\t<width>2</width>\n\t</LineStyle>\n\t</Style>\n\t<Style id="track">\n\t<LineStyle>\n\t\t<color>5fff8f8f</color>\n\t\t<width>4</width>\n\t</LineStyle>\n\t</Style>"""
|
||||
retstr += """\t<Folder>\n\t\t<name>Range rings</name>\n\t\t<open>0</open>"""
|
||||
|
||||
for rng in [100, 200, 300]:
|
||||
retstr += """\n\t\t<Placemark>\n\t\t\t<name>%inm</name>\n\t\t\t<styleUrl>#rangering</styleUrl>\n\t\t\t<LinearRing>\n\t\t\t\t<coordinates>%s</coordinates>\n\t\t\t</LinearRing>\n\t\t</Placemark>""" % (rng, self.draw_circle(self.my_coords, rng),)
|
||||
|
||||
retstr += """\t</Folder>\n\t<Folder>\n\t\t<name>Aircraft locations</name>\n\t\t<open>0</open>"""
|
||||
|
||||
#read the database and add KML
|
||||
q = "select distinct icao from positions where seen > datetime('now', '-5 minute')"
|
||||
c = self._db.cursor()
|
||||
c.execute(q)
|
||||
icaolist = c.fetchall()
|
||||
#now we have a list icaolist of all ICAOs seen in the last 5 minutes
|
||||
|
||||
for icao in icaolist:
|
||||
#print "ICAO: %x" % icao
|
||||
q = "select * from positions where icao=%i and seen > datetime('now', '-2 hour') ORDER BY seen DESC" % icao
|
||||
c.execute(q)
|
||||
track = c.fetchall()
|
||||
#print "Track length: %i" % len(track)
|
||||
if len(track) != 0:
|
||||
lat = track[0][3]
|
||||
if lat is None: lat = 0
|
||||
lon = track[0][4]
|
||||
if lon is None: lon = 0
|
||||
alt = track[0][2]
|
||||
if alt is None: alt = 0
|
||||
|
||||
metric_alt = alt * 0.3048 #google earth takes meters, the commie bastards
|
||||
|
||||
trackstr = ""
|
||||
|
||||
for pos in track:
|
||||
trackstr += " %f, %f, %f" % (pos[4], pos[3], pos[2]*0.3048)
|
||||
|
||||
trackstr = string.lstrip(trackstr)
|
||||
|
||||
#now get metadata
|
||||
q = "select ident from ident where icao=%i" % icao
|
||||
c.execute(q)
|
||||
r = c.fetchall()
|
||||
if len(r) != 0:
|
||||
ident = r[0][0]
|
||||
else: ident=""
|
||||
#if ident is None: ident = ""
|
||||
#get most recent speed/heading/vertical
|
||||
q = "select seen, speed, heading, vertical from vectors where icao=%i order by seen desc limit 1" % icao
|
||||
c.execute(q)
|
||||
r = c.fetchall()
|
||||
if len(r) != 0:
|
||||
seen = r[0][0]
|
||||
speed = r[0][1]
|
||||
heading = r[0][2]
|
||||
vertical = r[0][3]
|
||||
|
||||
else:
|
||||
seen = 0
|
||||
speed = 0
|
||||
heading = 0
|
||||
vertical = 0
|
||||
#now generate some KML
|
||||
retstr+= "\n\t\t<Placemark>\n\t\t\t<name>%s</name>\n\t\t\t<styleUrl>#airplane</styleUrl>\n\t\t\t<description>\n\t\t\t\t<![CDATA[Altitude: %s<br/>Heading: %i<br/>Speed: %i<br/>Vertical speed: %i<br/>ICAO: %x<br/>Last seen: %s]]>\n\t\t\t</description>\n\t\t\t<Point>\n\t\t\t\t<altitudeMode>absolute</altitudeMode>\n\t\t\t\t<extrude>1</extrude>\n\t\t\t\t<coordinates>%s,%s,%i</coordinates>\n\t\t\t</Point>\n\t\t</Placemark>" % (ident, alt, heading, speed, vertical, icao[0], seen, lon, lat, metric_alt, )
|
||||
|
||||
retstr+= "\n\t\t<Placemark>\n\t\t\t<styleUrl>#track</styleUrl>\n\t\t\t<LineString>\n\t\t\t\t<extrude>0</extrude>\n\t\t\t\t<altitudeMode>absolute</altitudeMode>\n\t\t\t\t<coordinates>%s</coordinates>\n\t\t\t</LineString>\n\t\t</Placemark>" % (trackstr,)
|
||||
|
||||
retstr+= '\n\t</Folder>\n</Document>\n</kml>'
|
||||
return retstr
|
@ -84,21 +84,34 @@ class adsb_rx_block (gr.top_block):
|
||||
|
||||
self.demod = gr.complex_to_mag()
|
||||
self.avg = gr.moving_average_ff(100, 1.0/100, 400);
|
||||
# self.filtcoeffs = gr.firdes.band_reject(1, rate, -691e3, -646e3, 10e3, WIN_HANN)
|
||||
# self.filter = gr.fir_filter_ccc(1, self.filtcoeffs)
|
||||
|
||||
#the DBSRX especially tends to be spur-prone; the LPF keeps out the
|
||||
#spur multiple that shows up at 2MHz
|
||||
self.filtcoeffs = gr.firdes.low_pass(1, rate, 1.8e6, 200e3)
|
||||
self.filter = gr.fir_filter_fff(1, self.filtcoeffs)
|
||||
|
||||
self.preamble = air.modes_preamble(rate, options.threshold)
|
||||
self.framer = air.modes_framer(rate)
|
||||
self.slicer = air.modes_slicer(rate, queue)
|
||||
|
||||
self.connect(self.u, self.demod)
|
||||
self.connect(self.demod, self.avg)
|
||||
self.connect(self.demod, (self.preamble, 0))
|
||||
self.connect(self.u, self.demod, self.filter)
|
||||
self.connect(self.filter, self.avg)
|
||||
self.connect(self.filter, (self.preamble, 0))
|
||||
self.connect(self.avg, (self.preamble, 1))
|
||||
self.connect(self.demod, (self.framer, 0))
|
||||
self.connect(self.filter, (self.framer, 0))
|
||||
self.connect(self.preamble, (self.framer, 1))
|
||||
self.connect(self.demod, (self.slicer, 0))
|
||||
self.connect(self.filter, (self.slicer, 0))
|
||||
self.connect(self.framer, (self.slicer, 1))
|
||||
|
||||
#use this flowgraph instead to omit the filter
|
||||
# self.connect(self.u, self.demod)
|
||||
# self.connect(self.demod, self.avg)
|
||||
# self.connect(self.demod, (self.preamble, 0))
|
||||
# self.connect(self.avg, (self.preamble, 1))
|
||||
# self.connect(self.demod, (self.framer, 0))
|
||||
# self.connect(self.preamble, (self.framer, 1))
|
||||
# self.connect(self.demod, (self.slicer, 0))
|
||||
# self.connect(self.framer, (self.slicer, 1))
|
||||
|
||||
def tune(self, freq):
|
||||
result = self.u.set_center_freq(freq)
|
||||
|
Loading…
Reference in New Issue
Block a user