Engee 文档
Notebook

OFDM过采样信号模型

在这个例子中,我们将考虑OFDM过采样信号模型(正交频分复用,一种使用大量紧密间隔的正交子载波的数字调制技术,或多路复用)。 该模型允许您查看多个调制的组合。 本例还使用测量叠加有噪声的OFDM调制信号的RMS单元,按与相对于FFT(快速傅立叶变换)大小的活动副载波数成比例的值缩放,以确认信号功率近似为一。

该模型基于以下原理。

  1. 生成随机整数数据集和导频输入字符。
  2. 16-QAM调制数据和导频符号。
  3. OFDM调制qam调制信号。 一对OFDM调制器和解调器处理导频信号的副载波索引和每个符号的循环前缀长度不同的三个符号。 OFDM信号包含模型以四倍采样率的频率生成的数据和导频。
  4. 接下来,我们将振幅失真应用于每个帧,这显着改变了信号强度。
  5. 之后,OFDM分别解调并输出数据和导频。
  6. 16-QAM解调数据和导频符号。
  7. 之后,我们找到输入和输出之间的差异。

下图显示了实现的模型。

image.png

接下来,初始化模型参数。

In [ ]:
M = 16;              # Порядок модуляции
nfft = 64;           # Длина FFT
NumSymbols=3;        # Количество символов OFDM
osf=4;               # Фактор передискретизации
ngbc = [9;8];        # Число носителей защитного диапазона
insertdcnull = true;  # Наличие DC-нулевой поднесущей
addpilotport = true;  # Присутствие пилота
Noise_power = 10; # Мощность шума
In [ ]:
# Индексы пилотных поднесущих
pscindx = [[12;26;40;54] [14;28;38;52] [12;26;40;54]]; 
cplen = [16; 32; 16];  # CyclicPrefixLength
# Выборки на кадр для данных
spf_data = NumSymbols * (nfft-sum(ngbc)-size(pscindx,1)-insertdcnull)
# Выборки на кадр для пилота    
spf_pilot = NumSymbols * size(pscindx,1)
# Число активных поднесущих
nasc = nfft-sum(ngbc)+insertdcnull;

声明模型参数后,初始化模型启动函数并运行模型本身。

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(5)
    return model_output
end

run_model("OFDM_Signal_and_QAM") # Запуск модели.
Building...
Progress 0%
Progress 0%
Progress 0%
Progress 3%
Progress 8%
Progress 13%
Progress 18%
Progress 23%
Progress 28%
Progress 33%
Progress 38%
Progress 43%
Progress 48%
Progress 54%
Progress 59%
Progress 64%
Progress 69%
Progress 74%
Progress 79%
Progress 84%
Progress 89%
Progress 94%
Progress 99%
Progress 100%
Progress 100%
Out[0]:
Dict{String, DataFrame} with 4 entries:
  "ErrorPilot" => 121×2 DataFrame…
  "RMSout"     => 10241×2 DataFrame…
  "ErrorData"  => 1261×2 DataFrame…
  "RMSinp"     => 10241×2 DataFrame

现在让我们分析记录的日期。

In [ ]:
ErrorData = collect(ErrorData);
ErrorPilot = collect(ErrorPilot);
RMSinp = collect(RMSinp);
RMSout = collect(RMSout);

ErrorData = ErrorData.value;
ErrorPilot = ErrorPilot.value;
RMSinp = RMSinp.value;
RMSout = RMSout.value;
In [ ]:
plot([real(RMSinp),real(RMSout)], title="RMS", label=["До наложения шума" "После наложения шума"])
Out[0]:

正如我们所看到的,信号强度因帧而异。 现在让我们来看看输入和输出数据之间的区别。

In [ ]:
plot([ErrorData,ErrorPilot], title="Разница между входами и выходами", label=["Данные" "Пилоты"])
Out[0]:

根据图表,误差为零,但为了确保这一点,我们将找到总误差。

In [ ]:
println("Суммарная разница между входными и выходными данными: " * string(sum(ErrorData)))
println("Суммарная разница между входными и выходными пилотами: " * string(sum(ErrorPilot)))
Суммарная разница между входными и выходными данными: 0.0
Суммарная разница между входными и выходными пилотами: 0.0

结论

在这个例子中,我们分析并演示了在通信系统中使用几种类型调制的可能性。 这种方法在这一活动领域非常受欢迎。