频谱分析仪 UI 自定义绘制

第一部分:实时频谱分析自定义绘制层

构造参数决定行为:

枚举 含义
ENRTSABaseTypem_basetype 图形类型:普通频谱 / 放大 / PvT / 概率密度(Thick) 等
ENRTSAColorTypem_colortype 是否显示右侧色温条:Color_Y 有,Color_N

TraceView 与 paint 的分工:

模式 TraceView paint
Base_Spec / Base_SpecLine / Base_PvT 白色频谱迹线 + 网格 参数文字、色条(若开启)、Marker
Base_Thick(频率功率/概率密度,默认 DisplayType=4) 仅网格/坐标轴 密度图 + 白色迹线 + 色条 + 标注 + Marker

Base_Thick 模式下 不调用 TraceView::UpdateTraceData,迹线完全由 paint → DrawTraceData 绘制。


1.2 paint 主流程(七步)

第一步:初始化绘制环境

  • painter->save() 保存画布状态。
  • 设置主题文字色、12pt 字体、文字抗锯齿。
  • 通过 pixMapper->GraphRect 计算绑图区及顶部/底部文字 Y 坐标。

第二步:语言分支

  • Language == 0:英文标注;否则中文。结构相同,仅字符串不同。

第三步:按 BaseType 绘制参数文字(仅文字,无图形数据)

BaseType 顶部 底部
Base_Spec / SpecLine / SpecLine2 Y 轴刻度、参考电平 中心频率、扫宽、RBW、采集时间
Base_Magnify / Base_Line 同上 Zone 中心频率、Zone 扫宽
Base_PvT --- RBW、刻度、采集时间
Base_Thick Y 轴刻度、参考电平 中心频率、扫宽、RBW、采集时间

数值由 SAUnits 自动格式化(dB、dBm、Hz、s)。

第四步:绘制右侧色温条(详见第二部分)

触发m_colortype == Color_Y m_basetype == Base_Thick

第五步:概率密度 + 白色迹线(仅 Base_Thick)

  1. 色条旁写五档百分比标签:100.0%、14.9%、2.2%、0.3%、0.0%。
  2. DrawPointData:底层彩色密度图。
  3. DrawTraceData:顶层白色瞬时谱线。

绘制顺序:密度(底)→ 迹线(顶)。

第六步:Marker 信息(所有 BaseType)

右上角显示当前选中标记的频率/幅度或 Delta 差值;频率精度随 Span/SweepPoint 自适应。

第七步:painter->restore() 结束。


1.3 DrawPointData --- 概率密度图

概率密度图是统计信号在「频率 + 幅度」二维平面上出现的频次 / 概率,专门抓瞬态、跳变、间歇性、低占空比信号,是普通频谱(迹线)做不到的。
数据m_BitMapData,256 行(功率档)× N 列(频率档),m_Scale/m_Offset 将行索引映射为 dBm。

步骤:

  1. 空数据则返回;扫描矩阵求 maxColor 归一化。
  2. 每行功率 → 像素 Y(GetYMaxData / GetYMinData)。
  3. 按屏幕宽度合并水平像素,避免过密。
  4. 非零单元:命中比 = 值/maxColorGetSelectColor(colors, 命中比)fillRect

密度图与右侧色条共用同一 colors 向量,保证图例与图像一致。


1.4 DrawTraceData --- 白色瞬时迹线

数据m_TraceData,长度 m_TraceNum

  • 点数 ≥ 像素宽:GetCompressedData 每列取 max/min,画竖线段(保峰)。
  • 点数 < 像素宽:GetEnlargedData 扩展宽度,画折线。
  • Y 坐标经 pixMapper->YValueToPixel 转换;画笔白色,drawLines 批量绘制。

1.5 多类型策略总览

复制代码
第三步:参数文字(所有类型)
    ↓
Color_Y 或 Base_Thick ? → 第四步:色温条
    ↓
Base_Thick ? → 第五步:密度 + 白线
    ↓
第六步:Marker(所有类型)

1.6 数据流

复制代码
Base_ReceiveData
├─ 所有模式:Trace1 → m_TraceData
├─ Base_Thick:BitMap → m_BitMapData,设置 Scale/Offset/BitMapNum,不调 UpdateTraceData
└─ 其他模式:UpdateTraceData + SignalUpdate(迹线由 TraceView 画)

paint 只读 rtasParammarkerParam,不修改数据。


第二部分:色温系统专题

色温逻辑是 AllColorData() 预生成,paint 运行时查表使用。

2.1 全局状态变量

静态变量 默认值 作用
m_AllColor --- 6 套完整调色板(QMap,key=0~5)
m_ColorType 1 当前使用的方案(对应 ParamCode::ColorSelect
m_MaxColor 100 色条顶部参考位置 %(FeferColorLocat
m_MinColor 0 色条底部位置 %(BottomColorLocat
m_MaxYData / m_MinYData 0 / -100 密度图 Y 轴 dBm 范围

用户参数映射(RtsaMainWidget::OnParamChanged):

  • ColorSelectSetColorType(index) → 切换 6 套配色
  • FeferColorLocatSetFeferData → 色条顶部裁剪
  • BottomColorLocatSetBottomData → 色条底部裁剪
  • ReferenceLevel / AxisYScaleSetYRange → 密度图 Y 映射

2.2 AllColorData --- 六套调色板预生成

调用时机RtsaMainWidget 构造时 RtsaPublicFunc::AllColorData(),只执行一次。

基本参数colorBarLength = 1530(约 255×6 级渐变),tempLength = 255 为每段长度。

方案 0 --- 冷色

按顺序生成 4 段 RGB 线性渐变:

渐变方向 视觉
1 B↑(蓝→青) (0, t, 1)
2 G↓(青→绿) (0, 1, 1-t),步长 2
3 R↑(绿→黄) (t, 1, 0),步长 2
4 G↓(黄→红) (1, 1-t, 0)

方案 1 --- 暖色

6 段完整彩虹环,每段 255 色:

渐变
1 红→黄 (1, t, 0)
2 黄→绿 ((2L-i)/L, 1, 0)
3 绿→青 (0, 1, t)
4 青→蓝 (0, 1-t, 1)
5 蓝→品 (t, 0, 1)
6 品→红 (1, 0, 1-t)

共约 1530 色。后续 AbstractColor 对暖色只取 前 4/6(约 1020 色)作为有效范围,对应红→蓝主视觉,去掉尾部冗余段。

方案 2 --- 灰色

灰度从 (153/255) 线性降至 (30/255),约 123 级。

方案 3 --- 雷达色

两段:红→黄(255 色)+ 黄→绿(255 色),共 510 色。

方案 4 --- 火热色

单段红→黄 (1, (255-i)/255, 0),255 色。

方案 5 --- 冰霜色

两段:浅蓝白 (i,i,1) 从 255→170;再过渡到 (i,i,(85+i)/255) 至 0。

设计意图:启动时一次性生成高分辨率色表,运行时零计算开销,仅做索引抽样。


2.3 AbstractColor --- 按绑图高度适配色表

入口AbstractColor(unsigned int width)width = 绑图区像素高度。

第一步 :按 m_ColorTypeveccolor = m_AllColor[m_ColorType],并确定有效色数 pointnum(暖色取 count/6*4,其余取全部)。

第二步 :按 widthpointnum 关系分支:

情况 策略
width == 0 直接返回完整 veccolor
width < pointnum(色多屏少) 抽取:均匀跳采样,每屏像素对应色表中一个颜色
width > pointnum(色少屏多) 重复 :每个原色重复 absnumabsnum+1 次填满高度

抽取/重复使用「商 + 余数分配」算法:前 absheight 行多分配 1 个色阶,保证总输出长度恰好等于 width

输出 :长度 = widthQVector<QColor>,每像素一行对应一个颜色。


2.4 GetColorLocat --- 色条最终输出

调用链GetColorLocat(width)AbstractColor(width) → 可选二次裁剪。

复制代码
GetColorLocat(allnum)
    │
    ├─ colors = AbstractColor(allnum)     // 已适配高度 + 当前 ColorType
    │
    ├─ 若 m_MaxColor==100 且 m_MinColor==0
    │     → 直接返回 colors(全范围色条)
    │
    └─ 否则二次裁剪:
          Allnum = (m_MaxColor - m_MinColor) / 100 × colors.count()
          从 colors 中再均匀抽取 Allnum 个颜色
          → 返回 tempcolor(缩短后的色条)

含义

  • m_MaxColor = 100m_MinColor = 0:色条覆盖全高度(默认)。
  • 用户调 FeferColorLocat(如 80%):m_MaxColor=80,色条只保留原色表的上 80% 段,低密度区颜色被裁掉,视觉上「热色区」压缩。
  • BottomColorLocat 控制底部裁剪,两者共同定义有效色温显示区间。

GetFeferData() 返回 m_MaxColor/100,供 paint 做垂直偏移。


2.5 paint 中绘制右侧色温条

位置RtsaSpecBaseItem::paint 第四步。

第一步:前置检查

  • 仅当 Color_YBase_Thick 时进入。
  • GraphRect.bottom < GraphRect.top,直接 return(区域无效)。

第二步:计算几何参数

参数 含义
allnum bottom - top 色条高度 = 绑图区像素高
colorwidth 20 色条宽度(px)
rightmargin 2 与绑图区右边缘间距
Xposition GraphRect.right + 2 色条左 X
startnum top + (1-GetFeferData())×allnum 垂直起始 Y(Fefer 偏移)

第三步:取色

  • colors = GetColorLocat(allnum),长度 = allnum

第四步:逐行 fillRect

  • 循环 index = 0 ... colors.count()-1
    • QRect(Xposition, startnum + index, 20, 1)
    • painter->fillRect(rect, colors[index])
  • 每行 1 像素高,20 像素宽,拼成竖直渐变色条。

第五步(Base_Thick 专属):百分比标签

  • 调用 DrawTextYAxisColor(painter, "100.0%", mode, width)mode 0~4 分别对应顶、1/4、1/2、3/4、底。
  • 文字 X = GraphRect.right + colorwidth + rightmargin,与色条对齐。
  • 五档标签与 GetSelectColor 的四段阈值一致(100%、14.9%、2.2%、0.3%、0.0%)。

第六步:密度图复用同一 colors

  • DrawPointData(painter, colors) 传入相同向量,命中比查同一色表,保证色条与密度图颜色语义一致。

2.6 GetSelectColor --- 命中比到颜色的非线性映射

密度图每个像素的 percennum = 矩阵值 / maxColor(0~1),映射规则:

percennum 范围 色条区间 对应标签
≥ 14.9% (0.149) 第 1 段(最热) 100.0%
2.2% ~ 14.9% 第 2 段 14.9%
0.3% ~ 2.2% 第 3 段 2.2%
< 0.3% 第 4 段(最冷) 0.3% / 0.0%

色条被均分为 4 段(everynum = count/4),段内线性插值索引。低频命中→冷色,高频命中→暖色。


2.7 色温系统数据流总图

复制代码
启动: AllColorData() → m_AllColor[0~5]

运行时参数:
  ColorSelect → m_ColorType
  FeferColorLocat → m_MaxColor
  BottomColorLocat → m_MinColor

每帧 paint:
  allnum = 绑图高度
  colors = GetColorLocat(allnum)
      └─ AbstractColor(allnum)
            └─ m_AllColor[m_ColorType] 抽样/重复
      └─ 按 Max/Min 二次裁剪
  fillRect × allnum → 右侧色条
  GetSelectColor(colors, 命中比) → 密度图 fillRect

第三部分:VSA 数字解调 --- 星座图与眼图

星座图与眼图是 VSA 数字解调两大核心分析视图,二者互补定位信号质量。星座图基于 IQ 复平面,每个点位对应一个传输符号,主要评估幅相精度。点位集中规整代表调制质量优异;点位弥散、偏移、出现杂点,说明存在噪声、IQ 失衡、相位偏差、功放非线性等问题,配套 EVM、MER 等指标可量化调制误差,常用于发射机、射频链路故障排查。

眼图由基带符号波形按时钟叠加而成,侧重分析时域信号完整性。眼孔开阔、线条纤细,代表码间干扰(ISI)、噪声、抖动小;眼孔收窄、边缘粗糙、水平扩散,意味着带宽不足、时序抖动大、同步异常。通过眼高、眼宽可判断噪声与时序裕量。

实际测试中,星座图查调制与射频失真,眼图看基带与时序问题,结合两项视图能快速定位数字通信链路的各类缺陷。
三层图像:

图层 内容
_backgroundLayer 黑底 + 网格 + 刻度
_foregroundLayer 星座/眼图曲线
_clickedLayer 鼠标点击读数

3.2 数据传入格式与顺序

测量端

  • I_constellation[i]Q_constellation[i]:解调后第 i 个符号的 I/Q。
  • ConstellationLen:有效点数 N。
含义
kIData I 数组指针
kQData Q 数组指针
kIQLength N
kSymRate 符号率
ModFormat / SymbolRate 测量参数,影响解调,不直接传入 Draw

合成 Complex

复制代码
索引:  0      1      2    ...   N-1
I:    I[0]   I[1]   I[2]  ...  I[N-1]
Q:    Q[0]   Q[1]   Q[2]  ...  Q[N-1]
→ Complex(I[i], Q[i]),按符号时间顺序排列

上限 MaxIQLen = 2002Render 内再截断至 16384。

Perform 归一化(每帧)

求 I/Q 各自 min/max,映射到约 [-0.9, 0.9],避免帧间幅度差导致显示缩放跳动。


3.3 模式配置与颜色

InitChartWidget 当前配置:

Widget SetModel 设计意图
m_pDiagramWidget kConsole, true 星座图
m_pEyeWidget kIQ, true 源码为 I/Q 时域(非经典眼图)
颜色 条件 含义
黄色 _input == true 星座:符号间 I-Q 轨迹折线;眼图:折叠叠加的黄色迹线(eyeInPen
红色 _output == trueSystemControl/EyeDiagram 版) 星座:各 (I,Q) 位置 4×4 红色像素块(参考/输出点)

3.4 星座图绘制步骤

模式_isDrawConstellation=true,走 DrawConstell

  1. DrawBGLayer:黑底、I/Q 网格、±1 刻度、中心十字线。
  2. 坐标映射 (每点 i):
    • screenX = 左边距 + 中心X + I × gain
    • screenY = 上边距 + 中心Y + Q × gain(非正方形控件做等比例补偿)
    • 超界裁剪。
  3. _input=true:黄线连接各点(≤4096 点平滑曲线,否则折线)→ 符号跳转轨迹。
  4. _output=true:在 (I,Q) 处画点(红块或浅绿像素,取决于实现版本)。
  5. DrawTicks:轴标签。
  6. paintEvent:合成三层 QImage。

64QAM:ModFormat 只影响解调算法;UI 只接收已解调的 I/Q 序列,理想时呈 8×8 点阵,噪声导致扩散。


3.5 眼图绘制步骤

  • X = 样本序号(时间);I 路、Q 路分别为绿/红折线(若 _isShowIPart/_isShowQPart 开启)。
  • 不是经典折叠眼图。

经典眼图

模式_isDrawEye=trueDrawEyediagram

  1. period = _samplePerSymbol × 2(2 符号周期宽度)。
  2. period 分段取连续 IQ 点,X = 段内时间槽,Y = 中心 + I×gain
  3. 每段画一条黄色 折线(eyeInPen),多段叠加成「眼」。
  4. _output=true 时另有绿色输出迹线(通常未开,故界面只见黄色)。

数据要求 :高采样率时域 IQ(meaDatI/Q);当前 VSA 传的是稀疏 I_constellation(每符号 1 点),更适合星座图。


3.6 后台线程刷新

DrawThread::run(约 100ms 周期):

  1. _isDrawBGLayer → 重画网格。
  2. _iqDataChanged → 拷贝 IQ → DrawFGLayer → 更新前景。
  3. _isDrawFGLayer → resize/切模式时强制重画。
  4. _isClickedMouse → 点击读数框。

3.7 VSA 当前代码缺口

环节 状态
测量 → MainWindow 正常
Complex 合成 + Render 已注释(ReceiveData 265--298 行)
SetSampleRate / SetSamplePerSymbol 已注释
m_pEyeWidget 模式 配置为 kIQ,非 kEye

完整可参考 Plugins/UIFIXAQPlugin_eyeDiagram->Render() 调用链。


第四部分:两套体系统对照

维度 RTSA VSA
宿主 TraceView + GraphItemBase 独立 QWidget + QImage 贴图
主数据 Trace1 + BitMap(256×N) kIData + kQData → Complex[]
颜色系统 RtsaPublicFunc 6 套色温 + GetSelectColor 固定黄/红(input/output)
异步 TraceView 重绘回调 paint DrawThread 100ms 循环
默认视图 Base_Thick(DisplayType=4) kConsole + kIQ
相关推荐
Agent手记2 小时前
制造业生产流程自动化,Agent需要具备哪些能力?深度拆解2026工业级智能体落地范式与核心架构
大数据·人工智能·ai·架构·自动化
Yunzenn3 小时前
深度分析字节最新研究cola-DLM 第 07 章:推理流水线逐行拆解 —— 从 prompt 到生成文本
人工智能·驱动开发·深度学习·chatgpt·架构·prompt·github
颖火虫盟主4 小时前
Linux 系统分层架构:从硬件通电到 systemd 进程管理
linux·运维·架构
ฅ ฅBonnie5 小时前
Hermes 与 Cloud Code/OpenClaw 架构对比分析及部署实践
人工智能·ai·架构·ai编程
实在智能RPA5 小时前
实在Agent针对金融行业Agent灾备与高可用是如何进行设计的?深度拆解金融级智能体的架构安全与连续性保障
人工智能·安全·ai·金融·架构
zhangfeng11336 小时前
主流推理模型架构的协议对比表格,和专利坑 专利埋雷
人工智能·语言模型·自然语言处理·架构·开源·开源协议
这是谁的博客?6 小时前
LangChain 框架深度解析:从 LCEL 到 Agent 架构的核心原理
ai·架构·langchain·llm·agent·架构设计
Championship.23.246 小时前
Linux 3.0 中断机制深度解析:从传统PIC到现代中断架构的转折点
linux·运维·架构·中断
高级c6 小时前
Ascend C 算子开发:10 分钟写一个高性能 MatMul
深度学习·架构·cann
@insist1236 小时前
系统架构设计师-企业信息化核心知识体系
架构·系统架构·软考·系统架构设计师·软件水平考试