Engee 文档
Notebook

调制方案分析

这项研究提出了一个系统的方法来实现和验证在Engee环境中接收和传输路径的测试模型。 这项工作包括对调制方案的各个方面进行顺序分析,从基本特性开始,以频谱特性结束。

辅助模型管理功能


为了确保模型的正确操作,实现了该功能 run_model,它自动化加载和执行模型的过程。 该函数执行以下操作:

*生成带有扩展名的模型文件的完整路径 .engee

*检查系统核心中模型的当前状态

*如有必要,可从文件下载模型,或打开已上载的模型。

*运行模型并输出有关过程的详细信息

*确保正确完成与模型的工作

*返回执行结果

无论系统的初始状态如何,这种方法都能保证稳定运行。

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
Out[0]:
run_model (generic function with 1 method)

误码概率分析

对BPSK,QPSK,8-PSK和16-QAM四种调制方案的特性进行了比较研究。 研究方法包括:

  1. 仿真在信噪比(Eb/No)范围内从0到10dB,增量为2dB

  2. 使用每种调制的数学模型进行BER特性的理论计算

  3. 结果可视化以对数标度进行可视化比较

使用了一个包含所有调制相同信号处理路径的基本模型,确保了比较分析的正确性,模型本身如下所示。

image.png
In [ ]:
EbNoArr = collect(0:2:10);
Eb_No = 0;
ber_bpsk = zeros(length(EbNoArr));
ber_8psk = zeros(length(EbNoArr));
ber_qpsk = zeros(length(EbNoArr));
ber_16qam = zeros(length(EbNoArr));

for i in 1:length(EbNoArr)
    Eb_No = EbNoArr[i]

    run_model("modulations_1");

    ber_bpsk[i] = collect(BER_BPSK).value[end][1]
    ber_8psk[i] = collect(BER_8PSK).value[end][1]
    ber_qpsk[i] = collect(BER_QPSK).value[end][1]
    ber_16qam[i] = collect(BER_16QAM).value[end][1]
end
Building...
Progress 0%
Progress 5%
Progress 16%
Progress 27%
Progress 39%
Progress 49%
Progress 63%
Progress 74%
Progress 83%
Progress 94%
Progress 100%
Progress 100%
Building...
Progress 0%
Progress 7%
Progress 20%
Progress 31%
Progress 44%
Progress 59%
Progress 71%
Progress 82%
Progress 94%
Progress 100%
Progress 100%
Building...
Progress 0%
Progress 7%
Progress 26%
Progress 41%
Progress 61%
Progress 74%
Progress 84%
Progress 93%
Progress 100%
Progress 100%
Building...
Progress 0%
Progress 5%
Progress 15%
Progress 24%
Progress 31%
Progress 39%
Progress 59%
Progress 69%
Progress 80%
Progress 90%
Progress 100%
Progress 100%
Building...
Progress 0%
Progress 6%
Progress 25%
Progress 43%
Progress 59%
Progress 85%
Progress 100%
Progress 100%
Building...
Progress 0%
Progress 6%
Progress 21%
Progress 33%
Progress 44%
Progress 55%
Progress 71%
Progress 84%
Progress 94%
Progress 100%
Progress 100%
In [ ]:
using SpecialFunctions
colors = Dict(:BPSK => :blue, :QPSK => :red, :PSK8 => :green, :QAM16 => :purple)
function theoretical_ber(EbNo_dB, mod_type)
    EbNo = 10 .^ (EbNo_dB ./ 10)
    if mod_type == :BPSK
        0.5 .* erfc.(sqrt.(EbNo))
    elseif mod_type == :QPSK
        0.5 .* erfc.(sqrt.(EbNo)) 
    elseif mod_type == :PSK8
        (2/3) .* erfc.(sqrt.(3*EbNo) .* sin(π/8))
    elseif mod_type == :QAM16
        (3/8) .* erfc.(sqrt.(2 .* EbNo ./ 5))                    
    end
end
EbNoArr_dense = range(minimum(EbNoArr), maximum(EbNoArr), length=1000)
plot(yscale=:log10, ylims=(1e-6, 1), grid=true, xlabel="Eb/No (dB)", ylabel="BER", title="理论和模拟BER")

for mod in [(:BPSK, ber_bpsk), (:QPSK, ber_qpsk), (:PSK8, ber_8psk), (:QAM16, ber_16qam)]
    mod_type, ber_sim = mod
    c = colors[mod_type]
    plot!(EbNoArr_dense, theoretical_ber(EbNoArr_dense, mod_type), line=:solid, color=c, label="$mod_type(理论)")
    scatter!(EbNoArr, ber_sim, marker=:circle, color=c, label="$mod_type(simul.)", markersize=5)
end
plot!(legend=:bottom)
Out[0]:

功率特性和信号星座分析

通过在接收和发送路径中使用具有奈奎斯特滤波器的模型来扩展该研究。 进行了分析:

*信号强度滤波前后评估滤波器的效果

*信号星座解调信号用于解调质量的可视化评估

构造具有参考点的所有考虑的调制方案的星座图。
\模型本身如下所示。

image.png
In [ ]:
run_model("modulations_2")
Building...
Progress 0%
Progress 5%
Progress 11%
Progress 16%
Progress 22%
Progress 27%
Progress 32%
Progress 71%
Progress 76%
Progress 83%
Progress 88%
Progress 93%
Progress 99%
Progress 100%
Progress 100%
Out[0]:
SimulationResult(
    run_id => 17,
    "16qam_demod" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/16qam_demod")
,
    "Find Delay.delay" => WorkspaceArray{Float64}("modulations_2/Find Delay.delay")
,
    "awgn_bpsk" => WorkspaceArray{Matrix{ComplexF64}}("modulations_2/awgn_bpsk")
,
    "ber_qpsk" => WorkspaceArray{Vector{Float64}}("modulations_2/ber_qpsk")
,
    "16qam" => WorkspaceArray{ComplexF64}("modulations_2/16qam")
,
    "qpsk_demod" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/qpsk_demod")
,
    "8psk_demod" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/8psk_demod")
,
    "8psk" => WorkspaceArray{ComplexF64}("modulations_2/8psk")
,
    "bpsk_demod" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/bpsk_demod")
,
    "qpsk" => WorkspaceArray{ComplexF64}("modulations_2/qpsk")
,
    "ber_bpsk" => WorkspaceArray{Float64}("modulations_2/ber_bpsk")
,
    "ber_8psk" => WorkspaceArray{Vector{Float64}}("modulations_2/ber_8psk")
,
    "awgn_16qam" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/awgn_16qam")
,
    "awgn_qpsk" => WorkspaceArray{Matrix{ComplexF64}}("modulations_2/awgn_qpsk")
,
    "16qam_f" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/16qam_f")
,
    "8psk_f" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/8psk_f")
,
    "bpsk" => WorkspaceArray{ComplexF64}("modulations_2/bpsk")
,
    "qpsk_f" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/qpsk_f")
,
    "bpsk_f" => WorkspaceArray{Vector{ComplexF64}}("modulations_2/bpsk_f")
,
    "awgn_8psk" => WorkspaceArray{Matrix{ComplexF64}}("modulations_2/awgn_8psk")
,
    "ber_16qam" => WorkspaceArray{Vector{Float64}}("modulations_2/ber_16qam")

)
In [ ]:
using Statistics 
println("过滤器之前:")
bpsk = collect(simout["modulations_2/bpsk"]).value
power_bpsk = mean(abs2.(x[1]) for x in bpsk)
println("BPSK功率:¥power_bpsk")

qpsk = collect(simout["modulations_2/qpsk"]).value
power_qpsk = mean(abs2.(x[1]) for x in qpsk)
println("QPSK功率:¥power_qpsk")

psk8 = collect(simout["modulations_2/8psk"]).value
power_8psk = mean(abs2.(x[1]) for x in psk8)
println("8psk功率:¥power_8psk")

qam16 = collect(simout["modulations_2/16qam"]).value
power_16qam = mean(abs2.(x[1]) for x in qam16)
println("16qam功率:$power_16qam")

println("过滤器后:")
bpsk = collect(simout["modulations_2/bpsk_f"]).value
power_bpsk = mean(abs2.(x[1]) for x in bpsk)
println("BPSK功率:¥power_bpsk")

qpsk = collect(simout["modulations_2/qpsk_f"]).value
power_qpsk = mean(abs2.(x[1]) for x in qpsk)
println("QPSK功率:¥power_qpsk")

psk8 = collect(simout["modulations_2/8psk_f"]).value
power_8psk = mean(abs2.(x[1]) for x in psk8)
println("8psk功率:¥power_8psk")

qam16 = collect(simout["modulations_2/16qam_f"]).value
power_16qam = mean(abs2.(x[1]) for x in qam16)
println("16qam功率:$power_16qam")
До фильтра:
Мощность BPSK: 1.0
Мощность QPSK: 1.0
Мощность 8PSK: 1.0
Мощность 16QAM: 10.25582944703531
После фильтра:
Мощность BPSK: 0.1409425649351918
Мощность QPSK: 0.17159058274740896
Мощность 8PSK: 0.14019923876567178
Мощность 16QAM: 1.4458938239675563

让我们为每个调制执行指南的构建。

In [ ]:
bpsk = collect(simout["modulations_2/bpsk_demod"]).value
bpsk = [x[1] for x in bpsk]  # 提取每个向量的第一个元素
plot(title="BPSK")
plot!(bpsk, seriestype=:scatter)
plot!([-1+0im, 1+0im], seriestype=:scatter)
Out[0]:
In [ ]:
qpsk = collect(simout["modulations_2/qpsk_demod"]).value;
qpsk = [x[1] for x in qpsk]  # 提取每个向量的第一个元素
plot(title="QPSK")
plot!(ComplexF64.(qpsk), seriestype=:scatter)
plot!([0.75+0.75im, 0.75-0.75im, -0.75+0.75im, -0.75-0.75im], seriestype=:scatter)
Out[0]:
In [ ]:
psk8 = collect(simout["modulations_2/8psk_demod"]).value;
psk8 = [x[1] for x in psk8]  # 提取每个向量的第一个元素
plot(title="8-PSK")
plot!(ComplexF64.(psk8), seriestype=:scatter)
plot!(cis.(2pi*[0:7...]/8), seriestype=:scatter)
Out[0]:
In [ ]:
qam16 = collect(simout["modulations_2/16qam_demod"]).value;
qam16 = [(i...)+0 for i in qam16];
plot(title="16QAM")
plot!(ComplexF64.(qam16), seriestype=:scatter)
plot!([a + b*im for a in -3:2:3, b in -3:2:3][:], seriestype=:scatter)
Out[0]:

调制信号的频谱分析

为了深入研究调制信号的性质,我们执行了:

  1. 频谱功率密度的计算使用:

    *汉宁窗功能,减少光谱泄漏影响

    *平滑频谱特性的中值滤波

  2. 平滑系数为0.2的奈奎斯特光谱与理论模型的比较

  3. 频谱特性的可视化在频域

所实现的模型演示了使用数据缓冲分析多频系统的可能性。

image.png
In [ ]:
using FFTW, DSP, Statistics, SpecialFunctions

function compute_smoothed_spectrum(signal, fs, window_size=20)
    window = hanning(length(signal))
    windowed_signal = signal .* window
    power_spectrum = abs.(fft(windowed_signal)).^2 / (sum(abs2, window) * fs)
    power_spectrum_db = 10*log10.(power_spectrum)
    
    function my_medfilt(signal, window_size)
        half_window = window_size ÷ 2
        smoothed = similar(signal)
        n = length(signal)
        for i in 1:n
            start_idx = max(1, i - half_window)
            end_idx = min(n, i + half_window)
            window_data = signal[start_idx:end_idx]
            smoothed[i] = median(window_data)
        end
        return smoothed
    end
    power_spectrum_db_smoothed = my_medfilt(power_spectrum_db, window_size)
    freqs = fftfreq(length(signal), fs)
    return fftshift(freqs), fftshift(power_spectrum_db_smoothed)
end

function nyquist_spectrum(frequencies, rolloff_factor=0.5, symbol_rate=1.0)
    T = 1.0 / symbol_rate
    f_N = 1.0 / (2 * T)
    spectrum = zeros(length(frequencies))
    for (i, f) in enumerate(frequencies)
        f_abs = abs(f)
        if f_abs <= (1 - rolloff_factor) * f_N
            spectrum[i] = T
        elseif f_abs <= (1 + rolloff_factor) * f_N && f_abs > (1 - rolloff_factor) * f_N
            spectrum[i] = T/2 * (1 + cos(π * T / rolloff_factor * (f_abs - (1 - rolloff_factor) * f_N)))
        else
            spectrum[i] = 0.0
        end
    end
    spectrum_db = 10 * log10.(spectrum .+ 1e-12)
    return spectrum_db
end

fs = 400
window_size = 15
symbol_rate = 50.0
rolloff = 0.2

run_model("modulations_3")

bpsk = collect(simout["modulations_3/bpsk_f"]).value
bpsk = [(i...)+0 for i in bpsk]
qpsk = collect(simout["modulations_3/qpsk_f"]).value
qpsk = [(i...)+0 for i in qpsk]
psk8 = collect(simout["modulations_3/8psk_f"]).value
psk8 = [(i...)+0 for i in psk8]
qam16 = collect(simout["modulations_3/16qam_f"]).value
qam16 = [(i...)+0 for i in qam16]

freqs_bpsk, spectrum_bpsk = compute_smoothed_spectrum(bpsk, fs, window_size)
freqs_qpsk, spectrum_qpsk = compute_smoothed_spectrum(qpsk, fs, window_size)
freqs_psk8, spectrum_psk8 = compute_smoothed_spectrum(psk8, fs, window_size)
freqs_qam16, spectrum_qam16 = compute_smoothed_spectrum(qam16, fs, window_size)
freqs_theoretical = range(-fs/2, fs/2, length=1000)
spectrum_nyquist_02 = nyquist_spectrum(freqs_theoretical, 0.2, symbol_rate)
max_experimental = maximum([maximum(spectrum_bpsk), maximum(spectrum_qpsk), maximum(spectrum_psk8), maximum(spectrum_qam16)])
max_theoretical_02 = maximum(spectrum_nyquist_02)
spectrum_nyquist_02_normalized = spectrum_nyquist_02 .- (max_theoretical_02 - max_experimental)

plot(freqs_bpsk, spectrum_bpsk, label="BPSK", linewidth=2, grid=true)
plot!(freqs_qpsk, spectrum_qpsk, label="QPSK", linewidth=2)
plot!(freqs_psk8, spectrum_psk8, label="8-PSK", linewidth=2)
plot!(freqs_qam16, spectrum_qam16, label="16-QAM", linewidth=2)
plot!(freqs_theoretical, spectrum_nyquist_02_normalized, label="奈奎斯特α=0.2", linewidth=3, linestyle=:dash, color=:red)
title!("调制信号的能谱(fs=$fs Hz)\带窗口的nmedian滤波器$window_size")
xlabel!("频率,赫兹")
ylabel!("光谱功率密度,dB/Hz")
xlims!(-fs/2, fs/2)
Building...
Progress 0%
Progress 6%
Progress 23%
Progress 32%
Progress 40%
Progress 49%
Progress 59%
Progress 68%
Progress 78%
Progress 88%
Progress 98%
Progress 100%
Progress 100%
Out[0]:

所获得的结果使得可以对调制方案进行全面分析,并证明为通信系统的特定操作条件选择最佳调制是可能的。

结论。

基于
通过对调制方案特性的综合分析,可以得出以下结论。

/参数/BPSK/QPSK/8-PSK/16-QAM|
|:---|:---|:---|:---|:---|
|效率/1b/s/Hz/2b/s/Hz/3b/s/Hz/4b/s/Hz|
/Ber=10-3|~7dB|~7dB|~11dB|~15dB|所需的Eb/No
|解调的复杂度/低/低/平均/高|

不同场景的最佳选择:

  1. 最大抗扰度→BPSK
  2. 最优折衷→QPSK↑
  3. 带宽有限,信噪比好→8-PSK
  4. 理想条件下的最大速度→16-QAM

总而言之,QPSK是大多数真实通信系统的最平衡和最实用的选择,提供了抗噪性,频谱效率和易于实现的最佳比率。 BPSK应用于具有极高可靠性要求的系统,而更高级别的调制应仅在保证良好通信信道质量的情况下使用。