diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 7e5d1452..78d4f3e7 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -2,25 +2,25 @@ env: SECRET_CODECOV_TOKEN: "Q3fuMdJjaQy9h/uk43rwSqz8M6ulvlCedU2Ir0S3QLP4t9F8cf7pzrTkX+nVhkGycZ/r5FRtTOwPr445R3wK5v9mEAsJN5GMOgI5w/L8m2XDwLmW3PN8RMno+fm2JVxZyPMNNmIQqbYEmmQcBS6Q3nywW3xi0Cl5umJuwDB+NdOFbpq3wc2wrnbOAbwlBJoCJmlH+F4ncuVY6EMmsgNKAf9RqUNWQxIthG616X1cNwuYEpL4dO/PWY2GMXWXTQ8ndO/713p4b5yIlzDP0mr2MrO+1A5fhgPc7Vr+f9mUlIAx+9AsWQYPrqPTkr2L5+mfaTodVE3u2Cop877WJZQD7w==;U2FsdGVkX1/wk2jzfWlRZ66IWgionQK/5Fu0pg3u0b26hhmmMjAjOklyi7QZKhJHjjt4KjK/dJzhd3eK28S0qQ==" steps: - - label: "Julia v1.10" + - label: "Julia v1.10 - GPU Tests" plugins: - JuliaCI/julia#v1: version: "1.10" - - JuliaCI/julia-test#v1: ~ - - JuliaCI/julia-coverage#v1: - codecov: true + commands: + - julia --project=ext/TrackingCUDAExt/test -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - julia --project=ext/TrackingCUDAExt/test ext/TrackingCUDAExt/test/runtests.jl agents: queue: "juliagpu" cuda: "*" if: build.message !~ /\[skip tests\]/ timeout_in_minutes: 60 - - label: "Julia v1.11" + - label: "Julia v1.11 - GPU Tests" plugins: - JuliaCI/julia#v1: version: "1.11" - - JuliaCI/julia-test#v1: ~ - - JuliaCI/julia-coverage#v1: - codecov: true + commands: + - julia --project=ext/TrackingCUDAExt/test -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - julia --project=ext/TrackingCUDAExt/test ext/TrackingCUDAExt/test/runtests.jl agents: queue: "juliagpu" cuda: "*" diff --git a/.gitignore b/.gitignore index 46eea050..2f01efcb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,11 @@ *.jl.mem /Manifest.toml test/Manifest.toml +ext/**/test/Manifest.toml docs/build/ docs/pdf/build/ docs/site/ docs/Manifest.toml + +.worktrees/ diff --git a/Project.toml b/Project.toml index 690b2809..a6b6ab9f 100644 --- a/Project.toml +++ b/Project.toml @@ -8,7 +8,6 @@ Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" Acquisition = "d4bbf60b-102b-5ffb-8f97-a7ea5817e69f" Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" Bumper = "8ce10254-0962-460f-a3d8-1f77fea1446e" -CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" @@ -20,6 +19,12 @@ StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" TrackingLoopFilters = "0814aff9-93cb-554c-9fff-9bf1cfdb5efa" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +[weakdeps] +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + +[extensions] +TrackingCUDAExt = "CUDA" + [compat] Accessors = "0.1" Acquisition = "0.1.1" diff --git a/README.md b/README.md index ef6b2724..e61124b7 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Moreover, Tracking.jl allows tracking of signals from phased antenna arrays mean * Secondary code detection * Bit detection * Phased array tracking -* GPU acceleration (CUDA) +* GPU acceleration (requires `using CUDA`) ## Getting started @@ -32,4 +32,17 @@ Install: ```julia julia> ] pkg> add Tracking +``` + +### GPU Support + +To use GPU acceleration features, you need to explicitly load CUDA: + +```julia +using Tracking +using CUDA # Activates GPU functionality + +# Access GPU types via the extension +ext = Base.get_extension(Tracking, :TrackingCUDAExt) +gpu_correlator = ext.GPUDownconvertAndCorrelator(...) ``` \ No newline at end of file diff --git a/ext/TrackingCUDAExt/TrackingCUDAExt.jl b/ext/TrackingCUDAExt/TrackingCUDAExt.jl new file mode 100644 index 00000000..c55b1d27 --- /dev/null +++ b/ext/TrackingCUDAExt/TrackingCUDAExt.jl @@ -0,0 +1,28 @@ +module TrackingCUDAExt + +using Tracking +using CUDA + +# Import dependencies needed by GPU code +using GNSSSignals +using StaticArrays +using Dictionaries +using Accessors +using DocStringExtensions +using Unitful: Hz +import Adapt + +# Import functions from Tracking that we need to extend or use +import Tracking: downconvert_and_correlate, downconvert_and_correlate!, get_num_samples, update + +# Include the GPU implementation +include("downconvert_and_correlate_gpu.jl") + +# Export GPU types from the extension +# Users access these via: Base.get_extension(Tracking, :TrackingCUDAExt).GPUDownconvertAndCorrelator +export GPUSatDownconvertAndCorrelator, + GPUSystemDownconvertAndCorrelator, + GPUDownconvertAndCorrelator, + convert_code_to_texture_memory + +end diff --git a/src/downconvert_and_correlate_gpu.jl b/ext/TrackingCUDAExt/downconvert_and_correlate_gpu.jl similarity index 100% rename from src/downconvert_and_correlate_gpu.jl rename to ext/TrackingCUDAExt/downconvert_and_correlate_gpu.jl diff --git a/ext/TrackingCUDAExt/test/Project.toml b/ext/TrackingCUDAExt/test/Project.toml new file mode 100644 index 00000000..7aa5f3a7 --- /dev/null +++ b/ext/TrackingCUDAExt/test/Project.toml @@ -0,0 +1,8 @@ +[deps] +Bumper = "8ce10254-0962-460f-a3d8-1f77fea1446e" +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +GNSSSignals = "52c80523-2a4e-5c38-8979-05588f836870" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Tracking = "10b2438b-ffd4-5096-aa58-44041d5c8f3b" +Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" diff --git a/ext/TrackingCUDAExt/test/runtests.jl b/ext/TrackingCUDAExt/test/runtests.jl new file mode 100644 index 00000000..dcfe9b3b --- /dev/null +++ b/ext/TrackingCUDAExt/test/runtests.jl @@ -0,0 +1,226 @@ +module TrackingCUDAExtTests + +using Test: @test, @testset, @inferred +using Unitful: Hz +using Tracking +using CUDA: CUDA, cu +using GNSSSignals: GPSL1, gen_code, get_code_frequency, get_code_center_frequency_ratio, get_code +using Pkg +using Bumper: SlabBuffer +using Tracking: + CPUDownconvertAndCorrelator, + SystemSatsState, + SatState, + TrackState, + downconvert_and_correlate, + get_last_fully_integrated_correlator, + track, + get_code_phase, + get_carrier_phase, + get_carrier_doppler, + get_code_doppler, + get_last_fully_integrated_filtered_prompt, + NumAnts, + get_default_correlator + +# Access extension types via Base.get_extension +const TrackingCUDAExt = Base.get_extension(Tracking, :TrackingCUDAExt) +const GPUDownconvertAndCorrelator = TrackingCUDAExt.GPUDownconvertAndCorrelator + +# Helper function to check CUDA.jl version +function is_cuda_below_version(version_string::String) + cuda_version = Pkg.installed()["CUDA"] + return cuda_version < VersionNumber(version_string) +end + +@testset "GPU Downconvert and Correlate" begin + !CUDA.functional() && return + + gpsl1 = GPSL1() + sampling_frequency = 5e6Hz + code_phase = 10.5 + num_samples_signal = 5000 + intermediate_frequency = 0.0Hz + + system_sats_state = SystemSatsState( + gpsl1, + [SatState(gpsl1, 1, code_phase, 1000.0Hz), SatState(gpsl1, 2, 11.0, 500.0Hz)]; + ) + multiple_system_sats_state = (system_sats_state,) + + downconvert_and_correlator = + GPUDownconvertAndCorrelator(multiple_system_sats_state, num_samples_signal) + + track_state = TrackState(multiple_system_sats_state) + + preferred_num_code_blocks_to_integrate = 1 + + signal = cu( + gen_code( + num_samples_signal, + gpsl1, + 1, + sampling_frequency, + get_code_frequency(gpsl1) + 1000Hz * get_code_center_frequency_ratio(gpsl1), + code_phase, + ) .* cis.(2π * (0:(num_samples_signal-1)) * 1000.0Hz / sampling_frequency), + ) + + next_track_state = @inferred downconvert_and_correlate( + downconvert_and_correlator, + signal, + track_state, + preferred_num_code_blocks_to_integrate, + sampling_frequency, + intermediate_frequency, + ) + + # GPU uses floating point arithmetic and might differ a little with the fixed point arithmetic + if is_cuda_below_version("5.8.0") + @test real.( + get_last_fully_integrated_correlator(next_track_state, 1).accumulators + ) ≈ [2921, 4949, 2921] + else + # Unfortuntely, the texture index rounding is off with CUDA 5.9 TODO: report + accumulator = + real.( + get_last_fully_integrated_correlator(next_track_state, 1).accumulators + ) + @test 2900 < accumulator[1] < 3000 + @test 4900 < accumulator[2] < 5000 + @test 2900 < accumulator[3] < 3000 + end + + signal = cu( + gen_code( + num_samples_signal, + gpsl1, + 2, + sampling_frequency, + get_code_frequency(gpsl1) + 500Hz * get_code_center_frequency_ratio(gpsl1), + 11.0, + ) .* cis.(2π * (0:(num_samples_signal-1)) * 500.0Hz / sampling_frequency), + ) + + next_track_state = @inferred downconvert_and_correlate( + downconvert_and_correlator, + signal, + track_state, + preferred_num_code_blocks_to_integrate, + sampling_frequency, + intermediate_frequency, + ) + + # GPU uses floating point arithmetic and might differ a little with the fixed point arithmetic + if is_cuda_below_version("5.8.0") + @test real.( + get_last_fully_integrated_correlator(next_track_state, 2).accumulators + ) ≈ [2919, 4947, 2919] + else + # Unfortuntely, the texture index rounding is off with CUDA 5.9 TODO: report + accumulator = + real.( + get_last_fully_integrated_correlator(next_track_state, 2).accumulators + ) + @test 2900 < accumulator[1] < 3000 + @test 4900 < accumulator[2] < 5000 + @test 2900 < accumulator[3] < 3000 + end +end + +@testset "Track multiple signals with GPU" begin + !CUDA.functional() && return + gpsl1 = GPSL1() + carrier_doppler = 200Hz + start_code_phase = 100 + code_frequency = carrier_doppler / 1540 + get_code_frequency(gpsl1) + sampling_frequency = 4e6Hz + prn = 1 + range = 0:3999 + start_carrier_phase = π / 2 + + num_samples = 4000 + num_ants = NumAnts(3) + + correlator = get_default_correlator(gpsl1, num_ants) + sat_states = + [SatState(gpsl1, 1, start_code_phase, carrier_doppler - 20Hz; num_ants, correlator)] + + system_sats_state = SystemSatsState(gpsl1, sat_states) + + # TODO: Why doesn't @inferred work here? + downconvert_and_correlator = + GPUDownconvertAndCorrelator((system_sats_state,), num_samples) + + track_state = @inferred TrackState(system_sats_state) + + signal = + cis.(2π .* carrier_doppler .* range ./ sampling_frequency .+ start_carrier_phase) .* + get_code.( + gpsl1, + code_frequency .* range ./ sampling_frequency .+ start_code_phase, + prn, + ) + signal_mat = cu(repeat(signal; outer = (1, 3))) + + track_state = @inferred track( + signal_mat, + track_state, + sampling_frequency; + downconvert_and_correlator, + ) + + iterations = 2000 + code_phases = zeros(iterations) + carrier_phases = zeros(iterations) + tracked_code_phases = zeros(iterations) + tracked_carrier_phases = zeros(iterations) + tracked_code_dopplers = zeros(iterations) + tracked_carrier_dopplers = zeros(iterations) + tracked_prompts = zeros(ComplexF64, iterations) + for i = 1:iterations + carrier_phase = + mod2pi( + 2π * carrier_doppler * 4000 * i / sampling_frequency + + start_carrier_phase + + π, + ) - π + code_phase = + mod(code_frequency * 4000 * i / sampling_frequency + start_code_phase, 1023) + signal = + cis.(2π .* carrier_doppler .* range ./ sampling_frequency .+ carrier_phase) .* + get_code.( + gpsl1, + code_frequency .* range ./ sampling_frequency .+ code_phase, + prn, + ) + signal_mat = cu(repeat(signal; outer = (1, 3))) + track_state = @inferred track( + signal_mat, + track_state, + sampling_frequency; + downconvert_and_correlator, + ) + comp_carrier_phase = + mod2pi( + 2π * carrier_doppler * 4000 * (i + 1) / sampling_frequency + + start_carrier_phase + + π, + ) - π + comp_code_phase = mod( + code_frequency * 4000 * (i + 1) / sampling_frequency + start_code_phase, + 1023, + ) + tracked_code_phases[i] = get_code_phase(track_state) + tracked_carrier_phases[i] = get_carrier_phase(track_state) + tracked_carrier_dopplers[i] = get_carrier_doppler(track_state) / Hz + tracked_code_dopplers[i] = get_code_doppler(track_state) / Hz + tracked_prompts[i] = get_last_fully_integrated_filtered_prompt(track_state) + code_phases[i] = comp_code_phase + carrier_phases[i] = comp_carrier_phase + end + @test tracked_code_phases[end] ≈ code_phases[end] atol = 1e-2 + @test tracked_carrier_phases[end] + π ≈ carrier_phases[end] atol = 5e-5 +end + +end diff --git a/src/Tracking.jl b/src/Tracking.jl index cab84fda..e2db5685 100644 --- a/src/Tracking.jl +++ b/src/Tracking.jl @@ -1,6 +1,5 @@ module Tracking -using CUDA using DocStringExtensions using GNSSSignals using LoopVectorization @@ -48,10 +47,7 @@ export get_early, SatState, SystemSatsState, CPUSatDownconvertAndCorrelator, - GPUSatDownconvertAndCorrelator, - GPUSystemDownconvertAndCorrelator, CPUDownconvertAndCorrelator, - GPUDownconvertAndCorrelator, ConventionalPLLAndDLL, DefaultPostCorrFilter, TrackState, @@ -62,7 +58,20 @@ export get_early, get_system, estimate_cn0, get_default_correlator, - convert_code_to_texture_memory + AbstractCorrelator, + AbstractDownconvertAndCorrelator, + MultipleSystemType, + MultipleSystemSatsState, + get_num_accumulators, + get_correlator_sample_shifts, + calc_signal_samples_to_integrate, + update, + get_code_frequency, + get_code_length, + get_codes, + get_modulation, + get_secondary_code, + update_accumulator const Maybe{T} = Union{T,Nothing} @@ -128,8 +137,8 @@ end include("sample_parameters.jl") include("downconvert_and_correlate.jl") include("downconvert_and_correlate_cpu.jl") -include("downconvert_and_correlate_gpu.jl") include("conventional_pll_and_dll.jl") include("tracking_state.jl") include("track.jl") + end diff --git a/test/Project.toml b/test/Project.toml index 660f58eb..8cb1fb5d 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -2,15 +2,14 @@ Acquisition = "d4bbf60b-102b-5ffb-8f97-a7ea5817e69f" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" Bumper = "8ce10254-0962-460f-a3d8-1f77fea1446e" -CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" GNSSSignals = "52c80523-2a4e-5c38-8979-05588f836870" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Tracking = "10b2438b-ffd4-5096-aa58-44041d5c8f3b" TrackingLoopFilters = "0814aff9-93cb-554c-9fff-9bf1cfdb5efa" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" diff --git a/test/downconvert_and_correlate.jl b/test/downconvert_and_correlate.jl index 8a716f01..cf9f16e3 100644 --- a/test/downconvert_and_correlate.jl +++ b/test/downconvert_and_correlate.jl @@ -2,33 +2,22 @@ module DownconvertAndCorrelateTest using Test: @test, @testset, @inferred using Unitful: Hz -using CUDA: CUDA, cu using GNSSSignals: GPSL1, gen_code, get_code_frequency, get_code_center_frequency_ratio -using Pkg using Bumper: SlabBuffer using Tracking: CPUDownconvertAndCorrelator, - GPUDownconvertAndCorrelator, SystemSatsState, SatState, TrackState, downconvert_and_correlate, get_last_fully_integrated_correlator -# Helper function to check CUDA.jl version -function is_cuda_below_version(version_string::String) - cuda_version = Pkg.installed()["CUDA"] - return cuda_version < VersionNumber(version_string) -end - @testset "Downconvert and Correlator" begin downconvert_and_correlator = CPUDownconvertAndCorrelator(Val(5e6Hz)) @test downconvert_and_correlator.buffer isa SlabBuffer end -@testset "Downconvert and correlate with $type" for type in (:CPU, :GPU) - type == :GPU && !CUDA.functional() && return - +@testset "Downconvert and correlate with CPU" begin gpsl1 = GPSL1() sampling_frequency = 5e6Hz code_phase = 10.5 @@ -44,25 +33,20 @@ end maximum_expected_sampling_frequency = Val(sampling_frequency) downconvert_and_correlator = - type == :CPU ? CPUDownconvertAndCorrelator(maximum_expected_sampling_frequency) : - GPUDownconvertAndCorrelator(multiple_system_sats_state, num_samples_signal) - - array_transform = type == :CPU ? Array : cu + CPUDownconvertAndCorrelator(maximum_expected_sampling_frequency) track_state = TrackState(multiple_system_sats_state) preferred_num_code_blocks_to_integrate = 1 - signal = array_transform( - gen_code( - num_samples_signal, - gpsl1, - 1, - sampling_frequency, - get_code_frequency(gpsl1) + 1000Hz * get_code_center_frequency_ratio(gpsl1), - code_phase, - ) .* cis.(2π * (0:(num_samples_signal-1)) * 1000.0Hz / sampling_frequency), - ) + signal = gen_code( + num_samples_signal, + gpsl1, + 1, + sampling_frequency, + get_code_frequency(gpsl1) + 1000Hz * get_code_center_frequency_ratio(gpsl1), + code_phase, + ) .* cis.(2π * (0:(num_samples_signal-1)) * 1000.0Hz / sampling_frequency) next_track_state = @inferred downconvert_and_correlate( downconvert_and_correlator, @@ -73,38 +57,18 @@ end intermediate_frequency, ) - # GPU uses floating point arithmetic and might differ a little with the fixed point arithmetic - if type == :CPU - @test real.( - get_last_fully_integrated_correlator(next_track_state, 1).accumulators - ) ≈ [2921, 4949, 2917] - else - if is_cuda_below_version("5.8.0") - @test real.( - get_last_fully_integrated_correlator(next_track_state, 1).accumulators - ) ≈ [2921, 4949, 2921] - else - # Unfortuntely, the texture index rounding is off with CUDA 5.9 TODO: report - accumulator = - real.( - get_last_fully_integrated_correlator(next_track_state, 1).accumulators - ) - @test 2900 < accumulator[1] < 3000 - @test 4900 < accumulator[2] < 5000 - @test 2900 < accumulator[3] < 3000 - end - end + @test real.( + get_last_fully_integrated_correlator(next_track_state, 1).accumulators + ) ≈ [2921, 4949, 2917] - signal = array_transform( - gen_code( - num_samples_signal, - gpsl1, - 2, - sampling_frequency, - get_code_frequency(gpsl1) + 500Hz * get_code_center_frequency_ratio(gpsl1), - 11.0, - ) .* cis.(2π * (0:(num_samples_signal-1)) * 500.0Hz / sampling_frequency), - ) + signal = gen_code( + num_samples_signal, + gpsl1, + 2, + sampling_frequency, + get_code_frequency(gpsl1) + 500Hz * get_code_center_frequency_ratio(gpsl1), + 11.0, + ) .* cis.(2π * (0:(num_samples_signal-1)) * 500.0Hz / sampling_frequency) next_track_state = @inferred downconvert_and_correlate( downconvert_and_correlator, @@ -115,27 +79,9 @@ end intermediate_frequency, ) - # GPU uses floating point arithmetic and might differ a little with the fixed point arithmetic - if type == :CPU - @test real.( - get_last_fully_integrated_correlator(next_track_state, 2).accumulators - ) ≈ [2919, 4947, 2915] - else - if is_cuda_below_version("5.8.0") - @test real.( - get_last_fully_integrated_correlator(next_track_state, 2).accumulators - ) ≈ [2919, 4947, 2919] - else - # Unfortuntely, the texture index rounding is off with CUDA 5.9 TODO: report - accumulator = - real.( - get_last_fully_integrated_correlator(next_track_state, 2).accumulators - ) - @test 2900 < accumulator[1] < 3000 - @test 4900 < accumulator[2] < 5000 - @test 2900 < accumulator[3] < 3000 - end - end + @test real.( + get_last_fully_integrated_correlator(next_track_state, 2).accumulators + ) ≈ [2919, 4947, 2915] end end diff --git a/test/track.jl b/test/track.jl index b415f9a6..479048d5 100644 --- a/test/track.jl +++ b/test/track.jl @@ -4,7 +4,6 @@ using Test: @test, @testset, @inferred using Random: Random using Unitful: Hz, kHz, MHz using Statistics: mean -using CUDA: CUDA, cu using GNSSSignals: GPSL1, GPSL5, @@ -18,7 +17,6 @@ using Tracking: SatState, TrackState, SystemSatsState, - GPUDownconvertAndCorrelator, track, get_code_phase, get_carrier_phase, @@ -30,8 +28,7 @@ using Tracking: get_last_fully_integrated_filtered_prompt, get_code_length, NumAnts, - get_num_ants, - get_default_correlator + get_num_ants @testset "Tracking with signal of type $type" for type in (Int16, Int32, Int64, Float32, Float64) @@ -490,115 +487,4 @@ end # plot(imag.(tracked_prompts)) end -@testset "Track multiple signals with GPU" begin - !CUDA.functional() && return - gpsl1 = GPSL1() - carrier_doppler = 200Hz - start_code_phase = 100 - code_frequency = carrier_doppler / 1540 + get_code_frequency(gpsl1) - sampling_frequency = 4e6Hz - prn = 1 - range = 0:3999 - start_carrier_phase = π / 2 - - num_samples = 4000 - num_ants = NumAnts(3) - - correlator = get_default_correlator(gpsl1, num_ants) - sat_states = - [SatState(gpsl1, 1, start_code_phase, carrier_doppler - 20Hz; num_ants, correlator)] - - system_sats_state = SystemSatsState(gpsl1, sat_states) - - # TODO: Why doesn't @inferred work here? - downconvert_and_correlator = - GPUDownconvertAndCorrelator((system_sats_state,), num_samples) - - track_state = @inferred TrackState(system_sats_state) - - signal = - cis.(2π .* carrier_doppler .* range ./ sampling_frequency .+ start_carrier_phase) .* - get_code.( - gpsl1, - code_frequency .* range ./ sampling_frequency .+ start_code_phase, - prn, - ) - signal_mat = cu(repeat(signal; outer = (1, 3))) - - track_state = @inferred track( - signal_mat, - track_state, - sampling_frequency; - downconvert_and_correlator, - ) - - iterations = 2000 - code_phases = zeros(iterations) - carrier_phases = zeros(iterations) - tracked_code_phases = zeros(iterations) - tracked_carrier_phases = zeros(iterations) - tracked_code_dopplers = zeros(iterations) - tracked_carrier_dopplers = zeros(iterations) - tracked_prompts = zeros(ComplexF64, iterations) - for i = 1:iterations - carrier_phase = - mod2pi( - 2π * carrier_doppler * 4000 * i / sampling_frequency + - start_carrier_phase + - π, - ) - π - code_phase = - mod(code_frequency * 4000 * i / sampling_frequency + start_code_phase, 1023) - signal = - cis.(2π .* carrier_doppler .* range ./ sampling_frequency .+ carrier_phase) .* - get_code.( - gpsl1, - code_frequency .* range ./ sampling_frequency .+ code_phase, - prn, - ) - signal_mat = cu(repeat(signal; outer = (1, 3))) - track_state = @inferred track( - signal_mat, - track_state, - sampling_frequency; - downconvert_and_correlator, - ) - comp_carrier_phase = - mod2pi( - 2π * carrier_doppler * 4000 * (i + 1) / sampling_frequency + - start_carrier_phase + - π, - ) - π - comp_code_phase = mod( - code_frequency * 4000 * (i + 1) / sampling_frequency + start_code_phase, - 1023, - ) - tracked_code_phases[i] = get_code_phase(track_state) - tracked_carrier_phases[i] = get_carrier_phase(track_state) - tracked_carrier_dopplers[i] = get_carrier_doppler(track_state) / Hz - tracked_code_dopplers[i] = get_code_doppler(track_state) / Hz - tracked_prompts[i] = get_last_fully_integrated_filtered_prompt(track_state) - code_phases[i] = comp_code_phase - carrier_phases[i] = comp_carrier_phase - end - @test tracked_code_phases[end] ≈ code_phases[end] atol = 1e-2 - @test tracked_carrier_phases[end] + π ≈ carrier_phases[end] atol = 5e-5 - - # using PyPlot - # pygui(true) - # figure("carrier_phases") - # plot(tracked_carrier_phases) - # plot(carrier_phases) - # grid(true) - # figure("Code Phases") - # plot(300 * (tracked_code_phases .- code_phases)) - # figure("Carrier Doppler") - # plot(tracked_carrier_dopplers) - # figure("Code Doppler") - # plot(tracked_code_dopplers) - # figure("Prompt") - # plot(real.(tracked_prompts)) - # plot(imag.(tracked_prompts)) -end - end