groovy - 如何在unetstack中发送和接收基带信号?
问题描述
我正在尝试一个项目,该项目涉及在水下通信中实施声学传播损耗模型(基于某篇研究论文)。我们正在尝试在unetstack
. 最终目标是创建一个实现了所有损失模型的通道模型类。
但是现在我们已经开始尝试从一个节点向另一个节点发送基带信号,然后尝试捕获接收节点上的频率并计算该给定频率上的损耗模型。(损耗模型是信号频率值的函数)。我尝试关注一些文档和一些博客文章,但我无法传输和接收信号。
作为参考,我已经参考了这些文章:1.) svc-12-baseband 2.) basic-modem-operations-using-unetstack
这是我正在遵循的研究论文,以根据不同的损失模型计算损失。
我试图为模拟编写一个 groovy 文件,但它似乎不起作用。如果有人可以请看一下并让我知道我所犯的错误,那将是真正的帮助。我们对 unetstack 以及像这样的水下信号处理主题还很陌生,这是我们第一次尝试在模拟器上实现它。我们正在使用unetsim-1.3
非常感谢任何帮助!提前致谢
import org.arl.fjage.*
import org.arl.unet.*
import org.arl.unet.phy.*
import org.arl.unet.bb.*
import org.arl.unet.sim.*
import org.arl.unet.sim.channels.*
import static org.arl.unet.Services.*
import static org.arl.unet.phy.Physical.*
import java.lang.Math.*
platform = RealTimePlatform
simulate 3.minutes, {
def n = []
n << node('1', address: 1, location: [0,0,0])
n << node('2', address: 2, location: [0,0,0])
n.eachWithIndex { n2, i ->
n2.startup = {
def phy = agentForService PHYSICAL
def node = agentForService NODE_INFO
def bb = agentForService BASEBAND
subscribe phy
subscribe bb
if(node.address == 1)
{
add new TickerBehavior(50000, {
float freq = 5000
float duration = 1000e-3
int fd = 24000
int fc = 24000
int num = duration*fd
def sig = []
(0..num-1).each { t ->
double a = 2*Math.PI*(freq-fc)*t/fd
sig << (int)(Math.cos(a))
sig << (int)(Math.sin(a))
}
bb << new TxBasebandSignalReq(signal: sig)
println "sent"
})
}
if(node.address == 2)
{
add new TickerBehavior(50000, {
bb << new RecordBasebandSignalReq(recLen: 24000)
def rxNtf = receive(RxBasebandSignalNtf, 25000)
if(rxNtf)
{
println "Received"
}
println "Tried"
})
}
}
}
}
在某些情况下,甚至在打印“已发送”之前先打印“已尝试”。这表明(node.address == 2)
代码在执行之前先(node.address == 1)
执行。
解决方案
TxBasebandSignalReq
您用于信号传输 ( ) 和接收 ( )的基本代码RecordBasebandSignalReq
似乎是正确的。
这应该在调制解调器上运行良好,除了您的信号生成可能由于两个原因而存在缺陷之外:
您正在尝试使用 24 kHz 的载波频率和 24 kHz 的带宽以基带表示生成 5 kHz 的信号。该信号将被混叠,因为该基带表示只能表示 24±12 kHz 的信号,即 12-36 kHz。如果您需要传输 5 kHz 信号,则需要调制解调器以低得多的载波频率运行(在模拟器中很容易,但实际上您需要检查调制解调器规格)。
您正在对
sin
和的输出进行类型cos
转换int
。这可能不是您打算做的,因为它signal
是一个在 -1 和 1 之间缩放的数组float
。所以(int)
建议放弃它。
在模拟器上,您需要确保正确设置调制解调器参数以反映您对基带载波频率、带宽和记录长度的假设:
modem.carrierFrequency = 24000
modem.basebandRate = 24000
modem.maxSignalLength = 24000
默认HalfDuplexModem
参数不同,并且您当前的代码将失败RecordBasebandSignalReq
并返回REFUSE
响应(您的代码未检查该响应)。
您的其余代码看起来不错,但我将其简化为:
import org.arl.fjage.*
import org.arl.unet.bb.*
import org.arl.unet.Services
platform = RealTimePlatform
modem.carrierFrequency = 24000
modem.basebandRate = 24000
modem.maxSignalLength = 48000
simulate 3.minutes, {
def n1 = node('1', address: 1, location: [0,0,0])
def n2 = node('2', address: 2, location: [0,0,0])
n1.startup = {
def bb = agentForService Services.BASEBAND
add new TickerBehavior(50000, {
float freq = 25000 // pick a frequency in the 12-36 kHz range
float duration = 1000e-3
int fd = 24000
int fc = 24000
int num = duration*fd
def sig = []
(0..num-1).each { t ->
double a = 2*Math.PI*(freq-fc)*t/fd
sig << Math.cos(a)
sig << Math.sin(a)
}
bb << new TxBasebandSignalReq(signal: sig)
println "sent"
})
}
n2.startup = {
def bb = agentForService Services.BASEBAND
add new TickerBehavior(50000, {
bb << new RecordBasebandSignalReq(recLen: 24000)
def rxNtf = receive(RxBasebandSignalNtf, 25000)
if(rxNtf) {
println "Received"
}
println "Tried"
})
}
}
这应该按预期工作!
但是,还有一些问题需要牢记:
您正在计时器上发送和记录。在模拟器上,这应该没问题,因为两个节点具有相同的时间来源并且没有传播延迟(您已将节点设置在同一位置)。但是,在真正的调制解调器上,传输时可能不会发生记录。
使用真正的调制解调器传输和接收信号效果很好。Unet 模拟器主要是一个网络模拟器,专注于模拟调制解调器的通信系统行为,但不一定是声学传播。虽然它支持该
BASEBAND
服务,但传输信号的通道物理特性并未由默认HalfDuplexModem
模型准确建模。因此,您对录音信号处理的里程可能会有所不同。这可以通过定义您自己的通道模型来解决,该模型使用适当的声学传播模型,但这是一项不平凡的任务。
推荐阅读
- angular - 如何同时使用实时数据更新多个小工具(所有条形图)
- drupal - Drupal 8 块和类型类
- python - Python:使类本身可调用
- linux - 项目错误:QT 中的未知模块:数据可视化
- reactjs - 使用 window.location.href 在反应中重定向页面时,Axios 无法正常工作
- javascript - 为什么从循环内部调用的回调处理程序没有从调用者那里获取适当的变量?
- javascript - 如何在 Netlify lambda 函数中从 Hugo 网站上的 Google Calendar API 获取请求
- sql - 使用 PASSWORD_VERIFY_FUNCTION 更改配置文件返回无效的函数名称
- reactjs - 使用 Material UI 进行主题嵌套
- java - Java 等价于 C++ Botan 函数调用