演示)
F´ 框架中的 Ref::SignalGen 组件详解多波形信号发生器与数据产品Data Product演示【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprime导读Ref::SignalGen是 F´F Prime飞行软件与嵌入式系统框架在参考部署Ref中提供的一个演示组件位于 TestDeploymentsProject/Ref/SignalGen。它一方面作为地面软件绘图与曲线测试的信号源能够按可调参数生成三角波、方波、正弦波与噪声四种波形另一方面它完整演示了 F´ 数据产品Data Product机制中“同步获取 / 异步请求”两种缓冲申请方式。读完本文你将掌握该组件的端口结构、四条命令的用法与参数校验逻辑、八路遥测与九个事件的含义、四种波形算法的底层实现以及数据产品从申请缓冲到序列化记录、再到发送清理的完整生命周期。1. 组件概述根据 Ref::SignalGen 软件设计文档该组件定位为演示组件核心用途有二生成不同波形作为测试信号源供地面软件ground software绘制曲线、验证绘图与遥测链路演示数据产品展示 F´ 框架中数据产品的两种缓冲请求方式并将命令指定数量的信号样本存入数据产品容器。在 FPPF´ Prime Parser模型中组件被定义为queued component队列化组件这意味着它拥有内部消息队列命令与异步数据产品接收product recv等都会进入队列按序处理 A component for generating periodic signals queued component SignalGen { ... }定义见 SignalGen.fpp2. 需求Requirements设计文档中给出了两条系统级需求均以系统测试作为验证方法需求编号描述验证方法REF-SGN-001Ref::SignalGen组件应能生成带可调参数的波形遥测tunable waveforms系统测试REF-SGN-002Ref::SignalGen组件应使用数据产品存储波形数据系统测试对应单元测试位于 SignalGen/test/ut/SignalGenTestMain.cpp 及 SignalGenTester.cpp其中的test_start()用例正是对上述两条需求的直接验证。3. 设计3.1 组件上下文与端口结构设计文档给出的组件框图如下源自 TestDeploymentsProject/Ref/SignalGen/docs/img/SignalGenBDD.jpgRef::SignalGen组件框图队列化组件包含调度输入、命令、遥测、事件与数据产品端口从框图与 FPP 模型可以归纳出组件的完整端口清单输入/特殊端口见 SignalGen.fpp端口类型说明schedInsync input port: Svc.Sched同步调度输入由 RateGroup 周期性驱动每次触发采样一次productGetOutproduct get port数据产品同步获取缓冲端口getproductRequestOutproduct request port数据产品异步请求缓冲端口requestproductRecvInasync product recv port异步接收数据产品容器返回productSendOutproduct send port发送已完成的数据产品timeCallertime get port获取时间标签组件还继承了 F´ 标准组件共有的命令cmdIn/cmdRegOut/cmdResponseOut、遥测tlmOut、事件logOut/logTextOut等特殊端口。组件内部定义了数据产品记录与容器 Signal generation data product record product record DataRecord: SignalInfo id 0 Data product container product container DataContainer id 0 default priority 10见 SignalGen.fpp3.2 核心数据结构FPP 类型定义组件在 FPP 中定义了供波形与数据产品复用的复合类型SignalGen.fppstruct SignalInfo { $type: Ref.SignalType history: Ref.SignalSet pairHistory: Ref.SignalPairSet } struct SignalPair { $time: F32 format {f} value: F32 format {f} } array SignalPairSet [4] Ref.SignalPair array SignalSet [4] F32 format {f} enum SignalType { TRIANGLE SQUARE SINE NOISE }要点SignalType枚举定义了四种波形TRIANGLE三角波、SQUARE方波、SINE正弦波、NOISE噪声SignalSet与SignalPairSet均为长度 4 的数组分别保存最近 4 个 Y 值与最近 4 个 (time, value) 点对作为滚动历史窗口SignalInfo是合成结构体聚合了当前波形类型、Y 值历史与点对历史既是遥测Info通道的类型也是数据产品记录DataRecord的载荷。4. 命令Commands组件共暴露四条命令全部定义在 Commands.fppi4.1 Settingsopcode 0x00设置波形参数async command Settings( Frequency: U32 Amplitude: F32 Phase: F32 SigType: Ref.SignalType ) \ opcode 0x00参数类型含义FrequencyU32信号频率HzAmplitudeF32信号幅值PhaseF32相位弧度SigTypeRef.SignalType波形类型TRIANGLE / SQUARE / SINE / NOISE参数校验源码级依据在 SignalGen.cpp 的Settings_cmdHandler中频率需要满足两个约束否则直接以Fw::CmdResponse::VALIDATION_ERROR拒绝并保留原设置Frequency 0零频率会导致除法/取模除零每周期采样数的一半halfSamplesPerPeriod截断为 0即频率过高超过采样频率的一半此时波形算法无法工作。校验通过后组件更新signalFrequency、signalAmplitude、signalPhase、sigType将历史数组清零重置发出SettingsChanged事件并立即更新Type遥测最后回复OK。4.2 Toggleopcode 1启停信号async command Toggle \ opcode 1翻转内部running标志并将采样计数器ticks归零。每调用一次在运行/停止之间切换无参数SignalGen.cpp。4.3 Skipopcode 2跳过下一个采样async command Skip \ opcode 2将skipOne标志置位下一次调度周期将输出 0 值采样等效于丢点用于测试地面软件的断点/缺口绘制能力随后标志自动复位SignalGen.cpp。4.4 Dpopcode 3生成数据产品enum DpReqType { IMMEDIATE ASYNC } async command Dp( reqType: DpReqType records: U32 $priority: U32 ) \ opcode 3参数类型含义reqTypeDpReqTypeIMMEDIATE同步获取缓冲 /ASYNC异步请求缓冲recordsU32要写入的记录条数必须 ≥ 1$priorityU32覆盖容器默认优先级容器默认优先级为 10该命令是数据产品演示的入口详细流程见第 7 节。5. 遥测通道Telemetry组件输出 8 路遥测定义见 Telemetry.fppi| 通道 | 类型 | ID | 格式 | 含义 | | ---- | ---- | -- | ---- | ---- | |Type| Ref.SignalType | 0 | - | 当前输出波形类型 | |Output| F32 | 1 |{.4f}| 当前单点 Y 值 | |PairOutput| Ref.SignalPair | 2 | - | 当前 (time, value) 点对 | |History| Ref.SignalSet | 3 | - | 最近 4 个 Y 值 | |PairHistory| Ref.SignalPairSet | 4 | - | 最近 4 个 (time, value) 点对 | |Info| Ref.SignalInfo | 5 | - | 综合信息类型 两组历史 | |DpBytes| U32 | 6 | - | 当前数据产品已写入字节数 | |DpRecords| U32 | 7 | - | 当前数据产品已写入记录数 |其中Output以 4 位小数格式化适合地面软件直接绘图History与PairHistory提供滚动窗口便于观察波形轨迹。6. 事件Events组件定义 9 个事件Events.fppi按严重级别分为两类活动级activity low——正常流程信息| 事件 | ID | 格式 | 含义 | | ---- | -- | ---- | ---- | |SettingsChanged| 0 |Set Frequency(Hz) {}, Amplitude {f}, Phase {f}, Signal Type {}| 参数已更新 | |DpStarted| 1 |Writing {} DP records| 数据产品写入开始 | |DpComplete| 2 |Writing {} DP records {} bytes total| 数据产品写入完成 | |DpMemRequested| 7 |Requesting {} bytes for DP| 申请缓冲大小 | |DpMemReceived| 8 |Received {} bytes for DP| 实际收到缓冲大小 |警告级warning low / warning high——异常与降级处理| 事件 | ID | 严重级别 | 含义 | | ---- | -- | -------- | ---- | |DpRecordFull| 3 | warning low | 容器已满提前关闭并发送 | |DpsNotConnected| 4 | warning high | 数据产品端口未连接 | |DpMemoryFail| 5 | warning high | 获取数据产品缓冲失败 | |InSufficientDpRecords| 6 | warning high | records 参数小于 1 |7. 数据产品演示两种缓冲请求方式核心特性这是设计文档特别强调的演示重点Ref::SignalGen会演示请求数据产品缓冲的两种不同方式并将命令指定条数的采样记录存储为数据产品sdd.md。7.1 命令入口的参数校验与预处理Dp_cmdHandlerSignalGen.cpp执行三件事记录数校验records 0时发出InSufficientDpRecords并回复VALIDATION_ERROR端口连接检查productGetOut输出端口未连接时发出DpsNotConnected并回复EXECUTION_ERROR按请求类型分派计算所需缓冲大小dpSize records * SIZE_OF_DataRecord_RECORD保存目标记录数、当前记录计数与优先级发出DpMemRequested事件后进入两条分支。7.2 方式一IMMEDIATE同步获取缓冲Fw::Success stat this-dpGet_DataContainer(dpSize, this-m_dpContainer);通过productGetOut的dpGet_DataContainer同步阻塞获取指定大小的DpContainer若失败Fw::Success::FAILURE发出DpMemoryFail回复EXECUTION_ERROR若成功将m_dpInProgress置位发出DpStarted与DpMemReceived打印实际缓冲大小回复OK并用命令传入的 priority覆盖容器优先级。7.3 方式二ASYNC异步请求缓冲this-dpRequest_DataContainer(dpSize);通过productRequestOut的dpRequest_DataContainer异步请求缓冲命令立即回复OK缓冲分配完成后由外部缓冲管理器如 DpManager通过productRecvIn端口回调触发dpRecv_DataContainer_handlerSignalGen.cpp状态为SUCCESS接收容器、置位m_dpInProgress、设置优先级、发出DpStarted状态为FAILURE发出DpMemoryFail并清理所有 DP 相关计数。7.4 记录写入调度驱动数据产品的实际写入发生在schedIn_handlerSignalGen.cpp中每到一个调度周期组件先调用doDispatch()处理队列中的命令与异步回调然后若正在运行生成一个采样并写入遥测若m_dpInProgress为真则Fw::SerializeStatus stat this-m_dpContainer.serializeRecord_DataRecord(sigInfo); this-m_currDp; this-m_dpBytes SignalInfo::SERIALIZED_SIZE;即把每个SignalInfo采样序列化为一条DataRecord记录。随后判断是否结束容器写满FW_SERIALIZE_NO_ROOM_LEFT发出DpRecordFull并立即关闭容器达到目标记录数m_currDp m_numDps发出DpComplete并关闭容器。两种情况下都调用cleanupAndSendDp()SignalGen.cpp通过dpSend将容器经productSendOut发送给下游存储组件然后复位m_dpInProgress、m_dpBytes、m_numDps、m_currDp。同时每周期更新DpBytes与DpRecords两路遥测。7.5 完整生命周期小结Dp 命令 → 校验(records/端口) → IMMEDIATE: dpGet 同步拿缓冲 / ASYNC: dpRequest 异步等回调 → schedIn 每周期序列化一条 DataRecord同时写遥测 → 容器满 或 达到 records → dpSend 发送 → 计数复位7.6 单元测试验证SignalGenTester.cpp 的test_start()完整复现了这一链路断言初始无遥测输出发送Toggle启动生成器并触发一次调度断言Output遥测产生 1 条发送Dp(IMMEDIATE, 10, priority1)断言productGetOut被调用 1 次缓冲申请成功再触发一次调度断言productSendOut发送 1 次数据产品完成输出。测试器在productGet_handler中用m_dpBuff[1024]提供缓冲并打印申请字节数与命令按records × 单条记录大小计算出的dpSize相互印证SignalGenTester.cpp。8. 波形生成算法源码级解析采样由内部辅助函数generateSample(U32 ticks)完成SignalGen.cpp。它基于两个参数计算samplesPerPeriod sampleFrequency / signalFrequency每周期采样数sampleFrequency默认 25以及halfSamplesPerPeriod samplesPerPeriod / 2当后者为 0 时直接返回 0 以防御退化频率。波形算法源码摘录数学含义TRIANGLEval m * (ticks % halfSamplesPerPeriod)其中m amplitude / halfSamplesPerPeriod以半周期为斜坡的线性三角波幅值由 m 缩放SINEval amplitude * sin(2π·normalizedFrequency·ticks phase·2π)其中normalizedFrequency 1/samplesPerPeriod标准正弦相位参数以 2π 倍率折算进相位角SQUAREval amplitude * ((ticks % samplesPerPeriod halfSamplesPerPeriod) ? 1.0 : -1.0)半周期为 amp、半周期为 −amp 的方波NOISEval amplitude * (rand() / RAND_MAX)均匀分布白噪声幅值缩放注源码注释表明正弦/三角波形“courtesy of the open source Aquila DSP Library”源自开源 Aquila DSP 库的思路。Skip命令通过skipOne标志使采样返回 0 实现丢点。8.1 调度与遥测写入流程schedIn_handler的完整执行序列doDispatch()由于是队列化组件必须在同步调度调用中主动派发队列里的命令与异步回调running为假则直接返回空跑生成采样或 Skip 丢点→ 构建SignalPair(ticks, value)滚动平移sigHistory与sigPairHistory长度 4 的滑动窗口末尾写入新值依次写 6 路波形遥测Type、Output、PairOutput、History、PairHistory、Info若正在进行数据产品写入序列化DataRecord并更新 DP 遥测ticks。9. 部署与实例化在参考部署Ref拓扑中该组件被实例化为5 个实例SG1~SG5TestDeploymentsProject/Ref/Top/instances.fppbase id 依次为0x10011000~0x10015000各自配置了队列深度。这 5 个实例在 Ref 拓扑定义 中与 RateGroup提供schedIn调度、命令分发器CmdDispatcher、遥测/事件接收链以及数据产品管理器DpManager连接形成可运行的端到端演示操作人员通过地面系统向某个 SG 实例发送Settings/Toggle即可在遥测曲线中看到对应波形发送Dp命令即可触发数据产品落盘。组件的构建与测试入口见 CMakeLists.txt。10. 变更日志Change Log设计文档记录的版本演进sdd.md日期说明2017-04-20初始版本2024-04-26新增数据产品演示DP 命令、IMMEDIATE/ASYNC 两种缓冲请求、DataRecord/DataContainer这也解释了为什么文档中的需求 REF-SGN-002数据产品存储与第 7 节内容是较新加入的特性。总结Ref::SignalGen是理解 F´ 框架命令-遥测-事件三件套与数据产品机制的极佳范例它用约 280 行 C 实现 一份 FPP 模型同时覆盖了波形信号生成、参数校验、队列化组件调度、数据产品双模式缓冲申请、容器序列化与发送的完整链路。无论是想为地面软件准备绘图数据源还是想复刻一套同步/异步获取数据产品缓冲的标准写法都可以直接以该组件为模板进行移植与扩展。【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考