Python GNSS/NMEA 接收机模拟
项目描述
nmeasim
Python 3 GNSS/NMEA 接收器模拟。
Python 2 项目的部分重写gpssim,最初用于为 NMEA 消费者生成测试数据。
概述
该软件包的核心是nmeasim.simulatorGNSS 模拟库,可发出 NMEA 语句。支持以下内容:
地理空间(GGA、GLL、RMC、VTG、ZDA) - 使用一致的位置/速度模型进行模拟,使用机器时间(不是 NTP,除非机器恰好是 NTP 同步)进行时间。
卫星(GSA、GSV) ——用随机方位角/仰角伪造。
该库支持 GP (GPS) 和 GL (Glonass) 句子。目前不支持 GN(融合 GNSS)语句。可以通过扩展轻松添加其他 GNSS 类型nmeasim.models。
图形用户界面
还包括nmea.gui一个 Tk GUI,它支持串行输出以模拟串行 GPS 调制解调器。目前这仅支持 GP (GPS) 语句。
特征:
- 静态/等速/随机游走迭代
- (可选)设置要路由到的目标位置
- 自定义更新间隔和模拟速度
- 模拟独立 RTC 的选项(没有修复的时间)
- 可以为所有测量指定自定义精度
- 自定义句子顺序和存在
- 模拟修复/不修复条件
- 模拟不断变化的卫星能见度
这可以使用控制台脚本从源代码运行nmeasim。GUI 还通过构建管道作为独立的 Windows 应用程序交付 - 可以独立下载和执行,无需任何 Python 依赖项。
安装
python -m pip install nmeasim
请参阅预构建的 Windows GUI 二进制文件的版本。
建造
本项目使用PEP 617/PEP 621构建系统,使用setuptools后端。存根setup.py仅用于启用可编辑安装。
首选(并经过测试)前端是build.
注意:如果使用 构建python -m build --no-isolation,构建依赖项将不会自动安装。相反,您需要手动安装requires.[build-system]pyproject.toml
例子
直接使用模型设置参数和获取语句
>>> from datetime import datetime, timedelta, timezone
>>> from nmeasim.models import GpsReceiver
>>> gps = GpsReceiver(
... date_time=datetime(2020, 1, 1, 12, 34, 56, tzinfo=timezone.utc),
... output=('RMC',)
... )
>>> for i in range(3):
... gps.date_time += timedelta(seconds=1)
... gps.get_output()
...
['$GPRMC,123457.000,A,0000.000,N,00000.000,E,0.0,0.0,010120,,,A*6A']
['$GPRMC,123458.000,A,0000.000,N,00000.000,E,0.0,0.0,010120,,,A*65']
['$GPRMC,123459.000,A,0000.000,N,00000.000,E,0.0,0.0,010120,,,A*64']
模拟 - 立即获取句子
>>> from datetime import datetime
>>> from pprint import pprint
>>> from nmeasim.models import TZ_LOCAL
>>> from nmeasim.simulator import Simulator
>>> sim = Simulator()
>>> with sim.lock:
... # Can re-order or drop some
... sim.gps.output = ('GGA', 'GLL', 'GSA', 'GSV', 'RMC', 'VTG', 'ZDA')
... sim.gps.num_sats = 14
... sim.gps.lat = 1
... sim.gps.lon = 3
... sim.gps.altitude = -13
... sim.gps.geoid_sep = -45.3
... sim.gps.mag_var = -1.1
... sim.gps.kph = 60.0
... sim.gps.heading = 90.0
... sim.gps.mag_heading = 90.1
... sim.gps.date_time = datetime.now(TZ_LOCAL) # PC current time, local time zone
... sim.gps.hdop = 3.1
... sim.gps.vdop = 5.0
... sim.gps.pdop = (sim.gps.hdop ** 2 + sim.gps.vdop ** 2) ** 0.5
... # Precision decimal points for various measurements
... sim.gps.horizontal_dp = 4
... sim.gps.vertical_dp = 1
... sim.gps.speed_dp = 1
... sim.gps.time_dp = 2
... sim.gps.angle_dp = 1
... # Keep straight course for simulator - don't randomly change the heading
... sim.heading_variation = 0
...
>>> pprint(list(sim.get_output(3)))
['$GPGGA,133816.75,0100.0000,N,00300.0000,E,1,14,3.1,-13.0,M,-45.3,M,,*55',
'$GPGLL,0100.0000,N,00300.0000,E,133816.75,A,A*67',
'$GPGSA,A,3,1,2,6,8,11,13,15,19,20,23,28,29,5.9,3.1,5.0*38',
'$GPGSV,0,1,14,01,24,171,32,02,72,298,31,06,08,242,36,08,79,280,36*7C',
'$GPGSV,1,2,14,11,58,336,34,13,13,140,37,15,90,316,35,19,08,063,30*7B',
'$GPGSV,2,3,14,20,69,097,36,23,31,103,37,28,02,232,30,29,34,220,31*78',
'$GPGSV,3,4,14,31,62,108,31,32,20,330,35,,,,,,,,*73',
'$GPRMC,133816.75,A,0100.0000,N,00300.0000,E,32.4,90.0,170921,1.1,W,A*29',
'$GPVTG,90.0,T,90.1,M,32.4,N,60.0,K,A*21',
'$GPZDA,133816.75,17,09,2021,12,00*67',
'$GPGGA,133817.75,0100.0000,N,00300.0090,E,1,14,3.1,-13.0,M,-45.3,M,,*5D',
'$GPGLL,0100.0000,N,00300.0090,E,133817.75,A,A*6F',
'$GPGSA,A,3,1,2,6,8,11,13,15,19,20,23,28,29,5.9,3.1,5.0*38',
'$GPGSV,0,1,14,01,24,172,33,02,72,298,32,06,09,242,36,08,80,280,37*7B',
'$GPGSV,1,2,14,11,58,336,34,13,14,141,38,15,90,136,35,19,09,064,31*75',
'$GPGSV,2,3,14,20,69,097,36,23,31,103,38,28,02,232,31,29,34,220,32*75',
'$GPGSV,3,4,14,31,62,108,32,32,20,331,35,,,,,,,,*71',
'$GPRMC,133817.75,A,0100.0000,N,00300.0090,E,32.4,90.0,170921,1.1,W,A*21',
'$GPVTG,90.0,T,90.1,M,32.4,N,60.0,K,A*21',
'$GPZDA,133817.75,17,09,2021,12,00*66',
'$GPGGA,133818.75,0100.0000,N,00300.0180,E,1,14,3.1,-13.0,M,-45.3,M,,*52',
'$GPGLL,0100.0000,N,00300.0180,E,133818.75,A,A*60',
'$GPGSA,A,3,1,2,6,8,11,13,15,19,20,23,28,29,5.9,3.1,5.0*38',
'$GPGSV,0,1,14,01,25,172,33,02,73,299,32,06,09,243,37,08,80,281,37*7B',
'$GPGSV,1,2,14,11,59,336,34,13,14,141,38,15,90,316,36,19,09,064,31*77',
'$GPGSV,2,3,14,20,70,098,37,23,32,103,38,28,03,232,31,29,35,221,32*71',
'$GPGSV,3,4,14,31,63,109,32,32,20,331,36,,,,,,,,*72',
'$GPRMC,133818.75,A,0100.0000,N,00300.0180,E,32.4,90.0,170921,1.1,W,A*2E',
'$GPVTG,90.0,T,90.1,M,32.4,N,60.0,K,A*21',
'$GPZDA,133818.75,17,09,2021,12,00*69']
模拟 - 同步输出句子
>>> import sys
>>> from nmeasim.simulator import Simulator
>>> sim = Simulator()
>>> sim.generate(3, output=sys.stdout)
$GPGGA,134437.004,0000.000,N,00000.000,E,1,12,1.0,0.0,M,,M,,*42
$GPGLL,0000.000,N,00000.000,E,134437.004,A,A*5B
$GPGSA,A,3,1,4,5,8,9,11,16,21,23,26,30,32,,1.0,*01
$GPGSV,0,1,12,01,25,105,32,04,78,242,31,05,83,185,31,08,21,181,38*7D
$GPGSV,1,2,12,09,89,102,36,11,68,048,32,16,28,229,39,21,90,276,33*73
$GPGSV,2,3,12,23,30,332,33,26,47,120,37,30,50,067,33,32,53,152,31*7F
$GPRMC,134437.004,A,0000.000,N,00000.000,E,0.0,0.0,170921,,,A*60
$GPVTG,0.0,T,,M,0.0,N,0.0,K,A*0D
$GPZDA,134437.004,17,09,2021,12,00*59
$GPGGA,134438.004,0000.000,N,00000.000,E,1,12,1.0,0.0,M,,M,,*4D
$GPGLL,0000.000,N,00000.000,E,134438.004,A,A*54
$GPGSA,A,3,1,4,5,8,9,11,16,21,23,26,30,32,,1.0,*01
$GPGSV,0,1,12,01,24,105,31,04,77,242,31,05,82,185,31,08,20,181,38*70
$GPGSV,1,2,12,09,88,101,36,11,67,047,32,16,28,229,38,21,89,276,33*78
$GPGSV,2,3,12,23,29,332,33,26,46,119,37,30,49,067,33,32,53,151,31*77
$GPRMC,134438.004,A,0000.000,N,00000.000,E,0.0,4.7,170921,,,A*6C
$GPVTG,4.7,T,,M,0.0,N,0.0,K,A*0E
$GPZDA,134438.004,17,09,2021,12,00*56
$GPGGA,134439.004,0000.000,N,00000.000,E,1,12,1.0,0.0,M,,M,,*4C
$GPGLL,0000.000,N,00000.000,E,134439.004,A,A*55
$GPGSA,A,3,1,4,5,8,9,11,16,21,23,26,30,32,,1.0,*01
$GPGSV,0,1,12,01,24,104,31,04,77,241,31,05,82,184,30,08,20,180,37*7C
$GPGSV,1,2,12,09,88,101,35,11,67,047,31,16,28,228,38,21,89,276,32*78
$GPGSV,2,3,12,23,29,332,33,26,46,119,37,30,49,067,32,32,52,151,30*76
$GPRMC,134439.004,A,0000.000,N,00000.000,E,0.0,6.6,170921,,,A*6E
$GPVTG,6.6,T,,M,0.0,N,0.0,K,A*0D
$GPZDA,134439.004,17,09,2021,12,00*57
模拟 - 1PPS 到串行端口(非阻塞)
>>> from serial import Serial
>>> from time import sleep
>>> from nmeasim.simulator import Simulator
>>> ser = Serial('COM5')
>>> ser.write_timeout = 0 # Do not block simulator on serial writing
>>> sim = Simulator()
>>> sim.serve(output=ser, blocking=False)
>>> sleep(3)
>>> sim.kill()
模拟 - 1PPS 转串口(阻塞)
from serial import Serial
from time import sleep
from threading import Thread
from nmeasim.simulator import Simulator
ser = Serial('COM5')
ser.write_timeout = 0 # Do not block simulator on serial writing
sim = Simulator()
worker = Thread(target=sim.serve, kwargs=dict(output=ser, blocking=True))
worker.start()
sleep(3)
sim.kill()
worker.join()
执照
Copyright (c) 2021 Wei Li Jiang
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Includes Public Domain icons from the Tango Desktop Project.
项目详情
下载文件
下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。
源分布
nmeasim-1.0.2.0.tar.gz
(192.7 kB
查看哈希)
内置分布
nmeasim-1.0.2.0-py3-none-any.whl
(188.8 kB
查看哈希)