我正在尝试一个项目,该项目涉及在水下通信中实现声传播损耗模型(基于某项研究论文)。我们正在尝试在unetstack
中进行模拟。最终目标是创建一个实现所有损耗模型的渠道模型类。
但是,现在我们开始尝试从一个节点向另一个节点发送基带信号,然后尝试捕获接收器节点上的频率并计算该给定频率上的损耗模型。 (损耗模型是信号频率值的函数)。我试图遵循一些文档和一些博客文章,但是我无法发送和接收信号。
作为参考,我已经参考了以下文章: 1.)svc-12-baseband 2.)basic-modem-operations-using-unetstack
这是我根据this来根据不同的损失模型计算损失的研究论文。
我试图编写一个用于模拟的Groovy文件,但是它似乎不起作用。如果有人可以看看并让我知道我所犯的错误,那将是真正的帮助。像这样的水下信号处理领域,我们是一个陌生的新话题,这是我们在模拟器上实现它的首次尝试。我们正在使用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)
执行之前先执行。
答案 0 :(得分:2)
您拥有用于信号的发送(TxBasebandSignalReq
和接收(RecordBasebandSignalReq
)的基本代码。
这在调制解调器上应该可以很好地工作,除了您的信号生成可能有缺陷的原因有两个:
您正在尝试使用24 kHz的载波频率和24 kHz的带宽以基带表示形式生成5 kHz的信号。该信号将被混叠,因为该基带表示只能表示24±12 kHz,即12-36 kHz的信号。如果您需要发送5 kHz信号,则需要使调制解调器以更低的载波频率运行(在模拟器中很容易,但是实际上您需要检查调制解调器的规格)。
您正在将sin
和cos
的输出转换为int
。这可能不是您要执行的操作,因为signal
是float
的数组,缩放范围为-1和1。因此建议您放下(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
模型无法准确地模拟传输信号的信道物理特性。因此,您在信号处理录音方面的努力可能会有所不同。可以通过定义自己的通道模型来解决此问题,该模型使用适当的声学传播模型,但这不是一件容易的事。