Engee 文档
Notebook

慢动作电视

在本例中,我们将研究基于慢扫描电视(SSTV)的图像传输协议,即慢扫描电视或小帧电视。这是一种独特而灵活的图像传输协议,非常适合窄带链路。SSTV 的可变性使传输可以根据特定条件进行调整,而且易于实施,因此深受无线电爱好者的欢迎。不过,由于传输速度较低,SSTV 不适合需要高速或高图像质量的应用。

本模型与实际应用中的任何通信标准无关,主要描述了我们可以在 Engee 中应用于此类系统的技术和方法。

SSTV 的一般原理是通过无线电信道等窄带通信信道传输静态图像。整个过程可分为几个步骤:图像编码、调制、传输、接收、解调和解码。

image_2.png

接下来,我们谈谈已实施的模型。

分析模型

以下逻辑在模型输入中实现:我们使用图像库将图像读入模型,并对图像进行归一化处理。

image_2.png

In [ ]:
using Images

path_img = "$(@__DIR__)/img.jpg"
inp_img = imrotate(Gray.(load(path_img)), deg2rad(-90))

S = size(inp_img)
println("Размер входного изображения: $(S))")
Размер входного изображения: (160, 160))

在本例中,图像的所有处理都将以灰色阴影表示。如果我们考虑朱莉娅视图,这意味着像素在 0 到 1 的范围内进行编码,其中 0 代表黑色,1 代表白色。

In [ ]:
Gray.([1,0])
Out[0]:
No description has been provided for this image

现在让我们进入下一个区块,即交织区块。交错是数据传输系统中用来提高抗错能力的一种技术。其基本思想是在传输之前改变数据的顺序,使相邻的比特或字符在数据流中分开。

image_2.png

该模块使用 Engee 函数实现。它的输入是交织组数和输入信号本身。

交织公式

index = mod((i - 1) * n, N) + div(i - 1, div(N, n)) + 1

位移公式

index = mod((i - 1), n) * div(N, n) + div(i - 1, n) + 1

这些公式可以确保索引不会超出数组范围,因为 mod 运算用于将索引限制在 N 范围内。

让我们比较一下公式本身。 1.在计算组内位置时存在差异。 在第一个公式中,组内位置的计算方法如下:mod((i-1),n)。 在第二个公式中,组内位置的计算公式如下:mod((i-1)×n,N)

2- 在计算组号时也存在差异。 在第一个公式中,组号的计算方法如下:div(i-1,n)。 在第二个公式中,组号是这样计算的:div(i-1,div(N,n))

也就是说,我们可以看到,它们是相互可逆的。接下来,让我们举一个简单的例子来说明我们所实现的交织法。

In [ ]:
L = 4
data_in = collect(1:L)
n = 2 # части массива
println("Исходные данные: ", data_in)

# Функция перемежения
N = length(data_in)
interleaved_data = similar(data_in)

for i in 1:N
    index = mod((i - 1) * n, N) + div(i - 1, div(N, n)) + 1
    interleaved_data[i] = data_in[index]
end

println("Перемеженные данные: ", interleaved_data)

# Функция деперемежения
N = length(interleaved_data)
deinterleaved_data = similar(interleaved_data)

for i in 1:N
    index = mod((i - 1), n) * div(N, n) + div(i - 1, n) + 1
    deinterleaved_data[i] = interleaved_data[index]
end

println("Деперемеженные данные: ", deinterleaved_data)
Исходные данные: [1, 2, 3, 4]
Перемеженные данные: [1, 3, 2, 4]
Деперемеженные данные: [1, 2, 3, 4]

我们可以看到,算法运行正常。现在我们来设置模型的组数。

In [ ]:
num = 400 # Количество групп
println("Количество значений в группе: $((S[1]*S[2])/num)")
Количество значений в группе: 64.0

我们使用的下一个模块是 XOR。这种操作是可逆的,允许我们实现一个简单的加扰器变体。

image_2.png

加扰器是一种软件或硬件设备,用于执行加扰,即在不改变传输速率的情况下对数字流进行可逆变换,以获得随机序列的特性。加扰后,输出序列中出现 "1 "和 "0 "的可能性相同。

接下来,让我们为加扰器设置比特掩码。

In [ ]:
bit_mask = 0b01010101 # max 8 bit
println("bit_mask: $bit_mask")
bit_mask: 85

接下来我们要考虑的是 16-FSK 调制和自动增益控制 (AGC)。

image.png

FSK 是一种调制方法,通过改变载波信号的频率来传输数字数据(比特)。每个比特值(0 或 1)或比特组对应一个特定的频率。16-FSK 是 FSK 的扩展,使用 16 个不同的频率同时传输 4 比特数据。 16-FSK 的比特和数字对应表: | 比特组合 | 数字 | | 比特组合 |----------------|---------------------| |[0, 0, 0, 0] | 1 | | |[0, 0, 0, 1] | 3 | |[0, 0, 1, 0] | 5 | |[0, 0, 1, 1] | 7 | |[0, 1, 0, 0] | 9 | |[0, 1, 0, 1] | 11 | |[0, 1, 1, 0] | 13 | |[0, 1, 1, 1] | 15 | |[1, 0, 0, 0] | -1 | |[1, 0, 0, 1] | -3 | |[1, 0, 1, 0] | -5 | |[1, 0, 1, 1] | -7 | |[1, 1, 0, 0] | -9 | |[1, 1, 0, 1] | -11 | |[1, 1, 1, 0] | -13 | |[1, 1, 1, 1] | -15 |

AGC 是一种系统,可自动调整接收端的信号增益,使输出信号电平保持恒定,而不受输入信号电平变化的影响。在我们的案例中,实现的逻辑是在信号增益之前计算相对于数据的输出功率,但您也可以很容易地用预设值取代这种方法。

image_4.png

根据下面的测试,我们可以清楚地得出结论,在 16-FSK 时,所需的信号功率为 85W。

In [ ]:
norm_img = ((channelview(inp_img))[:])
power_img = sum(norm_img.^2) / length(norm_img)
println("Мощность входного сигнала: ", power_img, " Вт")

values = [1:2:15; -1:-2:-15] 
v = [values[rand(1:length(values))] for _ in 1:length(norm_img)]
power_desired = sum(v .^ 2) / length(v)
println("Желаемая мощность: ", power_desired, " Вт")

K = sqrt(power_desired / power_img) # Используем квадратный корень, так как мощность пропорциональна квадрату амплитуды 
println("Коэффициент усиления: ", K)

amplified = norm_img .* K  # Усиленный сигнал

power_out = sum(amplified .^ 2) / length(amplified) 
println("Мощность выходного сигнала: ", round(power_out, digits=2), " Вт")
Мощность входного сигнала: 0.3573653492647059 Вт
Желаемая мощность: 84.9459375 Вт
Коэффициент усиления: 15.417540102273989
Мощность выходного сигнала: 84.97 Вт

接下来我们要了解的模块是 FM 调制器基带FM 解调器基带。这是一种将基带信号转换为频率调制(FM)信号的调制器。

调频无线电广播使用两个关键参数。

1.载波频率是调制信号的基频,用于传输信息。在调频广播中,它介于 87.5 MHz 和 108 MHz 之间。

2.偏差频率是信号传输时与载波频率的最大偏差。对于标准调频广播,最大允许偏差为 ±75 kHz。

因此,如果载波频率为 100 MHz,则传输信号的实际频率将在 99.925 和 100.075 MHz 之间变化。

In [ ]:
fs = 100e3 # Hz
println("Несущая частота: $fs Гц")

deviation_fs = fs * 0.05 # 5% от fs
println("Частота девиации: $deviation_fs Гц")
Несущая частота: 100000.0 Гц
Частота девиации: 5000.0 Гц

我们要考虑的最后一个模块是通信信道模块。它使用信噪比(SNR)指标,即信噪比来叠加噪声。该指标显示有用信号比噪声强多少。 image.png

信噪比越高,信号质量越高,因为噪声对数据的影响越小。相反,信噪比越低,信号质量越低,因为噪声开始主导有用信号。

例如

  1. 如果 SNR = 20 dB,这意味着信号比噪声强 100 倍(线性范围);
  2. 如果 SNR = 0 dB,表示信号和噪声的功率相等;
  3. 如果 SNR = -10 dB,表示噪声比信号强 10 倍。
In [ ]:
snr = 10;
println("SNR: $snr дБ")
snr_linear = 10^(snr / 10)
signal_power = 1
noise_power = 1 / snr_linear
println("Мощность шума: $noise_power")
SNR: 10 дБ
Мощность шума: 0.1

运行模型并分析结果

设置模拟参数并运行模型。

In [ ]:
st = 1/fs*S[1]*S[2] # Sample time
println("Время одного отсчёта: $st")
step = st/S[1]/S[2]
println("Шаг решателя: $step")
time_stop = st*2.1
println("Шаг моделирования: $st")
Время одного отсчёта: 0.256
Шаг решателя: 1.0e-5
Шаг моделирования: 0.256
In [ ]:
name_model = "SSTV"
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(1)
Building...
Progress 0%
Progress 5%
Progress 11%
Progress 16%
Progress 22%
Progress 28%
Progress 34%
Progress 39%
Progress 45%
Progress 50%
Progress 60%
Progress 67%
Progress 72%
Progress 81%
Progress 87%
Progress 93%
Progress 99%
Progress 100%
Progress 100%

将模型结果可视化,并对结果进行总结。

In [ ]:
println("SNR: $snr дБ")
println()
ber = ((collect(BER)).value)[end] 
println("Всего бит: $(Int(ber[3]))")
println("Кол-во ошибок: $(Int(ber[2]))")
println("BER: $(round(ber[1], digits=2))")

inp = plot(framestyle=:none, grid=false, title = "Вход")
heatmap!( 1:S[2], 1:S[1], permutedims(inp_img, (2, 1)), colorbar=false)

sim_img = imrotate(colorview(Gray, ((collect(img_FM))[3,:].value)), deg2rad(-90))
sim = plot(framestyle=:none, grid=false, title = "Выход")
heatmap!( 1:size(sim_img, 2), 1:size(sim_img, 1), permutedims(sim_img, (2, 1)), colorbar=false)

sim_error = (collect(error_sim)).value 
Average_error = round(sum(abs.(sim_error))/length(sim_error)*100, digits=2)
err = plot(sim_error, title = "Cредняя ошибка равна $Average_error % ")

plot(plot(inp, sim), err, layout = grid(2, 1, heights=[0.7, 0.3]), legend=false) 
SNR: 10 дБ

Всего бит: 430088
Кол-во ошибок: 39938
BER: 0.09
Out[0]:

从模拟结果可以看出,我们在输出端获得了良好的误码率值。如果我们对交织和加扰进行更详细的调整,就能获得更好的图像质量。为此,我们提供了第二个脚本 SSTV_test。其中没有多余的说明,只有本项目的代码。

输出

在本示例中,我们探讨了在 Engee 中模拟基于慢动作电视的图像传输协议的可能性,并探索了在 Engee 中运行此类项目的许多可用工具。从我们的示例中可以看出,Engee 拥有这些模型所需的所有功能和工具,而且它们都能正常运行。