Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add NRZI encoding decoding #12

Merged
merged 6 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion docs/make.jl
Copy link
Member

Choose a reason for hiding this comment

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

Ok for this !

Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
push!(LOAD_PATH, "../src/")

using Documenter, DigitalComm
using Documenter

# Running `julia --project docs/make.jl` can be very slow locally.
# To speed it up during development, one can use make_local.jl instead.
# The code below checks whether it's being called from make_local.jl or not.
const LOCAL = get(ENV, "LOCAL", "false") == "true"

if LOCAL
include("../src/DigitalComm.jl")
using .DigitalComm
else
using DigitalComm
ENV["GKSwstype"] = "100" # Prevents warnings in the doc build on github actions.
end

DocMeta.setdocmeta!(DigitalComm, :DocTestSetup, :(using DigitalComm); recursive=true)

Expand Down
9 changes: 9 additions & 0 deletions docs/make_local.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Assumes it's being run from project root.

using Pkg
Pkg.activate("docs/")
Pkg.instantiate()

ENV["LOCAL"] = "true"

include("make.jl")
10 changes: 10 additions & 0 deletions docs/src/base.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Function overview

## Common functions

```@autodocs
Expand All @@ -6,6 +8,14 @@ Pages = ["DigitalComm.jl"]
Order = [:function, :type]
```

## NRZI Encoding

```@autodocs
Modules = [DigitalComm]
Pages = ["NRZI.jl"]
Order = [:function, :type]
```

## Quadrature Amplitude Modulation

```@autodocs
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Currently, the package support the following elements
- Bit manipulation
- Generation of random binary sequence
- Conversion between binary sequences and octal sequences
- Non Return to Zero Inverted (NRZI) encoding and decoding
- Modulation // demodulation
- Quadrature Amplitude Modulation (QAM) with 4-QAM (QPSK), 16-QAM, 64-QAM and 256-QAM.
- Hard demapper for the x-QAM formats
Expand Down
4 changes: 4 additions & 0 deletions src/DigitalComm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export genByteSequence! , genByteSequence;
include("bitMapping.jl");
export bitMappingQAM! , bitMappingQAM;

include("NRZI.jl");
export encodeNRZI , decodeNRZI;
export encodeNRZI! , decodeNRZI!;

# --- QAM Hard demapper
include("bitDeMapping.jl");
export bitDemappingQAM! , bitDemappingQAM;
Expand Down
113 changes: 113 additions & 0 deletions src/NRZI.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
encodeNRZI(bits::AbstractVector, transitions::Symbol=:low)::AbstractVector

Map a bit sequence to Non-Return-to-Zero Inverted (NRZI) encoded bits.
Expects a vector of bits, e.g. `[0, 1, 1, 0, 0, 1, 0, 1, 0, 1]`.

# Arguments

- `bits::AbstractVector`: Vector of bits to encode.
- `transitions::Symbol`: Symbol indicating the symbol to transition on (`:low`/`:high`). Defaults to `:low`.

# Returns

- `encoded_bits::AbstractVector`: Vector of encoded bits.

# Examples

```jldoctest
julia> encoded_bits = encodeNRZI(Int32[0, 1, 1, 0, 0, 1], :low);

julia> transpose(encoded_bits)
1×6 transpose(::Vector{Int32}) with eltype Int32:
1 1 1 0 1 1
```

The example below shows how the `transitions` argument affects the encoded bit sequence.

```jldoctest
julia> encoded_bits = encodeNRZI(Int32[0, 1, 1, 0, 0, 1], :high);

julia> transpose(encoded_bits)
1×6 transpose(::Vector{Int32}) with eltype Int32:
0 1 0 0 0 1
```
"""
function encodeNRZI(bits::AbstractVector, transitions::Symbol=:low)::AbstractVector
encoded_bits = similar(bits)
encodeNRZI!(encoded_bits,bits,transitions)
return encoded_bits
end

function encodeNRZI!(encoded_bits::AbstractVector,bits::AbstractVector,transitions::Symbol=:low)
@assert size(encoded_bits) == size(bits) "With NRZI encoding, input and output should have same size ($(size(encoded_bits)) ≂̸ $(size(bits))"
last_bit = 0
transition_bit = (transitions == :high) ? 1 : 0
for n ∈ eachindex(bits)
if bits[n] == transition_bit
last_bit = last_bit ⊻ 1
end
encoded_bits[n] = last_bit
end
return nothing
end

"""
decodeNRZI(bits::AbstractVector, transitions::Symbol=:low)::AbstractVector

Decode a Non-Return-to-Zero Inverted (NRZI) encoded bit sequence.
Expects a vector of bits, e.g. `[0, 1, 1, 0, 0, 1, 0, 1, 0, 1]`.

# Arguments

- `bits::AbstractVector`: Vector of bits to encode.
- `transitions::Symbol`: Symbol represented by a transition in the NRZI coded sequence (`:low`/`:high`). Defaults to `:low`.

# Returns

- `decoded_bits::AbstractVector`: Vector of decoded bits. The first bit of the output depends on a value of a memory bit in the decoder.
this value is set to `0`.

# Examples

```jldoctest
julia> decoded_bits = decodeNRZI(Int32[1, 1, 1, 0, 1, 1], :low);

julia> transpose(decoded_bits)
1×6 transpose(::Vector{Int32}) with eltype Int32:
0 1 1 0 0 1
```

The example below shows how the `transitions` argument affects the decoded bit sequence.

```jldoctest
julia> decoded_bits = decodeNRZI(Int32[0, 1, 0, 0, 0, 1], :high);

julia> transpose(decoded_bits)
1×6 transpose(::Vector{Int32}) with eltype Int32:
0 1 1 0 0 1
```
"""
function decodeNRZI(encoded_bits::AbstractVector, transitions::Symbol=:low)::AbstractVector
decoded_bits = similar(encoded_bits)
decodeNRZI!(decoded_bits,encoded_bits,transitions)
return decoded_bits
end


function decodeNRZI!(decoded_bits::AbstractVector,encoded_bits::AbstractVector, transitions::Symbol=:low)
@assert size(encoded_bits) == size(decoded_bits) "With NRZI encoding, input and output should have same size ($(size(decoded_bits)) ≂̸ $(size(encoded_bits))"
last_bit = 0
transition_bit = (transitions == :high) ? 1 : 0
for n ∈ eachindex(encoded_bits)
current_bit = encoded_bits[n]
if current_bit != last_bit
decoded_bit = transition_bit
else
decoded_bit = 1 - transition_bit
end
last_bit = current_bit
decoded_bits[n] = decoded_bit
end
return nothing
end
3 changes: 3 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ include("test_bitMapping.jl");
include("test_bitDemapping.jl");
include("test_hardConstellation.jl");

# NRZI Mapping
include("test_nrzi.jl");

# Symbol demapper
include("test_symbolDemapper.jl");

Expand Down
29 changes: 29 additions & 0 deletions test/test_nrzi.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# ----------------------------------------------------
# --- Import modules
# ----------------------------------------------------
using DigitalComm
using Test
# ----------------------------------------------------
# --- Tests
# ----------------------------------------------------
# Note --> The mapping system is described in bitMapping.jl
println("Tests for symbol mapper with NRZI sequences");

@testset "NRZI" begin
# Create a bit squence (already tested)
nbBits = 2 * 2048;
bitSeq = genBitSequence(nbBits);
# Pass trough the function
buff = zeros(Complex{Float64},nbBits)
# Call
encodeNRZI!(buff,bitSeq);
buff2 = encodeNRZI(bitSeq);
@test all( buff .== buff2)
# Ensure Tx // Rx is Ok
@test all(bitSeq .== decodeNRZI(encodeNRZI(bitSeq)))
@test all(bitSeq .== decodeNRZI(encodeNRZI(bitSeq,:high),:high))
# Some manual check for both transitions
buff = [0x01;0x00;0x00;0x01;0x00;0x00;0x00;0x01 ];
@test all( encodeNRZI(buff,:low) .== [0;1;0;0;1;0;1;1]) # Transitions on 0
@test all( encodeNRZI(buff,:high) .== [1;1;1;0;0;0;0;1]) # Transitions on 1
end
Loading