当前位置: 首页 > news >正文

频谱分析仪 UI 自定义绘制

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

构造参数决定行为:

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

TraceView 与 paint 的分工:

模式TraceViewpaint
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/SpecLine2Y 轴刻度、参考电平中心频率、扫宽、RBW、采集时间
Base_Magnify/Base_Line同上Zone 中心频率、Zone 扫宽
Base_PvTRBW、刻度、采集时间
Base_ThickY 轴刻度、参考电平中心频率、扫宽、RBW、采集时间

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

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

触发m_colortype == Color_Ym_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_AllColor6 套完整调色板(QMap,key=0~5)
m_ColorType1当前使用的方案(对应ParamCode::ColorSelect
m_MaxColor100色条顶部参考位置 %(FeferColorLocat
m_MinColor0色条底部位置 %(BottomColorLocat
m_MaxYData/m_MinYData0 / -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 线性渐变:

渐变方向视觉
1B↑(蓝→青)(0, t, 1)
2G↓(青→绿)(0, 1, 1-t),步长 2
3R↑(绿→黄)(t, 1, 0),步长 2
4G↓(黄→红)(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(区域无效)。

第二步:计算几何参数

参数含义
allnumbottom - top色条高度 = 绑图区像素高
colorwidth20色条宽度(px)
rightmargin2与绑图区右边缘间距
XpositionGraphRect.right + 2色条左 X
startnumtop + (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)mode0~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。
含义
kIDataI 数组指针
kQDataQ 数组指针
kIQLengthN
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当前配置:

WidgetSetModel设计意图
m_pDiagramWidgetkConsole, true星座图
m_pEyeWidgetkIQ, 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()调用链。


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

维度RTSAVSA
宿主TraceView + GraphItemBase独立 QWidget + QImage 贴图
主数据Trace1 + BitMap(256×N)kIData + kQData → Complex[]
颜色系统RtsaPublicFunc 6 套色温 + GetSelectColor固定黄/红(input/output)
异步TraceView 重绘回调 paintDrawThread 100ms 循环
默认视图Base_Thick(DisplayType=4)kConsole + kIQ
http://www.jsqmd.com/news/894523/

相关文章:

  • 2026年比较好的厂区数字化孪生/厂区BIM三维规划/厂区仓储规划哪家好 - 行业平台推荐
  • OTAIP:用确定性智能体架构破解垂直领域AI应用难题
  • 15分钟构建本地MCP服务器:为AI智能体打造安全可控的“手和眼”
  • 2026年NL2SQL多智能体架构:从自然语言到安全SQL的模块化实现
  • 别再只盯着HTML了:聊聊SVG标签里那些意想不到的XSS攻击姿势
  • HyperAgents:AI智能体如何实现自主代码优化与安全自我改进
  • 8051微控制器代码空间配置与优化实践
  • 微处理器瞬态执行安全挑战与MA-IC验证框架
  • 负载电阻从500Ω到10kΩ:用Multisim玩转高频谐振放大器的选频特性与带宽权衡
  • 别再傻傻分不清!FPGA里简单双端口RAM和真双端口RAM到底怎么选?
  • 用30行YAML替代600美元工具:自建CI/CD代码审查流水线实践
  • 2026年4月钨钢回收企业推荐,钨钢回收/锡渣回收/废合金回收/锡膏回收/废锡回收,钨钢回收供应商哪个好 - 品牌推荐师
  • Unity游戏里做个动态时钟UI?用C#的DateTime.Now和ToString(),5分钟搞定
  • 别再手动建模了!手把手教你用Creo/STEP文件导入Adams做行星齿轮运动仿真
  • 别再只盯着角度了!用IMU模块(三轴加速度/陀螺仪/磁力计)玩点新花样:从平衡小车到手势识别
  • 从iwconfig到iw再到wpa_supplicant:一文理清Linux无线网络工具的历史演进与实战选型
  • 告别‘碰碰车’循线:手把手教你用Mixly调校L298N电机驱动的PID参数(附完整程序块)
  • 构建AI智能体可信工具搜索引擎:从意图理解到安全调用
  • PostgreSQL时间处理进阶:从‘today’到‘interval’,这些隐藏技巧让你的SQL更高效
  • 2026年比较好的瓶胚模具/热流道瓶胚模具/台州饮料瓶胚模具厂家哪家好 - 品牌宣传支持者
  • 别再手动烧录了!用STM32标准库给F4系列做个Bootloader,实现远程OTA升级
  • 从DT-830B到进阶:新手电子爱好者如何挑选你的第一块万用表(附避坑指南)
  • 【ChatGPT】美国泛林集团(Lam Research)Flex-Class 介质刻蚀机及其控制系统软硬件架构深度拆解、爆炸图10张、信息图10张、C++代码框架
  • 从Iris到实战:用sklearn的train_test_split划分数据,新手最容易踩的3个坑
  • 告别卡顿!用轻薄本+SSH+X11转发,远程流畅运行Vivado 2019.2全攻略
  • 给算法新手画张图:用等高线图解MOEAD的切比雪夫分解,到底怎么选解?
  • ZettaLith架构与CREST容错机制解析
  • Unity游戏里做个实时时钟?用C#的DateTime.Now和ToString(),5分钟搞定UI显示
  • 3分钟快速诊断网络NAT类型:NatTypeTester免费工具完整指南
  • 多IMU视觉惯性腿里程计在足式机器人中的应用