Note

This static document was automatically created from the output of a jupyter notebook.

Execute and modify the notebook online here.

# Implementing FEC codings

This Jupyter notebook will outline the step-by-step process of implementing a new coding scheme for the forward error correction in communication modems. The selected algorithm is a repetition encoder, since it is arguably the most basic error correction coding.

As an initial step, we will import all required modules from HermesPy:

[1]:

%%capture
pip install hermespy

[2]:

import numpy as np
from hermespy.fec import Encoder


Error correcting coding steps are represented by the abstract Encoder interface. Each coding algorithm is represented by a class inheriting from the interface, which requires them to implement the abstract functions and properties

Let’s assume our repetition coding takes blocks of $$K = 4$$ data bits and repeats them $$3$$ times. The resulting code block size would be $$N = 3K = 12$$, which results in a rate of $$\mathbf{R} = \frac{K}{N} = \frac{1}{3}$$ for the full encoding. During decoding, the repetition coding decides by majority voting which bit has been transmitted. So, our coding implementation is

[3]:

class RepetitionCoding(Encoder):

@property
def bit_block_size(self) -> int:
return 4

@property
def code_block_size(self) -> int:
return 12

def encode(self, data: np.ndarray) -> np.ndarray:
return np.tile(data, 3)

def decode(self, code: np.ndarray) -> np.ndarray:
return (np.mean(np.reshape(code, (3, self.bit_block_size)), axis=0, keepdims=False) > .5).astype(int)


Now we can inspect our coding implementation:

[4]:

coding = RepetitionCoding()
print(f"Our coding rate is {coding.rate} with an input block size of {coding.bit_block_size} and an output block size of {coding.code_block_size}")

data = np.random.randint(0, 2, coding.bit_block_size)
print(f"Let's assume we transmit the following data block: {data}")

code = coding.encode(data)
print(f"After encoding the respective code block is: {code}")

error_code = code.copy()
error_code[0] = not error_code[0]
print(f"After channel propagation the first bit has flipped: {error_code}")

corrected_data = coding.decode(error_code)
print(f"But the coding can correct a single bit flip to: {corrected_data}")

Our coding rate is 0.3333333333333333 with an input block size of 4 and an output block size of 12
Let's assume we transmit the following data block: [0 0 0 0]
After encoding the respective code block is: [0 0 0 0 0 0 0 0 0 0 0 0]
After channel propagation the first bit has flipped: [1 0 0 0 0 0 0 0 0 0 0 0]
But the coding can correct a single bit flip to: [0 0 0 0]


We may now investigate our newly created forward error correction coding within a full Hermes simulation capaign.

[6]:

from hermespy.simulation import Simulation
from hermespy.modem import BitErrorEvaluator, DuplexModem, RootRaisedCosineWaveform

# Create a new simulation featuring a single device transmitting at 10GHz
simulation = Simulation()
device = simulation.scenario.new_device()
device.carrier_frequency = 10e9

# Configure a communication operation on the device, using our coding
modem = DuplexModem()
modem.waveform_generator = RootRaisedCosineWaveform(modulation_order=4, oversampling_factor=2, num_preamble_symbols=0, num_data_symbols=10, symbol_rate=1e6)
modem.device = device

# Run a very low-demanding simulation for demonstration purposes
simulation.new_dimension('snr', np.linspace(2, .1, 20))
simulation.min_num_samples, simulation.num_samples = 1000, 1000
simulation.num_actors = 1
result = simulation.run()

──────────────────────────────────── Simulation Campaign ────────────────────────────────────

[16:30:28] Launched simulation campaign with 1 dedicated actors           monte_carlo.py:1672

           Generating a maximum of 20000 = 1000 x 20 samples inspected by monte_carlo.py:1692
1 evaluators


Simulation Grid
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Dimension ┃ Sections                                                                      ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ snr       │ 2.00 1.90 1.80 1.70 1.60 1.50 1.40 1.30 1.20 1.10 1.00 0.90 0.80 0.70 0.60    │
│           │ 0.50 0.40 0.30 0.20 0.10                                                      │
└───────────┴───────────────────────────────────────────────────────────────────────────────┘

[16:30:49] Simulation finished after 21.17 seconds                        monte_carlo.py:1832


This allows us to visualize the achieved bit error rates for given linear signal to noise ratios:

[ ]:

_ = result.plot()