5 (C) 2008 Gergely Imreh <imrehg@gmail.com>
7 cell_locator: Baruch Even <baruch@ev-en.org>
13 Uses input file: cellinfo.dat
14 Contain : Locations of known cells
15 Format : comma-separated values
16 Fields : mmc,mnc,cell_id,lattitude,longitude
21 import sys
, os
, serial
, time
, dbus
, csv
22 from time
import strftime
25 ### GPS import functions from stripped down version of cell_locator.py
26 from cell_locator_bare
import Terminal
27 from cell_locator_bare
import GPS
38 # Number of digits after decimal point when printing location
43 def triangulate(pos
,idist
):
45 def middlep(pos1
,idist1
,pos2
,idist2
):
46 """ Middle point of triangle side """
47 return (pos1
*idist1
+ pos2
*idist2
)/(idist1
+idist2
)
49 def perpvec(pos1
,pos2
):
50 """ Vector perpendicular to the line connecting pos1 & pos2 """
52 dir = array((-1*dir[1],dir[0]))
55 def inters(p1
,p2
,p3
,p4
):
56 """ Calculating intersection point """
58 ua
= ((p4
[0]-p3
[0])*(p1
[1]-p3
[1])-(p4
[1]-p3
[1])*(p1
[0]-p3
[0]))/((p4
[1]-p3
[1])*(p2
[0]-p1
[0]) - (p4
[0]-p3
[0])*(p2
[1]-p1
[1]))
63 def getconsensus(inters
):
64 """ Calculate where to place most likely location,
65 currently mean of the three intersections """
73 ## Get triangle side middle points
74 mp00
= middlep(pos
[:,0],idist
[0,0],pos
[:,1],idist
[0,1])
75 mp10
= middlep(pos
[:,0],idist
[0,0],pos
[:,2],idist
[0,2])
76 mp20
= middlep(pos
[:,1],idist
[0,1],pos
[:,2],idist
[0,2])
77 ## Get another point on the line perpendicular to the sides
78 mp01
= mp00
+perpvec(pos
[:,0],pos
[:,1])
79 mp11
= mp10
+perpvec(pos
[:,0],pos
[:,2])
80 mp21
= mp20
+perpvec(pos
[:,1],pos
[:,2])
82 i1
= inters(mp00
,mp01
,mp10
,mp11
)
83 i2
= inters(mp00
,mp01
,mp20
,mp21
)
84 i3
= inters(mp10
,mp11
,mp20
,mp21
)
85 i
= array(((i1
),(i2
),(i3
)))
87 [x
,y
] = getconsensus(i
)
91 def getpos(cells
,cellpresent
,mcc
,mnc
):
92 """ Calculating position based on GSM cell data """
94 Signal converted to relative distances with assumptions:
95 - Equal tower power output
96 - Free space propagation: signal strength scales with d^(-1/2)
97 : These are of course not true - but there is a priori knowledge of proper signal strengh/distance scaling
103 haveconnected
= False
104 pos
= zeros([2,len(cellpresent
)], Float
)
105 idist
= zeros([1,len(cellpresent
)], Float
)
108 for k
in range(len(cellpresent
)):
109 # Signal strength in dB -> linear scale
110 sig
= 10**(int(cellpresent
[k
]['rxlev'])/10.0)
111 # Linear scale -> distance scale (1/2 means assuming free space propagation)
113 if debug
: print "DEBUG:",cellpresent
[k
]['cell_id'],":signal:",cellpresent
[k
]['rxlev'],"Sig-linear:",sig
,"Distance scale:",dist
114 for i
in range(len(cells
)):
115 if (mcc
== cells
[i
]['mcc']) and (mnc
== cells
[i
]['mnc']) and (cellpresent
[k
]['cell_id'] == cells
[i
]['cell_id']):
116 if k
== 0 : haveconnected
= True
117 pos
[:,have
] = [float(cells
[i
]['lat']),float(cells
[i
]['lon'])]
118 idist
[0,have
] = 1./dist
120 if debug
: print "DEBUG:",cellpresent
[k
]['cell_id'],":CellFound: ",cells
[i
]['lat'], cells
[i
]['lon']
124 """ No guess if no tower """
128 """ Wild guess if one tower """
132 """ On a line if two towers """
133 lat
= (pos
[0,0]/idist
[0,0] + pos
[0,1]/idist
[0,1])/(1/idist
[0,0]+1/idist
[0,1])
134 lon
= (pos
[1,0]/idist
[0,0] + pos
[1,1]/idist
[0,1])/(1/idist
[0,0]+1/idist
[0,1])
136 """ Triangulate if three towers """
137 [lat
,lon
] = triangulate(pos
[:,0:3],idist
[:,0:3])
139 """ If more than three : use cleverness! (hopefully) """
142 if not haveconnected
:
143 """ If the connected tower is not on the known list, move forward the tower
144 with the highest signal level to be first in the list """
145 signals
= sort(idist
)
146 for k
in range(have
):
147 if float(idist
[0,k
]) == float(signals
[0][-1]):
152 tempidist
= idist
[0,0]
155 idist
[0,0] = idist
[0,k
]
158 idist
[0,k
] = tempidist
160 """ Triangulate possible triads (but keep the connected tower (or the highest signal one)
161 for all of them), and select for those that are closest to the known tower position,
162 finally average position """
163 subpos
= zeros([2,3], Float
)
164 subidist
= zeros([1,3], Float
)
165 subpos
[:,0] = pos
[:,0]
166 subidist
[0,0] = idist
[0,0]
167 numcalc
= ((have
-1)*(have
-2)) / 2
169 cpos
= zeros([2,numcalc
], Float
)
171 for k
in range(1,have
):
172 for m
in range(k
+1,have
):
173 subpos
[:,1] = pos
[:,k
]
174 subpos
[:,2] = pos
[:,m
]
175 subidist
[0,1] = idist
[0,k
]
176 subidist
[0,2] = idist
[0,m
]
177 [sublat
,sublon
] = triangulate(subpos
,subidist
)
178 cpos
[0,icalc
] = sublat
179 cpos
[1,icalc
] = sublon
180 [dist
, hdist
, vdist
] = calcdist(pos
[1,0],pos
[0,0],sublon
,sublat
)
183 numuse
= math
.ceil(numcalc
/2)
186 uplimit
= scdist
[int(numuse
)-1]
187 for k
in range(numcalc
):
188 if float(cdist
[k
]) <= (uplimit
):
189 lat
+= float(cpos
[0,k
])
190 lon
+= float(cpos
[1,k
])
197 if debug
: print "DEBUG:","Cells-found:",have
198 if debug
: print "DEBUG:","getpos:return:",lat
,lon
,have
,len(cellpresent
)
199 return lat
,lon
,have
,len(cellpresent
)
203 def calcdist(lon1
,lat1
,lon2
,lat2
):
204 """ Calculate (approximate) distance of two coordinates on Earth """
206 Returns distance, and North/South difference, Average East/West difference
207 --- if lat2 / lon2 are more North / East : positive, if more South / East : negative
209 # Earth mean radius (m)
213 dist
= r
*acos( cos(lat1
/180*pi
)*cos(lat2
/180*pi
)*cos(lon1
/180*pi
- lon2
/180*pi
) + sin(lat1
/180*pi
)*sin(lat2
/180*pi
))
214 # North/South difference
215 ns
= r
*acos( cos(lat1
/180*pi
)*cos(lat2
/180*pi
) + sin(lat1
/180*pi
)*sin(lat2
/180*pi
))
218 # Usually don't need to, only at big distances: East/West difference, at both lattitudes, take the average
219 ew1
= r
*acos( cos(lat1
/180*pi
)*cos(lat1
/180*pi
)*cos(lon1
/180*pi
- lon2
/180*pi
) + sin(lat1
/180*pi
)*sin(lat1
/180*pi
))
220 ew2
= r
*acos( cos(lat2
/180*pi
)*cos(lat2
/180*pi
)*cos(lon1
/180*pi
- lon2
/180*pi
) + sin(lat2
/180*pi
)*sin(lat2
/180*pi
))
228 """ Class to store GSM positioning information """
235 def getgsmpos(gsmpos
,gsmterm
,cells
):
236 """ Positioning loop, based on cell_locator.py """
237 neigh
= gsmterm
.get_neighbour_cell_info()
238 loc
= gsmterm
.get_location_and_paging_info()
239 cell
= gsmterm
.get_service_cell_info()
244 if cell
['cell_id'] > 0:
246 d
['cell_id'] = cell
['cell_id']
247 d
['rxlev'] = cell
['rxlev']
248 cellpresent
.append(d
)
250 for k
in range(len(neigh
)):
251 if neigh
[k
]['cell_id'] != 0:
253 d
['cell_id'] = neigh
[k
]['cell_id']
254 d
['rxlev'] = neigh
[k
]['rxlev']
255 cellpresent
.append(d
)
256 gsmpos
.lat
,gsmpos
.lon
,gsmpos
.numtower
,gsmpos
.tottower
= getpos(cells
,cellpresent
,mcc
,mnc
)
259 def looping(gsmterm
,gsm
,cells
,gps
=None):
260 """ Displaying results """
262 getgsmpos(gsm
,gsmterm
,cells
)
263 if (gsm
.lat
!= None) and (gsm
.lon
!= None):
264 print "GSM: Pos:",round(gsm
.lat
,posdigits
),",",round(gsm
.lon
,posdigits
),"T:",gsm
.numtower
,"/",gsm
.tottower
265 else: print "GSM: No fix"
267 if (gps
.lat
!= None) and (gps
.lon
!= None):
268 print "GPS: Pos:",round(gps
.lat
,posdigits
),",",round(gps
.lon
,posdigits
),"HDOP:",gps
.hdop
269 else: print "GPS: No fix"
270 if (gps
.lat
!= None) and (gps
.lon
!= None) and (gsm
.lat
!= None) and (gsm
.lon
!= None):
271 dist
,ns
,ew
= calcdist(gps
.lon
,gps
.lat
,gsm
.lon
,gsm
.lat
)
272 print "GSM-GPS Diff: ",round(dist
),"m"
273 print "N/S : ",round(ns
),"m | E/W: ",round(ew
),"m"
278 except (KeyboardInterrupt, SystemExit):
279 print "Keyboard Quit - please press Ctrl-C once more"
282 etype
= sys
.exc_info()[0]
283 evalue
= sys
.exc_info()[1]
284 etb
= traceback
.extract_tb(sys
.exc_info()[2])
285 print "Exception in main loop: ", str(etype
), " : ", str(evalue
) , ' : ', etb
286 print "Looping stopped - press Ctrl-c to quit"
293 def loadcellinfo(celldatafile
):
294 """ Load cell information """
297 f
= open(celldatafile
,'r')
299 params
= ('mcc','mnc','cell_id','lat','lon')
300 data
= line
.split(',')
303 d
[params
[0]] = int(data
[0])
304 d
[params
[1]] = int(data
[1])
305 d
[params
[2]] = int(data
[2])
306 d
[params
[3]] = float(data
[3])
307 d
[params
[4]] = float(data
[4])
310 etype
= sys
.exc_info()[0]
311 evalue
= sys
.exc_info()[1]
312 etb
= traceback
.extract_tb(sys
.exc_info()[2])
313 print "Error while loading GSM tower database: ", str(etype
), " : ", str(evalue
) , ' : ', str(etb
)
318 if __name__
== "__main__":
320 cells
= loadcellinfo('cellinfo.dat')
322 from dbus
.mainloop
.glib
import DBusGMainLoop
323 DBusGMainLoop(set_as_default
=True)
326 loop
= gobject
.MainLoop()
327 context
= loop
.get_context()
336 # Init GSM position storage
339 # Do positioning ever 3s
341 gobject
.timeout_add(3000, looping
, t
, gsm
, cells
, gps
)
344 except KeyboardInterrupt:
345 print "Keyboard Quit"
353 print "Closing GPS - wait for it!!"