ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LabVIEW虚拟仪器14个实验:四层知识地图与复习清单

LabVIEW虚拟仪器14个实验:四层知识地图与复习清单

简介:这份《虚拟仪器技术》实验报告面向测控技术与仪器及相关专业本科生,也可供学习LabVIEW编程与虚拟仪器开发的读者参考。内容围绕14个实验展开,从温度计、面板控制、鼠标属性、Tab控件与Event语句等基础VI设计,到帕斯瓦尔定理验证、双通道信号显示、函数波形发生器、信号处理、脉冲上升沿计数,再到串行通信、TCP/UDP波形传输和DataSocket技术,覆盖数据采集、信号处理与网络通信的关键环节。资源包为1个PDF文件,约4.22MB,结构完整,包含实验要求、目的、步骤、参考面板与实验记录,并配有DAQ PCI-6024E、Demobox等硬件配置说明及附录中的Demo Box使用介绍。已有96人学习。读者可据此复现实验流程、对照面板与程序框图理解LabVIEW编程逻辑,并借助通信与信号处理案例积累解决实际工程问题的思路。

1. 知识地图:14 个实验其实只有四层结构

虚拟仪器技术这门课,一句话概括就是「用软件定义仪器」。同一块多功能数据采集板、同一个 Demo Box 信号装置,前面板换成温度计就是温度仪,换成波形图就是示波器,换成频谱图就是分析仪——硬件不动,功能全靠 LabVIEW 程序堆出来。所以它跟传统仪器课最大的差别在于:要复习的重点不在电路,而在数据怎么从采集端口一路流到前面板的指示灯上。14 个实验摊开看很零散,什么温度计、Tab 控件、Event 语句、帕斯瓦尔定理、TCP/IP 通信,其实完全能收敛成四层:界面与数据流(控件、接线端、子VI)、程序结构(While、Case、Event、属性节点)、信号与测量(采样、FFT、帕斯瓦尔、波形发生、上升沿计数)、通信与采集(DAQ、串口、TCP/UDP、DataSocket)。前三层是基本功,第四层才是把仪器连成系统。如果你正对着实验报告复习,或者准备重做一遍交作业,按这四层往下走,比按实验序号一二三四硬背要省力得多。

2. 界面与数据流:控件、接线端与子VI的复用设计

这一层是所有实验的地基。温度计系列看起来是三个独立实验,实际是一条封装链:先做一个能显示温度的 VI,再把它当零件塞进分析 VI,最后在分析 VI 外面套一层报警逻辑。链条能不能搭起来,取决于你有没有真搞懂接线端和子VI的约定。

2.1 三块选板:控件、函数、工具各管一段

LabVIEW 的开发界面里,选板就三块,但初学时最容易把它们的功能搞混,以为控件选板里放的都是「显示」。控件选板上放的叫 Control(输入控件)和 Indicator(显示控件),区别在于数据方向,而不是外形——一个旋钮可以是输入,一个波形图也可以被改成输入。判断标准很简单:数据从它流向程序是输入,从程序流向它是显示;右键 Change to Control / Indicator 可以互转,转换之后接线端的箭头方向也会跟着变。

函数选板是框图窗口的专属,结构、数值运算、比较、字符串、信号处理、通信全在这里,实验里反复出现的 Multiply、Subtract、Divide、Select、While Loop、Case Structure 都是从这块拖出来的。工具选板则是操作层面的东西:操作值、定位、连线、断点、探针,其中最常用的是连线和探针,前者决定程序通不通,后者决定你知不知道为什么不通。Ctrl+E 在前后面板之间来回切,这个快捷键用熟了能省掉一半翻菜单的时间。

选板作用位置典型对象常见误用
控件选板前面板数值控件、布尔开关、波形图表、Tab、Table把显示控件当输入用,接线端方向搞反
函数选板程序框图While、Case、Event、Select、比较、信号处理在框图里找不到结构,跑去前面板翻
工具选板两者通用连线、定位、探针、断点一直用自动连线,交叉线把框图绕成面条

2.2 数据流:连线就是变量

LabVIEW 执行模型是数据流驱动的:一个节点的所有输入都到齐才开始执行,输出齐了再往下游传。这跟文本语言按行执行完全不是一回事,也是很多人第一次看框图时觉得「看不出顺序」的原因——它本来就没有严格的行序,只有依赖关系。温度计实验里,随机数先乘 100 得到 0 到 100 的模拟温度,再进 Select 的两个分支,最后进温度计指示,这条链的先后完全由连线决定。

由此带来两个经验:第一,顺序结构(Sequence)只在必须强制次序时才用,比如先配置串口参数、再写数据、最后读数据,其他情况滥用顺序结构会让框图变成一团乱麻;第二,局部变量和全局变量会绕开数据流,让程序出现「明明连线了但读到旧值」的玄学现象,初学阶段尽量用连线和移位寄存器代替。调试靠三件套:高亮执行(灯泡按钮)能看见数据沿着线一格一格跑,探针能钉在任意一根线上看实时值,断点则适合定位那些只在特定分支才出错的地方。

2.3 接线端与子VI:图标不是装饰

把一个 VI 变成可复用零件,要做两件事:编图标、定接线端。图标编辑里用画图工具画形状,按住 Shift 画线能保证水平或垂直;画完用文本工具写上短标签,字体换成小号更清楚。接线端则是点右上角图标框弹出 Show Connector,LabVIEW 会按前面板控件数量自动推荐一种端口布局,不满意可以自己选。

定义端口的方式很直观:用连线工具点一下端口框,框变黑;再点对应的控件,控件周围出现闪动的虚线框,说明绑定成功;点空白处虚线框消失、端口变暗,表示已定义。这里有个必须记住的约定:前面板控件的接线端,输入放图标左侧、输出放右侧,跟图标上数据的自然流向一致。搞反了不会报错,但调用方会一头雾水。

维度直接用连线的平铺程序封装成子VI之后
重复工作量每处都要重连一遍换算逻辑只连输入输出两根线
改动成本改一次要改 N 处,容易漏改子VI一处,全工程生效
调试难度全局可见但噪声大可单独打开子VI跑,边界清晰
复用范围只在本 VI 内可保存进 .llb 程序库跨 VI 调用

温度计 VI 就是按这个流程做好后存进程序库的,实验二里再通过 Select a VI 把它调进来当 SubVI,实验三又在实验二的基础上加报警。封装一次、三处复用,这是整门课最值得反复强调的设计习惯。

2.4 温度计三连:显示、分析、报警的递进关系

三个实验的难度是台阶式的,复习时把它们当成一条链看,比单独背每个实验的步骤有效得多。

实验输入核心结构输出考点
温度计随机数×100 模拟温度、单位选择开关Select 分支温度计指示件控件与指示件区分、图标与接线端
温度分析SubVI 输出的温度流While + 波形图表最大、最小、平均值循环、图表刷新、子VI调用
温度控制温度流比较 + 声音 + 时间超阈值报警比较子模板、报警逻辑、延时

单位换算这一步是三个实验共同的暗线,也是最容易记反的地方:从摄氏求华氏是乘 1.8 再加 32,从华氏求摄氏是先减 32 再除以 1.8。原文步骤里那一路随机数生成的是 0 到 100 的数值,布尔开关决定它走换算分支还是直通分支,Select 的两个输入端子分别接两条路——注意 Select 是按布尔值选,真分支和假分支各自接哪条线,一旦接反,前面板上指针动的方向就是错的,而程序本身不会报任何错。

3. 程序结构:While、Case、Event 与属性节点三件套

结构决定了程序「跑多久、走哪条路、什么时候响应」。这门课里出现的结构不多,但每一个都有明确的使用场景和对应实验:While 负责持续运行,Case 负责分支判断,Event 负责响应动作,属性节点负责改外观。四者叠起来,基本能覆盖面板控制、鼠标属性、Tab 控件、Event 语句这四个实验。

3.1 While 循环:条件接线端与机械属性

While 循环的条件接线端在右下角,默认是「真时停止」,右键可以切成「真时继续」,这两个设置写反了,程序的表现就是「一运行就退出」或者「怎么点都不停」——排查时先看这里,比看连线快。左下角的迭代端子 i 从 0 开始计数,做累加或者计数实验时经常要拿它当索引。

循环体里必须放一个等待函数(Wait ms 或 Wait Until Next ms Multiple),否则循环会以 CPU 能跑的最快速度空转,前面板卡死、风扇狂转,这是最典型的踩坑现场。等待时间设多少,取决于你需要多快的刷新率:显示温度这种慢变量,100 到 200 毫秒足够;做信号显示则要让采样节奏和循环节奏对上。

停止按钮的机械属性则是另一个高频翻车点。布尔控件的机械动作有四种,行为完全不同:

机械属性按下后行为松开后行为适合场景
Switch Until Released变真立即回假模拟按键脉冲
Latch When Released变真松开瞬间回假,且程序读到一次后自动复位大多数停止按钮
Latch When Pressed按下瞬间变真并锁存程序读到后复位触发一次性动作
Switch Until Released 之外的 Switch 型保持按下状态保持状态直到再次点击模式切换开关

做循环停止时选 Latch When Released 最省心,因为程序读到真值后会自己复位,下一轮循环不会因为开关还按着而立刻又退出。另外,实验里要求把某个状态设为默认值,用的是 Data Operations 里的 Make Current Value Default,这一步不做,下次打开 VI 开关的初始状态就跟你上次运行时不一样。

3.2 Case 结构:选择器可以是任何类型

Case 结构的选择器不只接受布尔值,枚举、整数、字符串、错误簇都能当分支条件。密码输入实验里,字符串比较的结果作为布尔选择器,真分支发声、假分支什么都不做;Tab 实验里则用整数索引去选页。默认分支一定要处理,否则某个没预料到的取值进来,程序会停在那个分支上不动,看起来就像死机。

密码子VI的几个细节值得单独记:字符串控件要设成密码显示(输入回显为星号),两个布尔开关按逻辑分别设机械属性,VI 属性里把窗口设成对话框样式并关掉不必要的按钮,主程序按下运行键才调用这个子VI。日期时间显示用的是格式化日期时间字符串函数,格式串写%Y-%m-%d %H:%M:%S就能输出常见的年月日时分秒,格式符写错是最常见的「显示不出来」原因。

3.3 属性节点:把外观当成数据来写

属性节点是 LabVIEW 里比较特殊的存在,它不传递业务数据,而是去改控件本身的属性,比如颜色、位置、尺寸、是否可见、是否可用。创建方式是在控件上右键 Create 找到 Property Node,节点左侧输入控件引用,右侧输出引用,中间用属性选择器点开挑具体属性。

鼠标属性实验的思路很典型:前面板放两个 Picture 控件盖在波形图上面,用调色板把 Picture 背景设成透明,这样波形照常显示,鼠标事件却落在 Picture 上。然后靠 Mouse Down 和 Mouse Position 这两个属性判断鼠标是否在窗口上方,落在 Case 结构里改颜色或者弹 One Button Dialog。这里用到的簇操作是 Unbundle,因为鼠标位置返回的是坐标簇,要拆出横纵坐标分别用。

Tab 控件实验则是纯粹的外观控制:四个数值显示控件放进不同页,用属性节点设置 Tab 的尺寸、颜色、明暗和使能状态,选页用数组索引。要注意属性节点之间没有天然的执行顺序,写属性是「设置」、读属性是「取值」,如果你需要「先设成可用再读值」这种次序,就得用错误簇串起来或者加顺序结构,光靠并排摆放是靠不住的。

3.4 Event 结构:把轮询换成事件

Event 结构解决的是「用户不点,程序也在空转检查」的问题。它内部的事件分支不是靠循环去查开关状态,而是由 LabVIEW 在事件真正发生时唤醒。结构左侧有超时端子,设成 -1 表示永不超时,设成正数则超时后走超时分支。事件源可以是本 VI、某个控件,也可以是动态注册的。

实验五里,showgraph.vi 负责同时显示多道数据,主程序用 Event 结构调用它并更新 Table 控件的内容,用 List 控件做选项。这里的分工要理清:子VI负责画,主VI负责触发和更新表格,事件只是触发手段。

对比项While + 轮询布尔Event 结构
CPU 占用循环多快就查多快,白烧无事件时不占
响应延迟取决于循环周期事件到达即响应
漏事件风险两次轮询之间的点击可能丢事件排队不丢
写法复杂度简单需要管事件源、超时和分支

事件分支里不要写耗时操作,比如等待、长循环、大文件读写——事件结构在处理某个分支期间不会响应其他事件,前面板会整体僵住。真需要耗时,就把参数丢出去,让另一个循环去干。

4. 信号与通信:从帕斯瓦尔定理到 TCP/UDP 的完整链路

这一层是整门课从「会画界面」到「能做测量系统」的分水岭。前三个实验还在跟控件较劲,从帕斯瓦尔定理开始就要面对真实的采样参数,从串行通信开始就要面对两台设备之间怎么把数据送过去。复习时建议按「采集 → 处理 → 显示 → 传输」这条链路串,而不是按实验编号背。

4.1 采集端:DAQ 板卡与 Demo Box 的信号通路

采集链路的起点是多功能数据采集板,实验里用到的是 PCI-6024E 这类插装式板卡,具备多路模拟输入通道,具体通道数和最高采样率以板卡手册为准,实验里真正用到的往往只是其中一路模拟输入。信号从 Demo Box 多功能信号装置进来——它能产生方波、正弦一类的测试信号,也能通过拨码开关给出电平变化,正好用来验证计数和波形显示。接线时要注意量程和参考方式,量程选小了信号会削顶,选大了分辨率浪费。

实验前期大量使用的 Demo Read Voltage 函数,是教学阶段的替代方案:它不真去读硬件,而是返回一个模拟电压值,让你先把数据流、循环、图表这套逻辑跑通。等逻辑通了再接真实通道,出问题的范围就缩小到「接线和配置」这一小块,这是很实用的排查策略。真实采集时要配的参数无非四项:用哪个通道、量程多大、采有限点还是连续采、采样率多少。

4.2 采样参数与帕斯瓦尔定理:三个公式撑起半章

采样率 fs、采样点数 N、频率分辨率 Δf 三者的关系是 Δf = fs / N,采集时长则是 T = N / fs。这三个式子必须能随手写出来,因为实验里几乎所有「谱线对不上」「频率测不准」的问题,最后都能追到这三个量上。奈奎斯特条件 fs > 2×最高频率分量是底线,低于它会出现混叠——高频信号伪装成低频,图上看不出任何异常,这是最阴险的一种错。

帕斯瓦尔定理说的是时域能量等于频域能量之和,离散形式下:

Σ |x[n]|² = (1/N) · Σ |X[k]|²

实验里验证它的常见做法是:给一个单频正弦,算时域均方值,再做 FFT 算各谱线能量和,两者应当相等。手动计算时有两点必须注意——单边谱除直流和奈奎斯特分量外要乘 2 才是真实幅度;频谱除以 N 才是归一化幅度。下面这段用代码把整个验算过程走一遍,比对着公式空想可靠得多。

import numpy as np fs = 1000.0 # 采样率,由采集时钟决定 N = 1024 # 采样点数,决定频率分辨率 df = fs / N t = np.arange(N) / fs x = 1.5 * np.sin(2 * np.pi * 50 * t) # 50 Hz、幅度 1.5 的单频信号 # 时域:均方值即平均功率 p_time = np.mean(x ** 2) # 频域:先除以 N 归一化,再还原单边谱幅度 X = np.fft.rfft(x) / N mag = np.abs(X) mag[1:-1] *= 2 # 除直流与奈奎斯特外乘 2 # 正弦的有效值平方 = 幅度平方 / 2 p_freq = np.sum(mag ** 2) / 2 print(round(p_time, 4), round(p_freq, 4)) # 两者应同为 1.125

这段代码里 fs 和 N 决定 Δf 是 1000/1024 约 0.977 Hz,50 Hz 正好落在第 51 根谱线上,所以能量几乎全集中在一根线里;如果信号频率落在两根谱线中间,能量会泄漏到相邻谱线,你会看到频域和略小于时域和——那不是帕斯瓦尔定理失效,而是没加窗或者没做整周期采样。另外,这段只对无直流的单频信号成立,真遇到带直流分量的数据,直流那根谱线不能除以 2,加了窗还要按窗函数的相干增益修正,这两条是最容易漏的。

4.3 波形发生、双通道显示与上升沿计数

函数波形发生器实验要能把波形类型、频率、幅度、相位、偏置、占空比这几个参数都做进前面板,方波的占空比和三角波的对称性是最容易被忽略的两个。生成端一般用信号生成类函数,输出接波形图显示;调参数时先动频率看周期变化,再动幅度看峰峰值,最后动偏置看整体上下平移,这样每个参数的作用一眼就能分清。

双通道信号显示实验的核心是「怎么把两路放进一张图还分得清」。两路信号可以捆成簇,也可以拼成二维数组,关键在于图例要能改名、Y 轴要能缩放。这里必须区分两种显示件:

显示件数据组织方式刷新行为典型用途
Waveform Chart单点或数组追加保留历史,逐点滚动温度、连续监测
Waveform Graph一次性给完整数组每次重画整段已采集完的波形、频谱

上升沿计数的思路是小信号处理里最经典的边沿检测:信号先过阈值比较变成布尔序列,再用移位寄存器保存上一拍的布尔值,当前为真、上一拍为假时判定为一次上升沿,计数加一。这里有个隐含前提——采样率必须远高于脉冲重复频率,否则一个窄脉冲可能整个落在两次采样之间,直接漏数。

4.4 通信四选一:串口、TCP、UDP、DataSocket

通信这块有四个实验,函数不同但套路一致:打开、配置、收发、关闭。区别在于可靠性和使用场景,做成一张表记最省事。

方式连接特性可靠性关键函数链适用场景
串行通信点对点、独占可靠但速率低配置串口 → 写 → 读(先查字节数)→ 关闭仪器控制、单片机对接
TCP面向连接、需先握手可靠、有序、不丢不重监听 → 打开连接 → 写 → 读(指定字节数)→ 关闭波形数据完整传输
UDP无连接、直接发不保证到达、可能乱序打开 → 写(带地址端口)→ 读 → 关闭实时波形广播、允许丢包
DataSocket基于 URL 的发布订阅取决于底层打开 → 写 / 读 → 关闭前面板数据共享、快速搭演示

串口配置要写清波特率、数据位、停止位、校验位和终止符,读写两侧必须完全一致,差一位就是一堆乱码。TCP 最容易误解的地方是它只保证字节流有序,不保证「一次读对应一次写」,所以必须自己做消息边界。下面这段演示长度前缀的做法,LabVIEW 端的读写逻辑与此完全对应。

import socket, struct HDR = struct.Struct("!I") # 4 字节大端长度头,收发两端约定一致 def send_frame(sock, payload: bytes): sock.sendall(HDR.pack(len(payload)) + payload) # 先发长度,再发内容 def recv_frame(sock) -> bytes: head = b"" while len(head) < HDR.size: # TCP 是字节流,头可能只到一半 chunk = sock.recv(HDR.size - len(head)) if not chunk: raise ConnectionError("对端已关闭") head += chunk (n,) = HDR.unpack(head) body = b"" while len(body) < n: # 必须循环读到 n 字节为止 chunk = sock.recv(n - len(body)) if not chunk: raise ConnectionError("对端已关闭") body += chunk return body

对应到 LabVIEW,TCP Read 的字节数输入就是这个 n,你不能指望它一次把整条消息吐出来,也不能随手填一个大数字等着它自己截断。DataSocket 则把这件事简化成 URL 发布订阅,形式上最像「共享变量」,适合快速搭出跨 VI 的数据传递,但对传输质量的要求不能太高。

5. 易错点:五个最容易翻车的地方

这些坑的共同特征是「程序不报错,但结果不对」,比崩溃更难查。每个都按「漏在哪、为什么漏、怎么补」写一遍,复习时对照自己曾经踩过的打勾。

5.1 界面与结构上的三个坑

易漏点一:华氏摄氏换算式方向记反。为什么漏:两个公式长得像,都带 32 和 1.8,平时只记「有个 32 有个 1.8」,考试一紧张就乱。怎么补:记一句物理常识——华氏一度比摄氏一度小,所以数值上华氏总是更大,从摄氏到华氏一定是乘 1.8 再往上加,反向才需要减。写完程序用两个锚点验:0 摄氏度等于 32 华氏,100 摄氏度等于 212 华氏,指针位置对不上立刻能发现。

易漏点二:停止按钮机械属性选错,或者循环里忘了放等待。为什么漏:默认属性有时刚好能用,换一台机器或者换个版本表现就变了;等待函数更是完全不影响功能正确性,只影响体验,所以很容易被删掉。怎么补:停止按钮统一用 Latch When Released,循环体里固定放一个 Wait,做显示用 100 到 200 毫秒,做采集按采样周期算。

易漏点三:子VI接线端方向和数量对不上。为什么漏:LabVIEW 不会因为你把输入端口放在右边而报错,只是调用时端口排列和你预期不一致,接错线也能跑,跑出来的数就是错的。怎么补:定完端口后立刻存盘,再新建一个空 VI 把它拖进来试调一次,看端口布局是否符合「左入右出」;子VI内部改动后记得重新打开调用方确认端口没变。

5.2 信号与通信上的两个坑

易漏点四:把采样率和频率分辨率混为一谈。为什么漏:两者都跟「每秒多少个点」有关,公式又只差一个 N。怎么补:把 Δf = fs / N 写在前言位置,每次设计采集参数先定 Δf(要分辨多近的两根谱线),再定 fs(要覆盖多高的频率),N 由这两个反推出来,顺序反了就会得到一堆看着能用其实分辨不开的数据。

易漏点五:把 TCP 当成「一次写对一次读」。为什么漏:本地测试时数据量小、网卡快,几乎总是一次就收发完整,看上去毫无问题,换到大数组传波形立刻碎成一堆错位数据。怎么补:收发两端强制加长度前缀或者固定终止符,读端循环读到够数为止;UDP 那边则相反,别指望它可靠,收到的包要带序号,缺了就直接丢,不要试图拼。

6. 复习清单:把 14 个实验压成一张自查表

复习到这一步,与其把实验报告从头翻一遍,不如做三件事:填一张模块表、答三个自测题、跑一遍参数验算。模块表按实验分组填,每一行只填最关键的那一项,填不出来的就是漏洞所在。

模块必须记住的控件与函数必须记住的参数常见追问
温度计三连Select、While、波形图表、子VI接线端华氏摄氏换算方向为什么封装成子VI
面板控制Case、字符串密码显示、格式化日期时间机械属性四选一停止按钮为什么用 Latch
鼠标与 Tab属性节点、Unbundle、透明 PictureTab 的尺寸颜色使能三类属性属性节点有没有执行顺序
Event 语句Event 结构、Table、List 控件超时端子取值含义事件里为什么不能放等待
信号处理FFT、单边谱、上升沿检测Δf = fs / N、奈奎斯特条件帕斯瓦尔两边对不上怎么查
通信四件套串口配置、TCP 监听与读写、UDP 收发、DataSocket波特率、字节数、URL 格式TCP 与 UDP 怎么选

三个自测题,能不看笔记答上来才算过关:第一,给你一段温度分析的框图,说出子VI调用前后数据是怎么流的,最大最小值在哪一步算出来;第二,采样率 2000 Hz、采 4096 点,频率分辨率是多少,能不能分辨 0.4 Hz 间隔的两根谱线;第三,要传一段 10 万点的波形,选 TCP 还是 UDP,为什么,消息边界怎么定。

第三步是把公式真的跑一遍。第 4 章那段验算代码改几个参数就能复用:把 fs 调成 2000、N 调成 1000,信号频率设成 50.5 Hz,观察频域能量怎么从一根谱线摊到两根上;再把幅度改成 3.0,确认时域均方值和频域和同步变成 4.5。跑过一遍,公式就不再是背下来的符号,而是能对数的东西。

我自己的血泪经验是:第一遍做温度分析时,指针动得很欢,最大最小值也出了数,交之前随手把随机数种子固定了才发现,平均值一直在小幅漂——原因就是循环里没放等待,图表刷新太快,看着像在采集,其实在读同一批数。从那以后我每次开新 VI,都强制先把三件事走一遍:循环里放等待、停止按钮设 Latch、子VI先单独跑通再接进主程序。这三步花不了两分钟,能省掉后面一晚上的排查。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进