Engee 文档
Notebook

DMR中的pdu

在诸如DMR(数字移动无线电)的现代专业无线电通信系统中,基站(BS)和用户无线电台(RS)之间的交互是严格监管和高度组织的过程。 这对于确保单个信道内多个用户的可靠、抗噪声和高效通信是必要的。

BS在其复盖区域(sote)中充当协调器和管理中心。 它不断传输业务信息,同步网络中的所有Pc,管理信道接入并提供通信服务。 反过来,无线电台(RS)对于其任何操作(开始呼叫,传输语音或数据,在网络上注册)必须通过请求资源并遵循其指示与BS交互。

这种交互是通过交换严格对应于DMR帧格式的特殊数据分组来进行的。 组织这种对话的关键结构之一是数据槽,其主要元素是PDU(协议数据单元)

时隙PDU是设计用于传输信号信息或用户数据的时隙的信息部分。 其结构包括几个关键信息元素,这些关键信息元素允许BS和RS正确地解释所传输的信息。 告警消息的时隙PDU的组成可由下表表示:

/信息元素(IE)/长度(位)/注释|
|:---|:---|:---|
/颜色代码(CC)|4|务区(小区)的唯一标识符。 允许无线电台将其基站与在相同频率上操作的其他基站区分开来(例如,在邻近小区中)。 PC忽略CC不正确的消息。|
/数据类型|4|定义传送到PDU的信息的类型和目的。 例如,该消息是连接请求、用户数据分组还是服务命令。|
/插槽类型奇偶校验|12|服务字段,这是FEC Golley代码(20.8)。 它用于控制和纠正前两个字段(CC和数据类型)中的错误。 它允许接收方检测和纠正传输过程中可能发生的错误,确保接收关键信号信息的高可靠性。|

以身作则的操作原理:

  1. 呼叫发起(PC->BS):

    *无线电台(PC)要建立连接。 它形成一个插槽PDU,它安装在其中:
    **颜色代码(CC)根据目标基站代码。
    数据类型为连接请求对应的值(例如, [0,0,1,0]).
    *对这8位(4+4)添加12位
    时隙类型奇偶校验
    (Gaulley FEC),形成受保护的20位块。
    *此分组被传送到BS。

  2. 请求处理(BS):

    *基站接收信号。 首先,它使用Gaulle代码解码20位块,以检查和纠正CC和数据类型字段中的错误。
    *BS检查颜色代码。 如果它与她自己的匹配,她继续处理。
    *BS分析数据类型。 意义 [0,0,1,0] 向她表明这是一个连接请求。
    *接下来,BS根据信道的占用情况,要么向此PC分配资源,并向其发送具有不同数据类型的响应确认PDU,要么拒绝该请求。

  3. 数据传输:

    在建立用于语音或用户数据传输的连接之后,PC和BS将在插槽PDU中使用为此目的保留的数据类型*(例如, [0,0,0,1]).

因此,时隙PDU的内容,即由Gaulley码颜色码数据类型保护的字段的组合,是确保DMR网络中基站和无线电台之间的任何通信会话的开始、维持和终止的根本机制。

与之前关于DMR主题的所有演示一样,我们继续使用自定义函数库。:

In [ ]:
include("/user/start/examples/communication/dmr_v3/dmr_lib.jl")
Out[0]:
decode_slot_pdu (generic function with 1 method)

让我们看看有什么新的。

1. 功能 typegen (扩展版)
它已被修改,现在接受两个输入参数:

  • CC (颜色代码)是表示系统的颜色代码的4位向量。
  • data_type -定义正在传输的数据类型的4位向量(例如, [0,0,1,0] 对于连接信号或 [0,0,0,1] 为用户数据)。

该函数将这两个向量组合成一个8位块,并使用Gaulle码(20.8)对其应用抗噪声编码。 此代码不仅可以检测,还可以纠正传输过程中发生的错误。 该功能的结果是一个20位安全块,准备好广播。

2. 功能 encode_slot_pdu
此函数是一个高级包装器 typegen. 它采用相同的参数(颜色代码和数据类型),调用 typegen 为了生成20位块,它可视地将生成的位序列输出到控制台。 其主要任务是简化编码过程并提供结果的可视化控制。

3. 功能 decode_slot_pdu
执行反向操作。 它将一个20位向量作为输入(由SLOT PDU接收),并将其分成其原始分量:

-前4位被解释为颜色代码(CC_decoded).
-接下来的4位作为数据类型(data_type_decoded).

该函数不使用Gaulley代码检查错误,而是简单地从时隙结构中的相应位置提取信息位。

In [ ]:
function typegen(CC::Vector{Int}, data_type::Vector{Int})
    data = vcat(CC, data_type)
    
    ENCODE_2087 = [
        0x0000, 0xB08E, 0xE093, 0x501D, 0x70A9, 0xC027, 0x903A, 0x20B4, 0x60DC, 0xD052, 0x804F, 0x30C1, 0x1075, 0xA0FB, 0xF0E6,
        0x4068, 0x7036, 0xC0B8, 0x90A5, 0x202B, 0x009F, 0xB011, 0xE00C, 0x5082, 0x10EA, 0xA064, 0xF079, 0x40F7, 0x6043, 0xD0CD,
        0x80D0, 0x305E, 0xD06C, 0x60E2, 0x30FF, 0x8071, 0xA0C5, 0x104B, 0x4056, 0xF0D8, 0xB0B0, 0x003E, 0x5023, 0xE0AD, 0xC019,
        0x7097, 0x208A, 0x9004, 0xA05A, 0x10D4, 0x40C9, 0xF047, 0xD0F3, 0x607D, 0x3060, 0x80EE, 0xC086, 0x7008, 0x2015, 0x909B,
        0xB02F, 0x00A1, 0x50BC, 0xE032, 0x90D9, 0x2057, 0x704A, 0xC0C4, 0xE070, 0x50FE, 0x00E3, 0xB06D, 0xF005, 0x408B, 0x1096,
        0xA018, 0x80AC, 0x3022, 0x603F, 0xD0B1, 0xE0EF, 0x5061, 0x007C, 0xB0F2, 0x9046, 0x20C8, 0x70D5, 0xC05B, 0x8033, 0x30BD,
        0x60A0, 0xD02E, 0xF09A, 0x4014, 0x1009, 0xA087, 0x40B5, 0xF03B, 0xA026, 0x10A8, 0x301C, 0x8092, 0xD08F, 0x6001, 0x2069,
        0x90E7, 0xC0FA, 0x7074, 0x50C0, 0xE04E, 0xB053, 0x00DD, 0x3083, 0x800D, 0xD010, 0x609E, 0x402A, 0xF0A4, 0xA0B9, 0x1037,
        0x505F, 0xE0D1, 0xB0CC, 0x0042, 0x20F6, 0x9078, 0xC065, 0x70EB, 0xA03D, 0x10B3, 0x40AE, 0xF020, 0xD094, 0x601A, 0x3007,
        0x8089, 0xC0E1, 0x706F, 0x2072, 0x90FC, 0xB048, 0x00C6, 0x50DB, 0xE055, 0xD00B, 0x6085, 0x3098, 0x8016, 0xA0A2, 0x102C,
        0x4031, 0xF0BF, 0xB0D7, 0x0059, 0x5044, 0xE0CA, 0xC07E, 0x70F0, 0x20ED, 0x9063, 0x7051, 0xC0DF, 0x90C2, 0x204C, 0x00F8,
        0xB076, 0xE06B, 0x50E5, 0x108D, 0xA003, 0xF01E, 0x4090, 0x6024, 0xD0AA, 0x80B7, 0x3039, 0x0067, 0xB0E9, 0xE0F4, 0x507A,
        0x70CE, 0xC040, 0x905D, 0x20D3, 0x60BB, 0xD035, 0x8028, 0x30A6, 0x1012, 0xA09C, 0xF081, 0x400F, 0x30E4, 0x806A, 0xD077,
        0x60F9, 0x404D, 0xF0C3, 0xA0DE, 0x1050, 0x5038, 0xE0B6, 0xB0AB, 0x0025, 0x2091, 0x901F, 0xC002, 0x708C, 0x40D2, 0xF05C,
        0xA041, 0x10CF, 0x307B, 0x80F5, 0xD0E8, 0x6066, 0x200E, 0x9080, 0xC09D, 0x7013, 0x50A7, 0xE029, 0xB034, 0x00BA, 0xE088,
        0x5006, 0x001B, 0xB095, 0x9021, 0x20AF, 0x70B2, 0xC03C, 0x8054, 0x30DA, 0x60C7, 0xD049, 0xF0FD, 0x4073, 0x106E, 0xA0E0,
        0x90BE, 0x2030, 0x702D, 0xC0A3, 0xE017, 0x5099, 0x0084, 0xB00A, 0xF062, 0x40EC, 0x10F1, 0xA07F, 0x80CB, 0x3045, 0x6058, 0xD0D6
    ]
    byte = bi2de(data)
    cksum = ENCODE_2087[byte+1]
    type_val = (byte << 12) | ((cksum & 0xFF) << 4) | (cksum >> 8)
    type20bit = de2bi(type_val, 20)
    return type20bit
end

function encode_slot_pdu(CC::Vector{Int}, data_type::Vector{Int})
    slot_pdu = typegen(CC, data_type)
    println("Полный SLOT PDU: $(join(slot_pdu))")
    return slot_pdu
end

function decode_slot_pdu(slot_pdu::Vector{Int})
    CC_decoded = slot_pdu[1:4]
    data_type_decoded = slot_pdu[5:8]
    return CC_decoded, data_type_decoded
end
Out[0]:
decode_slot_pdu (generic function with 1 method)

让我们对我们的新功能做一个简单的测试,以确保它们正常工作。

测试的逻辑:

  1. 我们设置初始数据:我们确定颜色代码(CC)和数据类型的测试值。 在这种情况下,两个参数都设置为 [0, 0, 0, 1].
  2. 我们对数据进行编码:函数 encode_slot_pdu 接受我们的初始数据。 里面,它调用一个函数 typegen 其中:
    *将CC和数据类型组合成8位序列。
    *对其应用复杂的抗噪声编码算法(Gaullei代码)。
    *这个块显示在屏幕上,我们可以看到我们原来的8位是如何变成20的。
  3. 解码数据:我们通过将接收到的20位块传输到函数来模拟接收数据的过程 decode_slot_pdu. 它的任务是从这个受保护的结构中提取初始信息位,即前4位(CC)和后4位(数据类型)。
  4. 比较结果。
In [ ]:
CC = [0, 0, 0, 1]
data_type = [0, 0, 0, 1]

println("Исходные данные:")
println("Цветовой код: $(join(CC))")
println("Тип данных: $(join(data_type))")
encoded_pdu = encode_slot_pdu(CC, data_type)
decoded_CC, decoded_data_type = decode_slot_pdu(encoded_pdu)

println("\nРезультаты:")
println("Декодированный CC: $(join(decoded_CC))")
println("Декодированный тип данных: $(join(decoded_data_type))")

if (CC == decoded_CC) && (data_type == decoded_data_type)
    println("✅ УСПЕХ: Все данные совпали!")
else
    println("❌ ОШИБКА: Данные не совпали!")
end
Исходные данные:
Цветовой код: 0001
Тип данных: 0001
Полный SLOT PDU: 00010001101111000000

Результаты:
Декодированный CC: 0001
Декодированный тип данных: 0001
✅ УСПЕХ: Все данные совпали!

进行的测试和随后的建模服务于一个重要但中间的目的。 正如我们从这个测试中可以看到的,并且从进一步的工作中可以理解到,当前阶段的关键任务不是对DMR协议及其所有细微差别进行详细和全面的建模。

我们的主要目标是创建和验证基本功能的正确性,这将作为这一系列演示开发的可靠基础。 我们抽象出不必要的复杂性,以便:

  1. 专注于关键机制(编码,插槽结构),而不会超载细节。
  2. 构建一组经过验证和工作的功能,可以在以下部分中自信地使用和扩展。
  3. 这种模块化方法允许您在后续演示中逐步添加新的功能层(例如,语音编解码器,各种类型的帧,多址机制),而无需重做基本实现。

因此,目前的实施是为将来扩展和深化到数字无线电通信主题而准备的概念框架。

实现DMR系统模型

image.png

让我们继续描述DMR标准中基站(BS)和无线电台(RS)之间交互的实现模型。 该模型基于反馈原理,包括几个关键块,确保连接建立,数据传输和系统状态管理。

模型的中央控制元素是Detect_mode_RS块。 它实现了控制无线电台状态的有限状态机。 该块监视两个全局状态: :disconnected (未连接)和 :connected (连接)。

工作逻辑如下:

-如果PC处于 :disconnected,它通过返回值来启动连接 2,其对应于连接请求。
-能够 :connected 块对输入数据进行分析。 如果数据可用(any(in1 .!= 0)故障计数器(fail_counter)正在重置。 如果没有数据,则计数器递增。
-当失败计数器达到阈值(例如,3个连续失败帧)时,无线电台返回到状态 :disconnected 并启动重新连接。
-如果数据可用且连接稳定,则块返回 1 允许数据传输或 0 以传送空帧。

该单元通过模拟真实无线电台在干扰或信号丢失条件下的行为来提供基本的通信稳定性。

接下来是文本数据供应单元(SMS),该单元被激活,前提是操作模式不是官方的(不是 0 而不是 2)并且下一帧不是业务控制帧(LC)。 出于测试目的,文本块的大小设置为27字节。 重要的是要注意,这些数据中的一些稍后在形成时隙PDU时将被复盖。

Gen_Pkg_RS块负责从无线电台生成传出数据包。 他的工作包括几个阶段:

  1. **LC报头生成(链路控制):**基于输入参数(例如AFLCO、BFID、adrp的发送者的地址和AdrI的接收者的地址),形成控制信息的结构。 然后向其中添加CRC以进行错误控制。
  2. **抗噪声编码:**LC数据经过几个阶段的编码,包括校验和计算(CS5bit)和矩阵折边编码(HemR,HemC)的应用。
  3. **插槽PDU形成:**使用功能 typegen 产生20位时隙类型字段,该字段包括颜色代码(CC)和数据类型。 此字段受Golley代码保护。
  4. **将数据打包到一个框架中:**取决于操作模式(Mode),或者一个连接请求被放置在框架中([0,0,1,0]),或用户数据([0,0,0,1]). 数据被打包成包括同步序列和信息位的DMR帧结构。

该单元还控制传输帧(LC和数据)的交织,确保与基站的正确交互。

接下来是Pkg_BS块,它模拟基站的简化行为。 他的主要任务是响应广播电台的请求。 该模块提供了模型运行所需的最小反馈。

-接收连接请求时([0,0,1,0] 它返回一个帧,其中插槽类型指示连接确认。
-接收数据帧时([0,0,0,1] 它返回一个帧,确认数据接收。
-在所有其他情况下,返回空帧。

Pkg_BS块并行,Data_selector块操作,其负责从接收的帧(216位)中提取有用数据,包括时隙PDU。

In [ ]:
# Подключение вспомогательной функции запуска модели.
function run_model( name_model)
    Path = (@__DIR__) * "/" * name_model * ".engee"
    if name_model in [m.name for m in engee.get_all_models()] # Проверка условия загрузки модели в ядро
        model = engee.open( name_model ) # Открыть модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
    else
        model = engee.load( Path, force=true ) # Загрузить модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
        engee.close( name_model, force=true ); # Закрыть модель
    end
    sleep(0.1)
    return model_output
end
run_model("test_BS_RS") # Запуск модели.
Building...
Progress 0%
Progress 5%
Progress 10%
Progress 15%
Progress 20%
Progress 25%
Progress 30%
Progress 35%
Progress 41%
Progress 46%
Progress 51%
Progress 56%
Progress 61%
Progress 66%
Progress 72%
Progress 77%
Progress 82%
Progress 87%
Progress 92%
Progress 98%
Progress 100%
Progress 100%
Out[0]:
SimulationResult(
    "Преобразование битов в целые числа-2.1" => WorkspaceArray{Vector{UInt32}}("test_BS_RS/Преобразование битов в целые числа-2.1")
,
    "Detect_mode_RS.1" => WorkspaceArray{UInt8}("test_BS_RS/Detect_mode_RS.1")
,
    "Pkg_BS.1" => WorkspaceArray{UInt8}("test_BS_RS/Pkg_BS.1")

)
In [ ]:
Mode_RS = collect(simout["test_BS_RS/Detect_mode_RS.1"]).value
Mode_BS = collect(simout["test_BS_RS/Pkg_BS.1"]).value
plot(Mode_RS, label="Mode RS", seriestype=:steppost)
plot!(Mode_BS, label="Mode BS", seriestype=:steppost)
Out[0]:

正如我们所看到的,系统正常工作,PC正在请求连接,BS正在响应,PC正在发送数据,BS正在响应。

In [ ]:
Data_out = reduce(vcat, (collect(simout["test_BS_RS/Преобразование битов в целые числа-2.1"]).value))
plot(Data_out, label="Data", seriestype=:steppost)
Out[0]:

分析所呈现的数据图,我们可以得出结论,除了我们从以前的演示中熟悉的文本符号之外,还有逻辑信道分组(LC)数据,并且图上的峰值对应于SLOT PDU数据。

结论

该模型实现了基本的DMR交互周期,包括连接建立、数据传输和错误处理。 重要的是要强调,这一发展的目的不是对DMR协议及其所有特定功能的详细和完整建模,而是创建概念框架和关键操作原则的演示。 这个基础允许进一步扩展功能。