Skip to content

Commit

Permalink
Subframewise decoding (#2)
Browse files Browse the repository at this point in the history
* subframewise decoding implemented

* Adapted the tests for the new decoding.

* cleaned the code with new GPSData constructors

* Allows to decode subframe 2 and 3 before subframe 1 is decoded

* Removed data_next as it is not needed anymore

* Make test runnable

* Removed some unused fields in GNSSDecoderState

* Added num_bits_after_valid_subframe

* Num bits after valid subframe must start with 8 because of second preamble

Co-authored-by: Karim El Isa <ke902320@fh-muenster.de>
Co-authored-by: Soeren Schoenbrod <soeren.schoenbrod@rwth-aachen.de>
  • Loading branch information
3 people authored Jan 27, 2022
1 parent 235b410 commit ddb9474
Show file tree
Hide file tree
Showing 9 changed files with 455 additions and 392 deletions.
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

0 comments on commit ddb9474

Please sign in to comment.