SkillAgentSearch skills...

GoWinSDR

基于高云FPGA与AD9363/AD9361射频收发器,构建了一套灵活可重构的软件无线电(SDR)系统,通信核心代码纯Verilog实现。软硬件全开源,高速基带处理部署于FPGA,交互业务部署于Python上位机,通过千兆以太网交互,实现了QPSK等多种实时通信与动态参数配置 Based on the Gowin FPGA and AD9363/AD9361 RF transceiver, a flexible and reconfigurable Software Defined Radio (SDR) system has been built, with the communication core implemented entirely in Verilog.

Install / Use

/learn @ConstStrings/GoWinSDR
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

GoWinSDR

最后由ConstString于2026-03-16编辑

Click to Read English Version:https://github.com/ConstStrings/GoWinSDR/blob/master/README_EN.MD

工程简介

本项目基于高云 GW5AT-LV60 FPGA与ADI AD9363/AD9361射频收发器,构建了一套灵活可重构的软件无线电(SDR)系统。通过软硬件协同设计,将高速基带处理部署于FPGA,将交互业务部署于Python上位机,通过千兆以太网交互,实现了QPSK等多种实时通信与动态参数配置

系统可通过千兆以太网或 USB2.0 (开发中)接口连接 PC 端,配套开发的图形用户界面(GUI上位机)能够直观展示通信参数、数据传输状态等信息,支持用户实时配置系统参数、监控传输过程,大幅提升了人机交互体验。经实际测试,该 SDR 无线通信系统可实现两台设备间的真实无线通信,数据传输速率高达 4Mbps

本工程所使用的FPGA只有PL端,因此将AD936X射频芯片的初始化部分代码移植至STM32平台,经测试运行稳定,使用较为方便。除初始化外的所有逻辑均在FPGA上用Verilog实现

相比Xilinx ZYNQ平台上众多的软件无线电开源项目,本项目没有使用异构FPGA,核心逻辑均使用Verilog实现,数据传输路径更加清晰,操作逻辑更加直观和接近底层,便于无线电爱好者/通信工程师/学生等人群更深入的了解软件无线电基本原理,或作为基本平台进行编码等内容的二次开发

工程结构


GoWinSDR/
├── FPGA/
│   ├── SDR_Final_CMOS/ # 完整版FPGA项目,基于SDR Base底板,实现所有功能
│   ├── SDR_TANG_CMOS/ # AD9363测试项目,基于AD9363_Debug测试板和Sipeed Tang Mega开发板,只能收发单音信号
│   └── Submodule/ # 用于存放测试时使用的子模块,非开发人员请勿使用
├── Firmware/
│   └── GoWinSDR_STM32/ # 初始化AD9363的STM32代码,移植自Xilinx,使用HAL库开发
├── Hardware/
│   ├── Gerber/ # PCB制版文件
│   ├── ProPrj_AD9363_Debug/ # 嘉立创EDA工程,AD9363功能测试板
│   └── ProPrj_GoWinSDR_SMT/ # 嘉立创EDA工程,项目完整PCB
├── Image/  # 存放文档图片
├── Matlab/  # 用于生成滤波器系数
├── Software/ # 基于PyQt的上位机
└── README.MD

系统框图

快速使用

  1. 打样工程ProPrj_GoWinSDR_SMT并焊接,测试各部分电源正常
  2. 打开工程GoWinSDR_STM32,通过板载SWD烧录STM32程序
  3. 打开工程SDR_Final_CMOS,将程序下载/固化到FPGA
  4. 使用Pycharm或其他软件运行上位机,检测参数能否配置,能否收发信号
  5. 若发现某一部分工作异常,可以通过串口和高云FPGA内置逻辑分析仪分析错误

核心代码功能介绍

核心代码位于目录\FPGA\SDR_Final_CMOS\src下

顶层模块

top.v

顶层模块,负责连接各子模块


AD936X 接口

ad9363_dev_cmos.v

AD9363 CMOS接口驱动模块。使用IDDR原语从12位并行总线同时采集I/Q两路ADC数据,使用ODDR原语将I/Q两路DAC数据交替输出至发送总线,实现AD9363芯片的收发时序控制。


以太网

eth_transceiver.v

以太网收发器顶层模块。通过RGMII接口驱动千兆PHY芯片,内部集成125MHz PLL、UDP/IP协议栈,对外提供简洁的用户数据收发接口,支持ARP应答与UDP数据包的封装解析。

eth_frame_gene.v

射频数据帧封装模块(rf_data_processor)。将以太网接收到的用户数据加上自定义帧头(0xEB90CAD3)和帧尾(0x55AA5C4B),通过跨时钟域FIFO送至射频发送侧,用于无线链路的帧同步。

eth_pack.v

射频数据解帧模块(rf_data_framer)。从射频解调比特流中搜索帧头,提取有效载荷,通过跨时钟域FIFO送至以太网发送侧,同时支持IQ互换帧头识别与超时帧错误检测。

arp_responder.v

ARP响应模块。监听以太网输入数据流,识别ARP请求包并提取发送方MAC/IP,自动构造并回复ARP应答帧,使PC能够正确解析FPGA的MAC地址。

crc.v

CRC校验模块,用于以太网帧数据的完整性校验。


调制解调

qpsk_demod.v

QPSK解调顶层模块。集成采样时钟生成、DDS载波生成、混频下变频、低通滤波、Costas环载波同步、Gardner定时同步及差分解码等子模块,完成从中频采样数据到基带比特流的完整解调链路。

costas.v

Costas环载波恢复模块。利用片内DDS生成本地载波,对输入I/Q信号进行正交混频,经鉴相器与环路滤波器闭环控制DDS相位,消除接收信号的载波频偏与相偏。

costas_flt_new.v

改进型Costas环路滤波器(costas_loop_filter_new)。实现带积分饱和保护的PI(比例-积分)控制器,可配置KP/KI增益参数,将鉴相器误差转换为DDS相位调整量,加快环路锁定速度并提升稳定性。

costas_loop_filter.v

Costas环一阶IIR环路滤波器。实现系统函数 H(z) = c1 + c2·z⁻¹/(1−z⁻¹) 的差分方程,采用双增益系数组自适应切换策略(前期大系数快速牵引,后期小系数稳定跟踪),输出24位相位控制字。

phase_detector.v

QPSK载波同步鉴相器。依据I/Q两路低通滤波后信号的符号位,采用判决引导法计算相位误差:error = Q·sign(I) − I·sign(Q),输出58位有符号相位误差供环路滤波器使用。

gardner_sync.v

Gardner定时同步顶层模块。串联内插滤波器、Gardner TED误差检测器与NCO,构成完整的符号定时恢复闭环,输出最佳抽样时刻的I/Q判决数据及同步标志。

gardner_ted.v

Gardner定时误差检测器(TED)。利用Gardner算法 e(k) = I(k−1)·[I(k)−I(k−2)] 计算符号定时误差,经一阶IIR环路滤波后输出16位误差控制字,同时在最佳判决时刻输出I/Q硬判决数据。

nco.v

数控振荡器(NCO)模块。接收环路滤波器输出的频率控制字w(n),对内部寄存器η递减累加,当η下溢(出现负值)时产生strobe溢出信号,同时输出用于内插滤波器的小数间隔μk,实现符号定时控制。

interpolate_filter.v

Farrow结构内插滤波器。依据NCO输出的小数间隔μk,对I/Q输入样值序列进行分段多项式内插(y(k) = f1·μk² + f2·μk + f3),在任意相位点重建信号,实现非整数倍采样率转换。


射频收发

rf_rxt.v

射频收发处理顶层模块。接收侧串联Costas环、Gardner定时同步与差分解码,完成QPSK解调输出比特流;发送侧对输入字节数据进行差分编码与QPSK星座映射,驱动DAC输出I/Q基带信号。

rf_diff_encode.v

QPSK差分编码模块(qpsk_differential_encoder)。将当前2位输入数据与上一时刻I/Q状态进行异或运算,实现差分相移编码(DQPSK),消除解调端的相位模糊问题。

rf_diff_decode.v

QPSK差分解码模块(qpsk_differential_decoder)。将当前I/Q判决位与前一符号进行异或,恢复原始2位数据,与差分编码端对应,实现相位模糊的透明消除。


其他

calibration.v

信号校准模块。对ADC输入数据进行平方运算,经FIR低通滤波提取信号包络,再由正弦波频率计测量当前频率,最终通过data_sender_24bit将24位校准频率数据输出至外部(STM32),用于系统标定。

com_fpga.v

FPGA与MCU通信模块(data_sender_24bit)。将128分频后的低速时钟作为数据时钟,在STM32请求信号触发下,按状态机逐字节串行输出24位数据,实现FPGA向STM32的同步并行数据传输。

led_control.v

433MHz OOK解调模块(demod_433)。对ADC输入的I/Q信号计算瞬时功率(I²+Q²),经64次滑动平均滤波后与功率阈值比较,输出OOK解调数据位,可用于LED状态指示或低速遥控信号接收。


约束文件

SDR_Test.cst

管脚约束文件

timeconstrain.sdc

时序约束文件

SDR_Test.rao

逻辑分析仪配置文件

ARM端程序使用方法

核心代码位于目录\Firmware\GoWinSDR_STM32\Hardware下

主程序已经实现串口命令读取和配置参数,故可以不用修改代码,直接烧录。需要根据实际引脚修改文件\Firmware\GoWinSDR_STM32\\Hardware\api\softspi.h内的SPI相关引脚。

如果想进行更加细致的配置,可修改main.c内的初始化结构体 AD9361_InitParam default_init_param,参数具体含义已在注释中

初始化时会通过串口打印初始化日志,初始化成功后打印当前状态:

采样频率:
  RX: 61440000 Hz (61.44 MSPS)
  TX: 61440000 Hz (61.44 MSPS)
ad9361_rfpll_int_recalc_rate: Parent Rate 80000000 Hz
ad9361_rfpll_int_recalc_rate: Parent Rate 80000000 Hz

LO频率:
  RX: 2400000000 Hz (2.400 GHz)
  TX: 2400000000 Hz (2.400 GHz)
ad9361_set_tx_atten : attenuation 0 mdB tx1=1 tx2=0
Rx gain can be set in MGC mode only
ad9361_rf_port_setup : INPUT_SELECT 0x3

=== Final Status ===
ENSM (0x017): 0x1A (TX_ON=1)
TX Ctrl (0x002): 0x58
PLL Lock (0x247): 0x02 (TX_PLL=1)

支持使用的命令如下,使用串口即可配置,想要查看和修改指令逻辑可以查看\Firmware\GoWinSDR_STM32\Hardware\ad9361\command.c:

help?  - Displays all available commands.
register?  - Gets the specified register value.
tx_lo_freq?  - Gets current TX LO frequency [MHz].
tx_lo_freq=  - Sets the TX LO frequency [MHz].
tx_samp_freq?  - Gets current TX sampling frequency [Hz].
tx_samp_freq=  - Sets the TX sampling frequency [Hz].
tx_rf_bandwidth?  - Gets current TX RF bandwidth [Hz].
tx_rf_bandwidth=  - Sets the TX RF bandwidth [Hz].
tx1_attenuation?  - Gets current TX1 attenuation [mdB].
tx1_attenuation=  - Sets the TX1 attenuation [mdB].
tx2_attenuation?  - Gets current TX2 attenuation [mdB].
tx2_attenuation=  - Sets the TX2 attenuation [mdB].
tx_fir_en?  - Gets current TX FIR state.
tx_fir_en=  - Sets the TX FIR state.
rx_lo_freq?  - Gets current RX LO frequency [MHz].
rx_lo_freq=  - Sets the RX LO frequency [MHz].
rx_samp_freq?  - Gets current RX sampling frequency [Hz].
rx_samp_freq=  - Sets the RX sampling frequency [Hz].
rx_rf_bandwidth?  - Gets current RX RF bandwidth [Hz].
rx_rf_bandwidth=  - Sets the RX RF bandwidth [Hz].
rx1_gc_mode?  - Gets current RX1 GC mode.
rx1_gc_mode=  - Sets the RX1 GC mode.
rx2_gc_mode?  - Gets current RX2 GC mode.
rx2_gc_mode=  - Sets the RX2 GC mode.
rx1_rf_gain?  - Gets current RX1 RF gain.
rx1_rf_gain=  - Sets the RX1 RF gain.
rx2_rf_gain?  - Gets current RX2 RF gain.
rx2_rf_gain=  - Sets the RX2 RF gain.
rx_fir_en?  - Gets current RX FIR state.
rx_fir_en=  - Sets the RX FIR state.
dds_tx1_tone1_freq?  - Gets current DDS TX1 Tone 1 frequency [Hz].
dds_tx1_tone1_freq=  - Sets the DDS TX1 Tone 1 frequency [Hz].
dds_tx1_tone2_freq?  - Gets current DDS TX1 Tone 2 frequency [Hz].
dds_tx1_tone2_freq=  - Sets the DDS TX1 Tone 2 frequency [Hz].
dds_tx1_tone1_phase?  - Gets current DDS TX1 Tone 1 phase [degrees].
dds_tx1_tone1_phase=  - Sets the DDS TX1 Tone 1 phase [degrees].
dds_tx1_tone2_phase?  - Gets current DDS TX1 Tone 2 phase [degrees].
dds_tx1_tone2_phase=  - Sets the DDS TX1 Tone 2 phase [degrees].
dds_tx1_tone1_scale?  - Gets current DDS TX1 Tone 1 scale.
dds_tx1_tone1_scale=  - Sets the DDS TX1 Tone 1 scale.
dds_tx1_tone2_scale?  - Gets current DDS TX1 Tone 2 scale.
dds_tx1_tone2_scale=  - Sets the DDS TX1 Tone 2 scale.
dds_tx2_tone1_freq?  - Gets current DDS TX2 Tone 1 frequency [Hz].
dds_tx2_tone1_freq=  - Sets the DDS TX2 Tone 1 frequency [Hz].
dds_tx2_tone2_freq?  - Gets current DDS TX2 Tone 2 frequency [Hz].
dds_tx2_tone2_freq=  - Sets the DDS TX2 Tone 2 frequency [Hz].
dds_tx2_tone1_phase?  - Gets current DDS TX2 Tone 1 phase [degrees].
dds_tx2_tone1_phase=  - Sets the DDS TX2 Tone 1 phase [degrees].
dds_tx2_tone2_phase?  - Gets current DDS TX2 Tone 2 phase [degrees].
dds_tx2_tone2_phase=  - Sets the DDS TX2 Tone 2 phase [degrees].
dds_tx2_tone1_scale?  - Gets current DDS TX2 Tone 1 scale.
dds_tx2_tone1_scale=  - Sets the DDS TX2 Tone 1 scale.
dds_tx2_tone2_scale?  - Gets current DDS TX2 Tone 2 scale.
dds_tx2_tone2_scale=  - Sets the DDS TX2 Tone 2 scale.
calibration?  - Get Lo Freq diff.
calibration=  - Calibrate Lo Freq diff.
rx_lo_up=  - Increase RX LO frequency.
rx_lo_down=  - Decrease RX LO frequency.
query_led_state?  - Decrease RX LO frequency.
query_led_state=  - Decrease RX LO frequency.

上位机功能介绍

上位机基于 Python + PyQt6 开发,采用多线程架构,通过串口与以太网双通道与 FPGA 通信,提供图形化的参数配置、数据收发与实时监控功能。


启动方法

安装好Python开发环境后,在PyCharm等软件内运行main.py

整体架构

主窗口 (main_window.py) 采用左右分栏布局:左侧为配置区,右侧为多选项卡功能区。后台运行多个独立的 QThread 工作线程,分别负责串口通信、UDP 网络收发、音频流采集/播放和摄像头采集,所有线程间通过 Qt 信号槽机制进行线程安全的数据传递。


串口通信

serial_worker.py 实现了串口工作线程,支持可用端口枚举、可配置波特率(最高 921600bps)的串口连接/断开,以及全双工的数据收发。接收端对数据流进行逐行解析:格式为 key=value 的响应被识别为参数回调并转发至参数面板,其余内容作为日志显示。

config_widget.py 提供串口配置 UI,包含端口刷新、波特率选择及连接状态管理。


以太网通信(UDP)

ethernet_worker.py 实现了基于 UDP 的可靠/不可靠双模式传输协议:

  • 文本命令:采用停等协议(Stop-and-Wait),支持最多 128 次重传。
  • 文件传输:先用停等协议发送文件头(含文件名与大小),再用 SR(Selective Repeat)滑动窗口协议(窗口大小为 4)发送文件数据,实现乱序重传;全程携带 CRC32 校验。
  • 实时视频流:采用自定义分包协议(帧头含帧ID、分片序号、总分片数),允许丢包,每帧拆分为最大 1024 字节的分片后以不可靠方式发送,接收端按帧ID进行分片重组。
  • 实时音频流:以不可靠方式直接发送 PCM 音频块,保证低延迟实时性。

ethernet_widget.py 提供 UDP 配置 UI,含 FPGA 目标地址(IP/端口)和本地监听地址配置,以及开始/停止监听按钮。


AD9363 参数配置

params_widget.py 提供 AD9363 射频芯片的参数配置面板,分 TX(发射)和 RX(接收)两个选项卡,涵盖本振频率、采样率、射频带宽、增益控制、FIR 使能及 DDS 音调频率等参数的读取与设置。每个参数条目包含输入框和 Set 按钮,点击后通过串口发送 key=value 格式命令。支持"手动查询所有参数"一键刷新,以及在连接后自动批量查询所有 GET 命令(ad9363_config.py 中定义)。


文件、文本及录音

text_audio_widget.py 支持通过串口发送文本消息,以及触发音频录制/停止。

file_send_widget.py 实现文件发送 UI,包含文件浏览、文件信息预览(文件名、大小、类型、路径),以及带实时进度条、传输速率(Mbps)和预计剩余时间的传输状态显示。

file_receive_widget.py 实现文件接收 UI,支持启用/禁用文件接收,显示带进度条和速率的实时接收状态,已接收文件列入表格并可选择保存到本地。


实时语音传输

realtime_audio_widget.py 提供实时双向语音传输界面,发射侧支持枚举系统音频输入设备(包括 WASAPI 内录),选择音源后启动麦克风采集并通过 UDP 实时发送;接收侧将网络接收的 PCM 数据送入音频输出队列实时播放。两侧均内嵌波形图实时显示音频波形。

audio_stream_worker.py 基于 sounddevice 库实现:AudioInputWorker 以回调方式从指定设备连续采集 44100Hz/单声道/float32 音频块;AudioOutputWorker

View on GitHub
GitHub Stars59
CategoryDevelopment
Updated11h ago
Forks9

Languages

Verilog

Security Score

80/100

Audited on Apr 5, 2026

No findings