慢扫描电视
在这个例子中,我们将考虑基于慢扫描电视(Sstv)的图像传输协议,即慢扫描电视或低帧电视。 它是一种独特而灵活的图像传输协议,非常适合窄带通信信道。 SSTV的可变性允许您根据特定条件调整传输,并且其实施的简单性使其在无线电业余爱好者中很受欢迎。 然而,由于低转印速率,SSTV不适用于要求高速或高图像质量的任务。
该模型与实践中实施的任何通信标准无关,主要描述了我们可以在Engee中应用于此类系统的技术和方法。
SSTV的一般原理是在诸如无线电信道的窄带通信信道上传输静态图像。 该过程可以分为几个阶段:图像编码、调制、发送、接收、解调和解码。
接下来,让我们继续实现模型。
模型分析
以下逻辑在模型的输入端实现:我们使用图像库将图像读入模型并对图像进行归一化。
using Images
path_img = "$(@__DIR__)/img.jpg"
inp_img = imrotate(Gray.(load(path_img)), deg2rad(-90))
S = size(inp_img)
println("Размер входного изображения: $(S))")
在这个例子中,图像的所有工作都将以表示的灰色阴影的格式进行。 如果我们考虑Julia表示,这意味着像素在0到1的范围内编码,其中0是黑色,1是白色。
Gray.([1,0])
现在让我们进入下一个块,交错块。 交织是在数据传输系统中用于增加差错容限的技术。 基本思想是在传输之前改变数据的顺序,然后相邻的位或字符将在流中分离。
该块使用Engee函数实现。 在输入端,它具有交织组的数量和输入信号本身。
交织公式:
*索引=mod((i-1)n,N)+div(i-1,div(N,n))+1
去人性化公式:
*索引=mod((i-1),n)div(N,n)+div(i-1,n)+1
这些公式确保索引不超过数组的限制,因为mod操作用于将索引限制在N内。
让我们比较公式本身。
-
组内的位置的计算存在差异。
在第一个公式中,组内的位置计算如下:mod((i-1),n)。
在第二个公式中,组内的位置计算如下:mod((i−1)×n,N)。 -
组号的计算也存在差异。
在第一个公式中,组号计算如下:div(i-1,n)。
在第二个公式中,组号是这样计算的:div(i-1,div(N,n))。
也就是说,正如我们所看到的,它们是相互可逆的。 接下来,让我们看一个我们实现的交织的简单示例。
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)
正如我们所看到的,算法工作正常。 现在让我们设置模型的组数。
num = 400 # Количество групп
println("Количество значений в группе: $((S[1]*S[2])/num)")
我们使用的下一个块是XOR。 此操作是可逆的,并允许您实现加扰器的简单版本。
加扰器(来自英文scramble-to encrypt,to mix)是执行加扰的软件或硬件设备,即在不改变传输速率的情况下对数字流进行可逆变换,以获得随机序列的属性。 加扰后,输出序列中出现"1"和"0"的可能性相等。
接下来,我们将为扰频器设置位掩码。
bit_mask = 0b01010101 # max 8 bit
println("bit_mask: $bit_mask")
我们将考虑的下一个模块是16—FSK调制和自动增益控制(AGC)的捆绑。
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是一种无论输入信号电平的变化如何自动调整接收侧的信号增益电平以保持恒定的输出信号电平的系统。 在我们的例子中,我们已经实现了在信号放大之前计算相对于数据的输出功率的逻辑,但是您可以轻松地将这种方法替换为预设值。
根据下面的测试,我们可以清楚地得出结论,在16-FSK下,所需的信号功率为85瓦。
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), " Вт")
我们将考虑的以下块是FM调制器基带和FM解调器基带。 这是一种将基础信号转换为频率调制(FM)信号的调制。
FM无线电广播中使用了两个关键参数。
-
载波频率是信号的主要频率,它被调制以传输信息。 在FM广播范围内,它介于87.5MHz和108MHz之间。
-
偏差的频率为信号传输过程中与载波频率的最大频率偏差。 对于标准FM广播,最大允许偏差为±75kHz。
因此,如果载波频率为100MHz,则发送信号的实际频率范围为99.925至100.075MHz。
fs = 100e3 # Hz
println("Несущая частота: $fs Гц")
deviation_fs = fs * 0.05 # 5% от fs
println("Частота девиации: $deviation_fs Гц")
我们将考虑的最后一个块是通信信道块。 为了应用噪声,它使用信噪比(SNR)度量,即信噪比。 该指标显示有用信号比噪声强多少。

SNR越高,信号质量越高,因为噪声对数据的影响越小。 相反,SNR越低,信号质量越低,因为噪声开始支配有用信号。
例如:
- 如果SNR=20dB,则意味着信号比噪声强100倍(在线性尺度上);
- 如果SNR=0dB,则表示信号和噪声功率相等;
- 如果SNR=-10dB,则表示噪声比信号强10倍。
snr = 10;
println("SNR: $snr дБ")
snr_linear = 10^(snr / 10)
signal_power = 1
noise_power = 1 / snr_linear
println("Мощность шума: $noise_power")
启动模型并分析结果
让我们设置仿真参数并运行模型。
st = 1/fs*S[1]*S[2] # Sample time
println("Время одного отсчёта: $st")
solver_step = st/S[1]/S[2]
println("Шаг решателя: $solver_step")
time_stop = st*2.1
println("Шаг моделирования: $st")
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)
让我们可视化模型的结果并总结结果。
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)
从仿真结果可以看出,我们在输出端得到了良好的BER值。 如果我们仔细观察交错和加扰设置,我们可以获得更好的图像质量。 出于这些目的,您将获得第二个脚本SSTV_test。 里面没有多余的描述,只给出了这个项目的代码。
结论
在这个例子中,我们研究了Engee中基于慢扫描电视的图像传输协议的建模功能,并探索了许多允许我们在Engee中执行此类项目的工具。 正如您从我们的示例中看到的,Engee具有这些模型的所有必要功能和工具,并且它们可以正常工作。