Skip to content

Commit

Permalink
Added Michael Niestroj as author
Browse files Browse the repository at this point in the history
  • Loading branch information
Soeren Schoenbrod committed Jan 27, 2022
2 parents dcdf64b + ddb9474 commit 8550134
Show file tree
Hide file tree
Showing 11 changed files with 464 additions and 398 deletions.
10 changes: 6 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name = "GNSSDecoder"
uuid = "bf6b1ec8-12ad-4501-972c-3dec0d675c2b"
authors = ["Erik Deinzer <erikdeinzer@gmail.com>, Soeren Schoenbrod <soeren.schoenbrod@nav.rwth-aachen.de>"]
authors = ["Soeren Schoenbrod <soeren.schoenbrod@nav.rwth-aachen.de>",
"Michael Niestroj <michael.niestroj@nav.rwth-aachen.de>",
"Erik Deinzer <erikdeinzer@gmail.com>"]
version = "0.0.1"

[deps]
Expand All @@ -19,12 +21,12 @@ FixedPointNumbers = "0.7, 0.8"
GNSSSignals = "0.14, 0.15, 0.16"
Parameters = "0.11, 0.12"
StaticArrays = "0.9, 0.10, 0.11, 0.12, 1.0"
Unitful = "0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 1.0"
Unitful = "0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 1"
julia = "1.5"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "Suppressor"]
test = ["Test", "Suppressor"]
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# GNSSDecoder.jl
# GNSSDecoder.jl (WIP)

Decodes GPSL1 satellite signals.
This is still very much work in progress. Expect changes to this module.

## Usage

#### Install:
```julia
julia> ]
pkg> add GNSSDecoder
pkg> add git@github.com:JuliaGNSS/GNSSDecoder.jl.git
```

### Initialization
Expand Down
59 changes: 24 additions & 35 deletions src/GNSSDecoder.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ module GNSSDecoder

using DocStringExtensions, GNSSSignals, Parameters, FixedPointNumbers, StaticArrays, LinearAlgebra
using Unitful: Hz

BUFFER_LENGTH = 1502 #Size of Buffer - All 5 Subframes + the last 2 Bits are stored
SUBFRAME_LENGTH = 300 #Size of Subframes

const SUBFRAME_LENGTH = 300 # Size of Subframes
const BUFFER_LENGTH = SUBFRAME_LENGTH + 2 + 8 # 2 Bits previous subfram + 300 Bits current subframe + 8 Bits following TOW
const WORD_LENGTH = 30

export decode,
GNSSDecoderState,
Expand Down Expand Up @@ -32,58 +33,46 @@ module GNSSDecoder
$(SIGNATURES)
# Details
checks, if the buffer has the expected size of 1508 bits (length of subframe + preamble),
checks, if the buffer has the expected size of 310 bits (length of subframe + preamble + 2 prevbits),
then tries to find a preamble.
"""
function decode(dc::GNSSDecoderState, data_bits::UInt64, num_bits)


a = num_bits - dc.nb_prev
dc.nb_prev = num_bits

if a !== 0
num_bits = a
end

function decode(dc::GNSSDecoderState, data_bits::UInt64, num_bits, debug = false)

for i = num_bits - 1:-1:0

current_bit = data_bits & (1 << i)

dc.buffer = push_buffer(dc.buffer, current_bit > 0)

# * Count if Buffer is new to full stored buffer
if dc.num_bits_buffered != BUFFER_LENGTH
# Count if Buffer is new to full stored buffer
if dc.num_bits_buffered != BUFFER_LENGTH
dc.num_bits_buffered += 1
end


# * Find first preamble
if (!dc.preamble_found) && (dc.num_bits_buffered == BUFFER_LENGTH)
dc.preamble_found = find_preamble(dc.buffer)
if !isnothing(dc.data.TOW)
dc.num_bits_after_valid_subframe += 1
end

# * Begin decoding after preamble is confirmed
if dc.preamble_found

# Every time the preamble is found at the correct positions
# decode the current subframe
if dc.num_bits_buffered == BUFFER_LENGTH && find_preamble(dc.buffer)
rev_buf = reverse(dc.buffer)
words_in_subframes = map( ##Splits Buffer in Subframes and Words
subfr_it->map(
word_it->rev_buf[(word_it * 30) + 3 + (SUBFRAME_LENGTH * subfr_it):((word_it + 1) * 30 ) + 2 + (SUBFRAME_LENGTH * subfr_it)],
0:9),
0:4) # gets the words of the subframe (word length = 30)
dc.prev_29 = rev_buf[1]
dc.prev_30 = rev_buf[2]
decode_words(dc, words_in_subframes)
dc.preamble_found = false
words_in_subframe = map(word_idx -> rev_buf[word_idx * WORD_LENGTH + 3:(word_idx + 1) * WORD_LENGTH + 2], 0:9)
dc.prev_29 = rev_buf[1]
dc.prev_30 = rev_buf[2]
decode_words(dc, read_id(dc.buffer), words_in_subframe, debug)
if dc.data.integrity_status_flag == false
dc.num_bits_after_valid_subframe = 8
end
end
end # end of for-loop
end # end of decode()


include("subframe_decoding.jl")
include("find_preamble.jl")
include("decode_words.jl")
include("subframe_decoding.jl")
include("find_preamble.jl")
include("decode_words.jl")
include("parity_check.jl")
include("bin_2_dec.jl")
end# end of module
187 changes: 114 additions & 73 deletions src/decode_words.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,89 +3,94 @@ struct ParityError <: Exception
text
end


"""
Controls the Buffer for Parity Errors
Checks the Buffer for Parity Errors
$(SIGNATURES)
´dc´: decoder, struct for all ephemeris data
´words_in_subframes´: buffer of 1500 bits, sliced in 5 subframes á 300 bits, which are again sliced in 10 Words á 30 Bits
´words_in_subframe´: buffer of 310 bits, which are again sliced in 10 Words á 30 Bits and 8 Bits prev preamble
# Details
# Controls every Word for Parity Errors
# Checks every Word for Parity Errors
"""
function buffer_control(dc::GNSSDecoderState, words_in_subframes)
function check_buffer(dc::GNSSDecoderState, words_in_subframe)


parity_buffer = vcat(words_in_subframes[1],
words_in_subframes[2],
words_in_subframes[3],
words_in_subframes[4],
words_in_subframes[5])
parity_buffer = words_in_subframe

dc.data_integrity = true
for i in 1:length(parity_buffer)
if i == 1
if dc.prev_30
parity_buffer[i][1:24] = .!parity_buffer[i][1:24]
end
if parity_check(parity_buffer[i], dc.prev_29, dc.prev_30)

else
@warn("Parity Error: Word , ", i)
dc.data_integrity = false
end
else
for i in 1:length(parity_buffer)
if i != 1
dc.prev_29 = parity_buffer[i - 1][29]
dc.prev_30 = parity_buffer[i - 1][30]

if dc.prev_30
parity_buffer[i][1:24] = .!parity_buffer[i][1:24]
end
if parity_check(parity_buffer[i], dc.prev_29, dc.prev_30)
else
@warn("Parity Error: Word , ", i)
dc.data_integrity = false
end
end
if dc.prev_30
parity_buffer[i][1:24] = .!parity_buffer[i][1:24]
end
if !parity_check(parity_buffer[i], dc.prev_29, dc.prev_30)
@warn("Parity Error: Word , ", i, dc.PRN)
dc.data_integrity = false
end
end

return dc
end

"""
Checks Data for Errors (IODC and matching IODEs)
$(SIGNATURES)
´data´: Data
# Details
# Checks if IODE of subframe 1 matches the 8 LSB of th in Subframe 1 transmitted IODC
"""
Controls Data for Errors (IODC and matching IODEs)
function check_data_sub1_and_sub2(data::GPSData,
subfr_1_data::Subframe_1_Data)

has_error = !isnothing(data.IODE_Sub_2) && subfr_1_data.IODC[3:10] != data.IODE_Sub_2 ||
!isnothing(data.IODE_Sub_3) && subfr_1_data.IODC[3:10] != data.IODE_Sub_3 # IODE and the 8 LSB of IODC must match
if has_error
@info "New data required, IODC and IODE of Subframe 2 and 3 do not match (CEI data set cutover)"
end
return !has_error
end

"""
Checks Data for Errors (IODC and matching IODEs)
$(SIGNATURES)
´TLM_HOW_Data´: Data of TLM and HOW Words of last read in subframe
´subframe_1_data´: Data of Subframe 1
´subframe_2_data´: Data of Subframe 2
´subframe_3_data´: Data of Subframe 3
´data´: Data
# Details
#checks if IODE of subframe 2 and 3 matches the 8 LSB of th in Subframe 1 transmitted IODC
# Checks if IODE of subframe 2 matches the 8 LSB of th in Subframe 1 transmitted IODC
"""
function control_data(TLM_HOW_Data::TLM_HOW_Data_Struct,
subfr_1_data::Subframe_1_Data,
subfr_2_data::Subframe_2_Data,
subfr_3_data::Subframe_3_Data)
function check_data_sub2(data::GPSData,
subfr_2_data::Subframe_2_Data)

status = true
if subfr_2_data.IODE != subfr_1_data.IODC[3:10] # IODE and the 8 LSB of IODC must match
@info "new data required, IODC and IODE of Subframe 2 do not match (CEI data set cutover)"
status = false
has_error = !isnothing(data.IODC) && subfr_2_data.IODE != data.IODC[3:10] # IODE and the 8 LSB of IODC must match
if has_error
@info "New data required, IODC and IODE of Subframe 2 do not match (CEI data set cutover)"
end

return !has_error
end

if subfr_3_data.IODE != subfr_1_data.IODC[3:10] # IODE and the 8 LSB of IODC must match
@info "new data required, IODC and IODE of Subframe 3 do not match (CEI data set cutover)"
status = false
end
"""
Checks Data for Errors (IODC and matching IODEs)
$(SIGNATURES)
´data´: Data
# Details
# Checks if IODE of subframe 3 matches the 8 LSB of th in Subframe 1 transmitted IODC
"""
function check_data_sub3(data::GPSData,
subfr_3_data::Subframe_3_Data)

return status
has_error = !isnothing(data.IODC) && subfr_3_data.IODE != data.IODC[3:10] # IODE and the 8 LSB of IODC must match
if has_error
@info "New data required, IODC and IODE of Subframe 3 do not match (CEI data set cutover)"
end
return !has_error
end


Expand All @@ -95,37 +100,73 @@ end
$(SIGNATURES)
´dc´: decoder, struct for all Satellite Data
´words_in_subframes´: buffer of 1500 bits, sliced in 5 subframes á 300 bits, which are again sliced in 10 Words á 30 Bits
´words_in_subframe´: buffer of 310 bits, which are again sliced in 10 Words á 30 Bits and 8 Bits prev preamble
# Details
# Decodes complete subframe from the buffer, saves data for position computing in ´dc.data´. It returns the decoder, ´dc´.
#The number of saved Bits is resetted to 2 due to the Buffer length of 1502. Those 2 Bits will be the previous 2 Bits to the next 5 Subframes.
# The number of saved Bits is resetted to 10 due to the Buffer length of 308. Those 10 Bits will be the previous 2 Bits + 8 Bits TOW.
"""
function decode_words(dc::GNSSDecoderState, words_in_subframes)
function decode_words(dc::GNSSDecoderState, subframe_id, words_in_subframe, debug)

dc = buffer_control(dc, words_in_subframes)
dc = check_buffer(dc, words_in_subframe)
if dc.data_integrity == true
TLM_HOW, subframe_1_data = decode_subframe_1(words_in_subframes[1])
dc.subframes_decoded[1] = true
TLM_HOW, subframe_2_data = decode_subframe_2(words_in_subframes[2])
dc.subframes_decoded[2] = true
TLM_HOW, subframe_3_data = decode_subframe_3(words_in_subframes[3])
dc.subframes_decoded[3] = true
TLM_HOW = decode_subframe_4(words_in_subframes[4])
dc.subframes_decoded[4] = true
TLM_HOW = decode_subframe_5(words_in_subframes[5])
dc.subframes_decoded[5] = true


if control_data(TLM_HOW, subframe_1_data, subframe_2_data, subframe_3_data) # Checks for Data Errors
data = create_data(TLM_HOW, subframe_1_data, subframe_2_data, subframe_3_data) # Creates GPSData from single, subframe specific data and the TLM Word
dc.data = data
println(" DECODING COMPLETED!")
prev_subframes_decoded = copy(dc.subframes_decoded)
if subframe_id == 1
TLM_HOW, subframe_1_data = decode_subframe_1(words_in_subframe, debug)
dc.data = GPSData(dc.data, subframe_1_data)
dc.data = GPSData(dc.data, TLM_HOW)
are_correct = check_data_sub1_and_sub2(dc.data, subframe_1_data)
dc.subframes_decoded[1] = true
dc.subframes_decoded[2] = dc.subframes_decoded[2] && are_correct
dc.subframes_decoded[3] = dc.subframes_decoded[3] && are_correct
if debug
println("DECODED SUB1!")
end
elseif subframe_id == 2
TLM_HOW, subframe_2_data = decode_subframe_2(words_in_subframe, debug)
is_correct = check_data_sub2(dc.data, subframe_2_data)
dc.subframes_decoded[2] = is_correct
if is_correct
dc.data = GPSData(dc.data, subframe_2_data)
dc.data = GPSData(dc.data, TLM_HOW)
if debug
println("DECODED SUB2!")
end
end
elseif subframe_id == 3
TLM_HOW, subframe_3_data = decode_subframe_3(words_in_subframe, debug)
is_correct = check_data_sub3(dc.data, subframe_3_data)
dc.subframes_decoded[3] = is_correct
if is_correct
dc.data = GPSData(dc.data, subframe_3_data)
dc.data = GPSData(dc.data, TLM_HOW)
if debug
println("DECODED SUB3!")
end
end
elseif subframe_id == 4
TLM_HOW = decode_subframe_4(words_in_subframe, debug)
dc.subframes_decoded[4] = true
dc.data = GPSData(dc.data, TLM_HOW)
if debug
println("DECODED SUB4!")
end
elseif subframe_id == 5
TLM_HOW = decode_subframe_5(words_in_subframe, debug)
dc.data = GPSData(dc.data, TLM_HOW)
dc.subframes_decoded[5] = true
if debug
println("DECODED SUB5!")
end
end

if prev_subframes_decoded != dc.subframes_decoded == [true, true, true, true, true] && debug
println("PRN",dc.PRN," DATA COMPLETED OR RENEWED!")
end
end

dc.num_bits_buffered = 2 # Due to Buffer length of 1502 and the need to save the last two bits, only 1500 Bits have to been read in the next loop.
dc.num_bits_buffered = 10 # Due to Buffer length of 1502 and the need to save the last ten bits, only 1500 Bits have to been read in the next loop.
return dc
end

Loading

2 comments on commit 8550134

@zsoerenm
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register()

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/53279

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.0.1 -m "<description of version>" 8550134798166cda2da51ac8da14d64a65465f2b
git push origin v0.0.1

Please sign in to comment.