简介面向GPS信号模拟与软件定义无线电学习者的PLUTO-GPS-SIM工程源码包用于生成GPS基带信号IQ数据流并借助ADALM-Pluto SDR在GPS L1频点发射。用户可通过命令行设定静态位置结合GPS广播星历文件brdc构建卫星星座计算视野内卫星的模拟伪距与多普勒再生成数字化I/Q样本送入Pluto。资源共14个文件以C源码与头文件为核心辅以Makefile构建脚本、README说明文档、OCXO改装原理图PDF与实物照片、circle.csv示例数据及LICENSE等压缩包约3.02MB结构紧凑便于二次开发。已有2340人学习下载。读者可从中获得完整的信号生成流程实现、星历解析与伪距多普勒计算思路以及Pluto本振精度不足导致频偏与温漂的注意事项适合具备一定C语言与SDR基础的开发者参考。1. 一块巴掌大的 SDR 板怎么把 GPS 信号“造”出来手里只有一块 ADALM-Pluto想验证 GPS 接收机、做信号完整性实验或者给教学演示搭个可控的卫星信号源最省事的路径不是买昂贵的射频记录回放仪而是用软件把基带信号算出来再交给 SDR 发射。pluto-gps-sim 就是干这件事的它用 C 语言实现 GPS L1 C/A 码的基带信号生成输出 IQ 数据流最后通过 ADALM-Pluto 的发射通道把信号打出去。整套东西不依赖图形界面编译完就是命令行工具适合想搞清楚 GPS 信号结构、又不想被商业仿真软件绑住的从业者。它解决的核心问题是“信号可控”——卫星编号、多普勒、码相位、发射增益都能自己定而不是被动接收天上那几颗星。适合做 GNSS 算法验证、SDR 射频链路调试、以及通信课程里需要可复现信号源的人。2. GPS L1 C/A 基带生成从码相位到 IQ 采样2.1 为什么选 L1 C/A 而不是别的信号GPS 有三个常见民用频点L1 1575.42 MHz 上的 C/A 码是门槛最低的一个。码率 1.023 Mcps码长 1023周期 1 ms一个码周期正好对应 2046 个采样点按 2.046 MHz 采样率算。这个整数关系不是巧合它让基带生成可以用查表和整数索引完成不需要复杂的重采样。pluto-gps-sim 选这条路径本质上是把“信号结构简单”换成了“实现可控”。L1 C/A 的扩频增益约 43 dB接收端即使信号功率低到 -130 dBm 量级也能解出所以发射端对幅度精度的要求没那么苛刻SDR 的 12 位 DAC 足够用。选 C/A 码还有一个现实原因它的 Gold 码生成逻辑是公开的两个 10 级线性反馈移位寄存器抽头位置固定用 C 写出来不到五十行。相比之下 L1C 或者 L5 的副码和调制方式复杂得多调试成本高。做信号源验证时越简单的信号越容易定位问题——信号发不出去你至少能确定不是调制方式写错了。2.2 基带生成的三个核心参数生成一段可用的 GPS 基带信号绕不开三个参数采样率、中频、卫星 PRN 号。采样率决定一个码周期里有多少个点常见取 2.046 MHz、4.092 MHz 或 5 MHz。取 2.046 MHz 时每个码片两个采样点实现最简单取 4.092 MHz 时每个码片四个点信号频谱更干净但数据量翻倍。中频是把基带搬到载波上的偏移量Pluto 的发射本振可以设所以中频一般取 0 到几 MHz 之间避免和直流泄漏混在一起。PRN 号决定用哪颗卫星的码。GPS 的 32 个 PRN 对应不同的抽头组合生成时查一张表即可。多普勒频移是第四个隐含参数做静态验证时可以设 0做动态场景模拟时按卫星仰角和相对速度算典型值在 ±5 kHz 以内。/* 简化示意按 PRN 生成一个码周期的 C/A 码采样 */ #define SAMPLE_RATE 2046000.0 #define CHIP_RATE 1023000.0 #define CODE_LEN 1023 #define SAMPLES_PER_CODE 2046 static int ca_code[CODE_LEN]; void gen_ca_code(int prn) { /* 两个 10 级 LFSR抽头由 PRN 查表决定此处省略表 */ int g1[10] {1,1,1,1,1,1,1,1,1,1}; int g2[10] {1,1,1,1,1,1,1,1,1,1}; for (int i 0; i CODE_LEN; i) { int out1 g1[9]; int out2 g2[9]; ca_code[i] out1 ^ out2; /* 模二加得到 C/A 码片 */ int fb1 g1[2] ^ g1[9]; /* G1 反馈抽头 3、10 */ int fb2 g2[1] ^ g2[2] ^ g2[5] ^ g2[7] ^ g2[8] ^ g2[9]; /* 右移并注入反馈 */ for (int j 9; j 0; j--) { g1[j] g1[j-1]; g2[j] g2[j-1]; } g1[0] fb1; g2[0] fb2; } }上面这段只演示码片生成实际工程里还要把码片按采样率展开成采样点再乘上载波。展开时用整数倍关系最稳每个码片重复SAMPLE_RATE / CHIP_RATE次2.046 MHz 下正好是 2。如果采样率不是码率的整数倍就得做插值相位会漂长序列跑下来码相位对不齐这是后面避坑章节要展开的点。2.3 从码片到 IQ载波搬移与量化码片序列是 ±1 的实数要变成 Pluto 能吃的 IQ 数据得乘上复载波。设中频为 f_if采样点为 n则 I 路是code[n] * cos(2π f_if n / fs)Q 路是code[n] * sin(2π f_if n / fs)。这里有个细节C/A 码是 BPSK 调制理论上只有实部但 SDR 发射通道要的是复数基带所以 Q 路不能省否则 Pluto 的 IQ 校正会出问题。量化位宽按 Pluto 的 12 位 DAC 来实际写文件时常用 16 位有符号整数留出余量。幅度不要顶满峰值控制在满量程的 60% 到 70%给滤波器的过冲留空间。生成完的 IQ 数据按交错格式存成二进制文件I 在前 Q 在后小端序这是 Pluto 的 IIO 接口能直接读的格式。# 生成 10 秒、PRN 1、中频 0、采样率 2.046 MHz 的 IQ 文件 ./pluto-gps-sim -p 1 -f 0 -r 2046000 -d 10 -o gps_prn1.bin # 查看文件大小验证采样点数是否对得上 ls -l gps_prn1.bin # 期望大小 10 * 2046000 * 2(IQ) * 2(16bit) 81,840,000 字节命令里的-p是 PRN 号-f是中频-r是采样率-d是时长秒数-o是输出文件。跑完先看文件大小这是最便宜的校验手段算出来的字节数和实际不符说明采样率或者时长参数没生效别急着往下走。3. 把 IQ 流灌进 ADALM-Pluto发射链路配置3.1 Pluto 的发射通道怎么开ADALM-Pluto 默认上电后发射通道是关的需要先通过 IIO 接口把tx的ensm_mode设成fdd或者tx再把raw模式打开才能灌数据。常见做法是用 libiio 的 C 接口或者先用 iio_attr 命令行把通道配好再用脚本推流。pluto-gps-sim 本身只负责生成文件推流这一步要么用项目自带的发送程序要么自己写一个 libiio 循环。发射本振频率要设成目标载波减去中频。比如想让信号落在 1575.42 MHz中频设了 0本振就设 1575.42 MHz中频设了 1 MHz本振设 1574.42 MHz。采样率要和生成文件时一致Pluto 的发射采样率上限在 61.44 MHz 量级2.046 MHz 完全在范围内但要注意它的时钟分频是整数关系设 2.046 MHz 时实际可能落到 2.083 MHz 附近这个偏差会让码率轻微偏移做长时间相干积累时要留意。# 配置 Pluto 发射通道设备名按实际枚举结果替换 iio_attr -c ad9361-phy voltage0 sampling_frequency 2046000 iio_attr -c ad9361-phy voltage0 rf_bandwidth 2000000 iio_attr -c ad9361-phy altvoltage1 frequency 1575420000 iio_attr -c ad9361-phy voltage0 hardwaregain -10 # 打开发射使能 iio_attr -c ad9361-phy voltage0 ensm_mode fddhardwaregain是发射增益单位 dB范围大概 -89 到 0。做近距离验证时别开太高-20 dB 以下配合衰减器更安全直接接天线全功率发射在多数场景下不合规这一点后面避坑章节会专门说。rf_bandwidth设成和采样率同量级太窄会把 C/A 码的主瓣切掉太宽会引入带外噪声。3.2 推流循环与欠载处理推流的核心是一个循环从文件读一块缓冲区写进 Pluto 的cf-ad9361-dds-core-lpc设备的voltage0输出通道。缓冲区大小建议取采样率的整数分之一比如 2046 的整数倍这样每次写入的码相位是连续的。Pluto 的 USB 2.0 接口带宽有限2.046 MHz 采样率、16 位 IQ 的码率约 8.2 MB/sUSB 2.0 理论 60 MB/s 够用但实际受主机调度影响缓冲区太小会欠载。欠载的表现是发射信号出现周期性断裂接收端看到的是码相位跳变。判断方法很简单在推流程序里统计每次write的返回值如果返回字节数小于请求值就是欠载。解决手段是加大缓冲区、提高线程优先级或者把采样率降到 1.023 MHz 试试。我一般会把缓冲区设成 16384 个采样点约 8 ms 的数据给调度留足余量。/* libiio 推流循环骨架 */ struct iio_buffer *buf iio_device_create_buffer(tx_dev, 16384, false); while (running) { ssize_t nbytes read(fd, iq_buf, buf_size); if (nbytes 0) break; memcpy(iio_buffer_start(buf), iq_buf, nbytes); ssize_t written iio_buffer_push(buf); if (written nbytes) { fprintf(stderr, underrun: %zd/%zd\n, written, nbytes); } }iio_buffer_push返回实际推入的字节数小于请求值就是欠载信号。这段骨架里没做重试实际用的时候欠载了要么补零要么重读补零会让码相位断掉重读更稳。缓冲区 16384 是经验值采样率越高越要加大。3.3 用接收端验证信号是否真的发出去了发出去不等于发对了。最直接的验证是用另一块 SDR 或者一台 GPS 接收机在近场接收。没有第二块 SDR 时可以用 Pluto 自己的接收通道做环回加一个衰减器把 TX 接到 RX看频谱上 1575.42 MHz 附近有没有 C/A 码的 sinc 包络。频谱仪上看C/A 码的主瓣宽度约 2.046 MHz零点在 ±1.023 MHz 处旁瓣依次衰减。更严格的验证是解调用开源的 GNSS 软件接收机处理录下来的 IQ看能不能捕获到对应 PRN 的卫星。捕获成功说明码相位和载波都对捕获到了但跟踪不稳多半是采样率偏差或者增益设置问题。这一步别跳过很多“信号发不出去”的翻车其实是参数对不上频谱上看着有能量解调一跑就露馅。4. 避坑与排查五个真实翻车点4.1 采样率不是码率整数倍码相位越跑越偏现象短时间接收正常跑几分钟后捕获不到或者跟踪环频繁失锁。原因生成时用了 2.5 MHz 这类非整数倍采样率每个码周期的采样点数不是整数累积下来码相位漂移超过半个码片。解决采样率取 1.023 MHz 的整数倍2.046 MHz 或 4.092 MHz 最稳实在要用别的值在生成端做相位累加器补偿别指望接收端追。4.2 发射增益开满近场接收机前端饱和现象接收机就在天线旁边信号强度显示很高但就是解不出星。原因Pluto 发射增益设到 0 dB近场功率远超接收机线性范围前端 LNA 饱和产生互调。解决发射增益降到 -30 dB 以下中间串 20 到 30 dB 衰减器接收端看到的功率落在 -80 到 -100 dBm 之间最合适。做实验时先小功率试逐步加。4.3 中频设 0直流泄漏把码频谱顶歪现象频谱上 1575.42 MHz 处有一根很高的尖峰C/A 码的包络被压得看不清。原因中频设 0 时基带信号中心落在直流Pluto 的 DAC 和混频器有直流偏置泄漏到射频上形成强单音。解决中频挪到 1 MHz 到 2 MHz让信号避开直流或者在生成端加一个简单的直流阻断但挪中频更省事。4.4 文件字节序或交错格式不对推流全是噪声现象推流程序不报错频谱上也有能量但完全是噪声捕获不到任何 PRN。原因IQ 文件按大端序写或者 I、Q 分开存而不是交错Pluto 按小端交错读数据全错位。解决生成端统一小端序、I 在前 Q 在后交错用xxd看文件头几个字节和预期值对一下别嫌麻烦。4.5 USB 带宽不够推流欠载导致码相位跳变现象接收端偶尔能捕到但跟踪时断时续码相位有规律地跳。原因缓冲区太小或者主机负载高iio_buffer_push周期性欠载每次欠载丢一段数据码相位不连续。解决缓冲区加到 16384 采样点以上推流线程提优先级关掉主机上占 USB 带宽的其他设备还不行就降采样率到 1.023 MHz。5. 进阶用多 PRN 叠加做场景模拟与验证闭环单 PRN 只能验证链路通不通要做接近真实的场景得把多颗卫星的信号叠在一起。做法不复杂每个 PRN 单独生成一段 IQ按各自的功率比例相加再统一量化。功率比例按仰角算低仰角的卫星信号弱一些典型动态范围控制在 10 dB 以内避免量化时弱信号被截断。叠加时要注意各 PRN 的码相位是独立的不需要对齐但采样率必须一致否则没法直接相加。import numpy as np # 读取多个单 PRN 的 IQ 文件按功率权重叠加 def load_iq(path): raw np.fromfile(path, dtypenp.int16) return raw[0::2] 1j * raw[1::2] # I 偶 Q 奇转复数 signals [load_iq(fgps_prn{p}.bin) for p in (1, 7, 13)] weights [1.0, 0.7, 0.5] # 按仰角粗估的相对功率 n min(len(s) for s in signals) combined sum(w * s[:n] for w, s in zip(weights, signals)) combined / np.max(np.abs(combined)) * 1.4 # 留 30% 余量防削顶 iq np.empty(combined.size * 2, dtypenp.int16) iq[0::2] (combined.real * 32767).astype(np.int16) iq[1::2] (combined.imag * 32767).astype(np.int16) iq.tofile(gps_multi.bin)这段脚本的关键在归一化那行除以峰值再乘 1.4是把峰值压到满量程的 70% 左右给叠加后的过冲留空间。权重按仰角粗估只是权宜真要精确得按自由空间路径损耗算但做链路验证够用。叠加完推流接收端应该能同时捕获到三颗星捕获的载噪比排序和权重排序一致就说明叠加没出错。验证闭环我一般这么走先用单 PRN 确认发射链路和接收端都正常再上多 PRN 看捕获数量最后改多普勒参数看跟踪环的动态响应。每一步只改一个变量出问题能立刻定位到是哪一环。有个习惯是从那以后每次改采样率或者中频都先把文件大小和频谱包络过一遍再推流省得在接收端瞎猜。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
千笔AI:MBA学习场景的AIGC工具解析 1. 项目概述:千笔AI如何重塑MBA学习场景 在商学院的案例研讨室里,经常能看到这样的场景:小组讨论时有人对着电脑屏幕抓耳挠腮,PPT上的数据分析图表迟迟无法成型;凌晨三点的图书馆角落,赶作业的学生对着空白… · 2026/11/4 8:03:40
iOS快捷指令校园网自动登录:GET请求实战指南 1. 项目概述:这不是“自动化”,而是对校园网登录机制的一次精准外科手术“利用iOS快捷指令实现校园网自动登录:GET命令实战解析”——这个标题里藏着三个关键信号:iOS生态的边界能力、校园网认证体系的脆弱性、HTTP协议层的底层操… · 2026/11/4 8:02:40
DASSIDirect 3.0 安装配置全攻略:从环境核对到通信验证 简介:DASSIDirect3.0驱动程序是面向工业自动化编程人员的通讯中间件,用于打通西门子PLC与Intouch上位机之间的数据链路,解决现场设备与组态软件无法直接通信的问题。其适配范围覆盖S7-200、300、400、1200、1500及400H等主流系列,… · 2026/11/4 8:02:40
中小学信息学竞赛真题的CT式诊断与动态验证方法 简介:本资源为2024年海淀区中小学生信息学竞赛校级预选赛官方试题PDF,面向小学高年级及初中阶段编程初学者,聚焦基础编程能力与算法思维的阶段性测评。试题涵盖编程基础知识单选题(变量命名、赋值语句、进制转换、表达式运算、逻辑… · 2026/11/4 8:36:06
Spring Boot与微信小程序打造智能市容考核系统 1. 项目概述 这个基于Spring Boot和微信小程序的市容监察城市管理考核管理系统,是我最近完成的一个毕业设计项目。作为一名有10年开发经验的全栈工程师,我设计这个系统的初衷是想解决城市管理中常见的考核效率低下、数据不透明等问题。系统采用了前后端分… · 2026/11/4 8:36:06
GEO优化与AI推荐系统的地域内容策略 1. GEO概念解析:内容优化的地理维度 GEO(Geographic Targeting)是数字内容分发领域的核心策略之一,指根据用户地理位置特征进行内容优化的技术体系。这个看似简单的概念背后,其实包含着从数据采集到算法适配的完整技术… · 2026/11/4 8:36:06
ISO/IEC 42001:2023 是组织级 AI 治理的结构性约束协议 简介:本资源为国际标准化组织(ISO)与国际电工委员会(IEC)联合发布的首版人工智能管理体系标准——ISO/IEC 42001:2023官方英文原版PDF文档,面向AI产品研发团队、信息技术安全管理者、企业质量体系建设负责人… · 2026/11/4 8:36:06
.NET Core与微信小程序构建市容监管系统实践 1. 项目概述 市容监察管理系统是一个基于.NET框架和微信小程序的综合解决方案,旨在为城市管理部门提供高效、便捷的市容环境监管工具。作为一名从事软件开发十余年的工程师,我深知这类系统在实际应用中的痛点——传统纸质记录方式效率低下、信息传递滞后… · 2026/11/4 8:36:06
SequenceO1:当推理从token级跃升到序列级,长文本生成的新范式 开篇先说清楚一件事:这篇论文的标题挂着“SequenceO1”,但别被名字骗了。它讲的不是又一个“把O1的结果蒸馏成SFT数据”的跟风工作,而是把O1那套“先想后答”的推理范式,从“单步思考”推广到了“整段序列生成”的层面。我读第一遍… · 2026/11/4 8:35:06
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38