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:
Nick Foster 2010-10-23 16:05:08 -07:00
parent 01a0b635c6
commit 839596a4b2
4 changed files with 177 additions and 7 deletions

View File

@ -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> Eric Blossom <eb@comsec.com>

View File

@ -182,6 +182,9 @@ bruteResultTypeDef modes_ec_brute(modes_packet &err_packet)
//we assume that the syndrome result has already been calculated //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. //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. //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. //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.
//statistically it's far more likely that a single bit was flipped somewhere, so we should go through those codes first. THEN we move on to two bits flipped, and so on. //statistically it's far more likely that a single bit was flipped somewhere, so we should go through those codes first. THEN we move on to two bits flipped, and so on.

148
src/python/modes_kml.py Normal file
View 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

View File

@ -84,22 +84,35 @@ class adsb_rx_block (gr.top_block):
self.demod = gr.complex_to_mag() self.demod = gr.complex_to_mag()
self.avg = gr.moving_average_ff(100, 1.0/100, 400); 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.preamble = air.modes_preamble(rate, options.threshold)
self.framer = air.modes_framer(rate) self.framer = air.modes_framer(rate)
self.slicer = air.modes_slicer(rate, queue) self.slicer = air.modes_slicer(rate, queue)
self.connect(self.u, self.demod) self.connect(self.u, self.demod, self.filter)
self.connect(self.demod, self.avg) self.connect(self.filter, self.avg)
self.connect(self.demod, (self.preamble, 0)) self.connect(self.filter, (self.preamble, 0))
self.connect(self.avg, (self.preamble, 1)) 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.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)) 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): def tune(self, freq):
result = self.u.set_center_freq(freq) result = self.u.set_center_freq(freq)
return result return result