Влияние доплеровского сдвига на спутниковую связь
Влияние доплеровского сдвига на спутниковую связь
В этом примере рассмотрим, как геометрия пролёта спутника влияет на радиолинию. Средствами EngeeSatellites рассчитаем дальность, доплеровский сдвиг и отношение несущей к шуму. Затем в модели Engee сравним приём BPSK с известной частотной коррекцией и без неё.
Во время пролёта спутник приближается к станции, проходит ближайшую точку и удаляется. Изменение наклонной дальности влияет на потери распространения, а радиальная скорость вызывает доплеровский сдвиг частоты. Даже при достаточной мощности частотная ошибка поворачивает фазу сигнала и мешает когерентному приёму.
Для радиальной скорости , положительной при удалении, сдвиг приближённо равен
Рассчитаем три момента времени: −200, 0 и 200 с. Высота круговой орбиты равна 550 км, несущая — 150 МГц. CNR — отношение мощности несущей к мощности шума в заданной полосе.
Это учебная связь геометрического расчёта с моделью приёмника. В настройку AWGN передаётся ограниченная величина clamp(CNR−10, 2, 20), а доплеровский сдвиг уменьшается в 100 раз. Так представляется условный остаток после грубой коррекции; полноценный бюджет линии и работа алгоритма оценки частоты здесь не моделируются.

В модели Demo03_SatellitePass.engee биты проходят через BPSK-модулятор, частотный сдвиг Doppler и шум DownlinkNoise. Затем сигнал поступает в две ветви: непосредственное решение DemodRaw и коррекция DopplerCorrection с последующим решением.
Корректор получает точно известный остаточный сдвиг с обратным знаком. Поэтому пример показывает эффект идеальной компенсации, а не процесс её поиска.
Подключим библиотеки и зададим путь к модели относительно папки скрипта. Вспомогательная функция загрузит и откроет модель, применит параметры и закроет её после запуска. Данные To Workspace читаются из общей рабочей области Engee, поэтому программный запуск этого примера выполняем с isolate = false.
using Statistics, DataFrames, Plots
gr()
name = "SatellitePass"
path = joinpath(@__DIR__, name * ".engee")
@assert isfile(path) "Не найден файл модели: $path"
function load_and_run(path, name; settings=Pair{String,String}[])
try engee.close(name; force=true) catch end
model = engee.load(path; force=true)
engee.open(name)
for (block, keyvalue) in settings
engee.set_param!("$name/$block", keyvalue)
end
try
engee.run(model)
finally
engee.close(name; force=true)
end
end
wa(name) = Core.eval(Main, :(collect($(Symbol(name)))))
Теперь рассчитаем параметры пролёта и выполним три запуска модели. В каждой точке зададим частотную ошибку, противоположную ей коррекцию и уровень шума. BER определим по записанным битам обеих ветвей.
using EngeeSatellites
import EngeeSatellites.Functions: slantRangeCircularOrbit, dopplerShiftCircularOrbit, satelliteCNR
orbit_time = [-200.0,0.0,200.0]
distance_m = vec(Float64.(slantRangeCircularOrbit(20.0,550e3,0.0,orbit_time)))
doppler_hz = vec(Float64.(dopplerShiftCircularOrbit(20.0,550e3,0.0,150e6,orbit_time)))
cfg = EngeeSatellites.SatelliteCNRConfig(Frequency=0.15,Bandwidth=0.001,BitRate=0.001,SymbolRate=0.001)
cnr = Float64[]; ber_raw = Float64[]; ber_corrected = Float64[]
for j in eachindex(orbit_time)
cfg.Distance = distance_m[j]/1000
carrier_to_noise, _ = satelliteCNR(cfg)
push!(cnr,carrier_to_noise)
snr = clamp(carrier_to_noise-10,2,20)
residual = doppler_hz[j]/100
settings = ["Doppler"=>("FreqOff"=>string(residual)),
"DopplerCorrection"=>("FreqOff"=>string(-residual)),
"DownlinkNoise"=>("SNR"=>string(snr))]
load_and_run(path,name;settings=settings)
b = wa("bits"); r = wa("raw"); c = wa("corrected")
n = minimum((nrow(b),nrow(r),nrow(c)))
valid = 11:n
truth = Float64.(b.value[valid]) .> 0.5
push!(ber_raw,mean((Float64.(r.value[valid]) .> 0.5) .!= truth))
push!(ber_corrected,mean((Float64.(c.value[valid]) .> 0.5) .!= truth))
end
Построим дальность, доплеровский сдвиг, CNR и BER. Сравним, как изменение геометрии сочетается с качеством двух вариантов приёмника.
p1 = plot(orbit_time,distance_m./1000,marker=:circle,xlabel="Время пролёта, с",ylabel="Дальность, км",title="Геометрия",legend=false)
p2 = plot(orbit_time,doppler_hz,marker=:circle,xlabel="Время пролёта, с",ylabel="Сдвиг, Гц",title="Доплер",legend=false)
p3 = plot(orbit_time,cnr,marker=:circle,xlabel="Время пролёта, с",ylabel="CNR, дБ",title="Энергетика",legend=false)
p4 = bar(1:3,hcat(ber_raw,ber_corrected),label=["Без коррекции" "С коррекцией"],xlabel="Точка пролёта",ylabel="BER",title="Приём битов")
display(plot(p1,p2,p3,p4,layout=(2,2),size=(1000,700)))
println("BER без коррекции=",ber_raw,"; с коррекцией=",ber_corrected)
Графики дальности и доплеровского сдвига описывают выбранную круговую орбиту. Диаграмма BER показывает действие частотной коррекции. Без неё фаза вращается, и битовые решения ухудшаются; при известной коррекции это вращение устраняется.
Результат относится к трём коротким независимым опытам. Непрерывное сопровождение спутника, задержка распространения и ошибки оценки частоты в модель не включены.
Вывод
В данном примере мы связали расчёты EngeeSatellites с параметрами модели Engee. Это позволяет отдельно исследовать геометрию линии и влияние остаточной частотной ошибки на приём. Для проектирования реального спутникового приёмника потребуется добавить бюджет линии и алгоритм оценки доплеровского сдвига.
