Документация Engee
Notebook

Модуляция основной полосы частот

Открыть пример в Engee

Этот пример показывает простой способ выполнения модуляции основной полосы частот путем умножения модулированного комплексного сигнала на сложную синусоидальную волну для выполнения преобразования частоты с повышением. Предпочтительнее моделировать систему в сложной основной полосе частот. Однако существуют некоторые обстоятельства, при которых необходимо моделировать систему в реальной полосе пропускания. Примером этого является случай, когда сигнал соседней полосы частот обрабатывается с нелинейностью и вызывает помехи в желаемой полосе частот. Этот пример также иллюстрирует эффект такого вмешательства и представлен в двух вариантах:

  1. В виде скрипта;
  2. В виде модели.

Схема алгоритма имеет следующий вид:

passband.png

Построение системы при помощи скрипта

Первый шаг построения системы: подключаем все используемые системные элементы и библиотеки.

In [ ]:
using FFTW, Plots
import .EngeeComms
gr()
step = EngeeComms.step;

Создадим структуру, в которой содержатся все переменные, связанные с параметрами подключенных блоков.

In [ ]:
mutable struct passband_modulator
    # Transmitter
    obj_random_integer
    obj_QPSK_modulator
    obj_raised_cosine_transmit
        # Upconverter
        obj_sine_upc
        obj_prod_upc
        obj_re_upc
    # Channel
    obj_sum
    obj_AWGN
        #interference
        obj_sine_inter
        obj_re_inter
        obj_const_inter
        obj_math_inter
        obj_gain_inter
    # Receiver
    #   downconverter
        obj_sine_wave_dc
        obj_conj_dc
        obj_prod_dc
    obj_raised_cosine_receive
    obj_QPSK_demodulator
    # Metrics
    obj_int_to_bit
    obj_BER
    obj_delay
    obj_EVM

    function passband_modulator()
        new(EngeeComms.random_integer(4, 37, 1e-6, 100, "Int"), EngeeComms.QPSK(pi/4), EngeeComms.rcostrans(0.2, 8, 8, 1.0), 
        EngeeComms.sine_wave(1.0, 2500000.0, 0.0, "Discrete", "Complex", "Trigonometric fcn", 1e-6/8, 800, "Restart at time zero"), EngeeComms.product(2, "Element-wise"), EngeeComms.complex_to_real_imag("Real"),
        EngeeComms.Sum("+"), EngeeComms.AWGN(67, "mode", 8.0, 2, 1/(2*8), 1e-6, 1e-4), EngeeComms.sine_wave(1.0 ,8.833333333333334e+05, 0.0, "Discrete", "Complex", "Trigonometric fcn", 1e-6/8, 800, "Restart at time zero"), EngeeComms.complex_to_real_imag("Real"), 3, EngeeComms.math("pow"), EngeeComms.Gain(.25),
        EngeeComms.sine_wave(1.0 ,2500000.0, 0.0, "Discrete", "Complex", "Trigonometric fcn", 1e-6/8, 800, "Restart at time zero"), EngeeComms.math("conj"), EngeeComms.product(2, "Element-wise"), EngeeComms.rcosreciev(0.2, 8, 8, 2.0, 8, 0), EngeeComms.deQPSK(pi/4), 
        EngeeComms.IntToBit(2, "Unsigned", "MSB first", "Boolean"), EngeeComms.error_rate(16, 0, "Entire frame", "Port", false, false), EngeeComms.delay(8,1), EngeeComms.EVM("Average reference signal power", "Input port", "Input length", 1))
    end
end

Создадим функцию для выполнения логики работы системы.

In [ ]:
function step1(obj::passband_modulator)
    out_upconv1 =[];
    out_downcov =[];
    out_rec_filt =[];
    out_interfer =[];
    out_BER =zeros(3);
    EngeeComms.setup(obj.obj_random_integer);
    EngeeComms.setup(obj.obj_AWGN, [1]);
    EVM_out = 0;
    for i =1:201
        # Передатчик
        ri = step(obj.obj_random_integer);
        QPSK_tr = step(obj.obj_QPSK_modulator, ri);
        raised_cos_tr = step(obj.obj_raised_cosine_transmit, QPSK_tr)
        test_rcos = raised_cos_tr;
            # Повышающий преобразователь
            sine_wave_upc = step(obj.obj_sine_upc);
            prod_upc = step(obj.obj_prod_upc, sine_wave_upc,raised_cos_tr);
            out_upconv = step(obj.obj_re_upc, prod_upc);
        
        # Канал
            # Интерференция с нелинейными искажениями
            sine_wave_nonl = step(obj.obj_sine_inter);
            re_nonl = step(obj.obj_re_inter, sine_wave_nonl);
            inter_pow = step(obj.obj_math_inter, re_nonl, obj.obj_const_inter);
            inter_gain = step(obj.obj_gain_inter, inter_pow);

        AWGN_in = step(obj.obj_sum, out_upconv, inter_gain);
        Channel_out = step(obj.obj_AWGN, AWGN_in);

        # Приемник
            # Понижающий преобразователь
            sine_dc = step(obj.obj_sine_wave_dc);
            conj_dc = step(obj.obj_conj_dc, sine_dc);
            out_dc = step(obj.obj_prod_dc, conj_dc, Channel_out);
        raised_cos_reciev = step(obj.obj_raised_cosine_receive, out_dc[:,1]);
        out_reciever = step(obj.obj_QPSK_demodulator, raised_cos_reciev);


        # Расчет побитовой ошибки (BER)
        out_bits = step(obj.obj_int_to_bit, out_reciever);
        rand_int_bits = step(obj.obj_int_to_bit, ri);

        BER = step(obj.obj_BER, rand_int_bits, out_bits);
        # Расчет EVM_rms
        ref_sig = step(obj.obj_delay, QPSK_tr)
        EVM_out = step(obj.obj_EVM, ref_sig, raised_cos_reciev)

        # Выходы
        out_BER = BER;
        out_upconv1 = vcat(out_upconv1, out_upconv);
        out_downcov = vcat(out_downcov, out_dc);
        out_rec_filt = vcat(out_rec_filt, raised_cos_reciev);
        out_interfer = vcat(out_interfer, inter_gain);
    end
    return out_BER, out_upconv1, out_downcov, out_rec_filt, out_interfer, EVM_out;
end
Out[0]:
step1 (generic function with 1 method)

Запуск системы и получение выходных данных.

In [ ]:
passband = passband_modulator() # Вызов структуры
BER,Upconverter,Downconverter,receive_filter,Interference, EVM_out = step1(passband); # Вызов функции
println(BER[1]," BER;") # Вывод данных в командной строке
println(BER[2], " Bit errors;") 
println(BER[3], " Bits;")
println()
println(EVM_out, " EVM_rms.") # Построение графика
0.001493131594664543 BER;
60.0 Bit errors;
40184.0 Bits;

35.140576755325306 EVM_rms.

Построим спектр сигнала на выходе передатчика и спектр вносимых искажений.

In [ ]:
b = Float64.(Upconverter);
spec_b = fftshift(fft(b))[80400:160800];
plot([0:4e6/80400:4e6...],(20log10.(abs.((spec_b)./[4e6/80400,4e6/80400:4e6/80400:4e6...]))), label ="Сигнал на выходе передатчика")

e = Float64.(Interference);
spec_e = fftshift(fft(e))[80400:160800];
plot!([0:4e6/80400:4e6...],20log10.(abs.((spec_e))), label ="Искажения")

ylabel!("Мощность дБВт")
xlabel!("Частота Гц")
plot!(legend=:outerbottom)
ylims!(-240, -60)
xlims!(0.2e6,4e6)
Out[0]:

Спектр сигнала после прохождения понижающего преобразователя.

In [ ]:
d = ComplexF64.(Downconverter);
spec_d = fftshift(fft(d));
plot([-4e6:8e6/160800:4e6-1...],10log10.(abs.((spec_d/3e6))), label ="Сигнал на выходе понижающего преобразователя")
ylabel!("Мощность дБВт")
xlabel!("Частота МГц")
plot!(legend=:outerbottom)
Out[0]:

Схема сигнального созвездия.

In [ ]:
f = ComplexF64.(receive_filter);
plot(f[end-200:end], seriestype=:scatter)
plot!([0.75+0.75im, 0.75-0.75im, -0.75+0.75im, -0.75-0.75im], seriestype=:scatter, lc=:red, lw=:5, ls =:dot)
plot!(legend=:none)
xlabel!("Синхфазная амплитуда")
ylabel!("Квадратурная амплитуда")
Out[0]:

Построение модели

Теперь рассмотрим второй способ построения систем связи, это моделирование процессов цифровой обработки сигналов при помощи моделей Engee.

Passbanmod

image3.png

Interference with Nonlinearity

image.png

Upconverter

image.png

Downconverter

image.png

Calculate RMS EVM

image.png

Compute BER

image.png

In [ ]:
function run_model( name_model, path_to_folder )
    
    Path = path_to_folder * "/" * 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

    return model_output
end
# Запуск модели
run_model( "passbandmod", @__DIR__ )
Building...
Progress 0%
Progress 0%
Progress 5%
Progress 10%
Progress 15%
Progress 20%
Progress 25%
Progress 30%
Progress 35%
Progress 40%
Progress 45%
Progress 50%
Progress 55%
Progress 60%
Progress 65%
Progress 70%
Progress 75%
Progress 80%
Progress 85%
Progress 90%
Progress 95%
Progress 100%
In [ ]:
# Подключение библиотек
using CSV, DataFrames
using Plots # Подключение библиотеки для построения графиков
gr() # Подключение бэкенда - метода отображения графики
Out[0]:
Plots.GRBackend()
In [ ]:
## EVM
EVM = Matrix(CSV.read("$(@__DIR__)/EVM.csv", DataFrame)); #загрузка данных
plot(EVM[:,1], EVM[:,2], xlabel="Время", ylabel="EVM", title="EVM") # Построение графика
Out[0]:
In [ ]:
## BER
BER = Matrix(CSV.read("$(@__DIR__)/BER.csv", DataFrame)); #загрузка данных
plot(BER[:,1], BER[:,2], xlabel="Время", ylabel="BER", title="BER") # Построение графика
Out[0]:

Вывод

Мы реализовали скрипт и модель простого способа выполнения модуляции основной полосы частот путем умножения модулированного комплексного сигнала на сложную синусоидальную волну для выполнения преобразования частоты с повышением. А также показали как использовать скрипты и модели для цифровой обработки сигналов в Engee.