Skip to content

Encoder

Class representing encoder.

Attributes:

Name Type Description
pi_max_il NDArray[uint8]

Vector representing fixed interleaving pattern table.

Q NDArray[uint16]

Vector where indexes represent realiabilities and values represent polar sequence.

Methods:

Name Description
determine_n

The purpose of this function is to determine n.

interleave

Function is doing interleaving to distribute errors on the output of decoder and increase efficiency of coding.

encode

Function for encoding using polar code, function does not anticipate the presence of parity bits in message.

Source code in src\encoder.py
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
class Encoder:
    """
    Class representing encoder.

    Attributes
    ----------
    pi_max_il : NDArray[np.uint8]
        Vector representing fixed interleaving pattern table.
    Q : NDArray[np.uint16]
        Vector where indexes represent realiabilities and values represent polar sequence.

    Methods
    -------
    determine_n(K, E, n_max)
        The purpose of this function is to determine n.
    interleave(K, i_il, pi_max_il)
        Function is doing interleaving to distribute errors on the output of decoder and increase efficiency of coding.
    encode(msg)
        Function for encoding using polar code, function does not anticipate the presence of parity bits in message.
    """

    def __init__(self, pi_max_il: NDArray[np.uint8], Q: NDArray[np.uint16]):
        """
        Inicjalizacja enkodera.

        Parameters
        ----------
        pi_max_il : NDArray[np.uint8]
            Vector representing fixed interleaving pattern table.

        Q : NDArray[np.uint16]
            Vector where indexes represent reliabilities and values represent polar sequence.
        """

        self.pi_max_il = pi_max_il
        self.Q = Q


    def determine_n(self, K: int, E: int, n_max: int) -> int:
        """ 
        The bit sequence input for a given code block to channel coding is denoted by c[0], c[1], c[2], c[3], ..., c[K-1] where K is the
        number of bits to encode. After encoding the bits are denoted by d[0], d[1], d[2], ..., d[N-1], where N = 2^n and the purpose of 
        this function is to determine n.

        Parameters
        ----------
        K : int
            Number of bits in input bit sequence.
        E : int
            Rate matching output length. It is stated by the higher layers (MAC, scheduler) before channel encoding - in the transmission planning phase.
        n_max : int
            In polar encoding is the maximum exponent of 2 for the encoded block length N. It limits how large a single block can be. In 5G NR for user data: n_max = 11, for control info: n_max = 9.

        Returns
        -------
        int
            The predcited n.
        """

        if E < K:
            raise ValueError(f"E = {E} is less than K = {K}: too few bits to hold the information")
        if E > 2**n_max:
            raise ValueError(f"E = {E} exceeds maximum block length 2**{n_max} = {2**n_max}")

        if ( E <= (9/8) * pow(2, ceil(log2(E))-1) ) and ( (K / E) < 9/16 ):
            n1 = ceil(log2(E)) - 1
        else:
            n1 = ceil(log2(E))

        R_min = 1/8
        n2 = ceil(log2(K / R_min))

        n_min = 5 # default is 5 
        n = max(min(n1, n2, n_max), n_min)

        return n


    def interleave(self, K: int, i_il: bool, pi_max_il: NDArray[np.uint8]) -> NDArray[np.uint8]:
        """
        Function is doing interleaving to distribute errors on the output of decoder and increase efficiency of coding.

        Parameters
        ----------
        K : int
            Number of bits in input bit sequence.
        i_il : bool
            When set to False no interleaving is occuring.
        pi_max_il : NDArray[np.uint8]
            Representing fixed interleaving pattern (table) stated in 5G standard.

        Returns
        -------
        NDArray[np.uint8]
            The created interleaving pattern.
        """

        K_max_il = pi_max_il.size     # number of entries in table of fixed interleaving pattern
        pi = np.empty(K, dtype=np.uint8)

        if not i_il:
            pi = np.arange(K, dtype=np.uint8)
        else:
            k = 0
            for m in range(K_max_il):
                if pi_max_il[m] >= K_max_il - K:
                    pi[k] = pi_max_il[m] - (K_max_il - K)
                    k += 1

        return pi


    def encode(self, msg: NDArray[np.uint8], E: int) -> NDArray[np.uint8]:
        """
        Function for encoding using polar code, function does not anticipate the presence of parity bits in message.

        Parameters
        ----------
        msg : NDArray[np.uint8]
            Message bits sequence to be encoded.
        E : int
            Rate matching output length. It is stated by the higher layers (MAC, scheduler) before channel encoding - in the transmission planning phase.

        Returns
        -------
        NDArray[np.uint8]
            Encoded bits sequence.
        """

        K = msg.size
        n = self.determine_n(K=K, E=E, n_max=9)
        N = pow(2, n)

        # permutation_pattern = self.interleave(K=K, i_il=False, pi_max_il=self.pi_max_il)
        Q = self.Q[self.Q < N]
        #frozen_bits_idxes = Q[:N-K]
        message_bits_idxes = Q[N-K:]
        u = np.zeros(N, dtype=np.uint8)
        u[message_bits_idxes] = msg

        k = 1
        while k < N:
            for i in range(0, N, 2*k):
                u[i:i+k] = np.mod(u[i:i+k] + u[i+k:i+2*k], 2)
            k *= 2

        return u

__init__(pi_max_il, Q)

Inicjalizacja enkodera.

Parameters:

Name Type Description Default
pi_max_il NDArray[uint8]

Vector representing fixed interleaving pattern table.

required
Q NDArray[uint16]

Vector where indexes represent reliabilities and values represent polar sequence.

required
Source code in src\encoder.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def __init__(self, pi_max_il: NDArray[np.uint8], Q: NDArray[np.uint16]):
    """
    Inicjalizacja enkodera.

    Parameters
    ----------
    pi_max_il : NDArray[np.uint8]
        Vector representing fixed interleaving pattern table.

    Q : NDArray[np.uint16]
        Vector where indexes represent reliabilities and values represent polar sequence.
    """

    self.pi_max_il = pi_max_il
    self.Q = Q

determine_n(K, E, n_max)

The bit sequence input for a given code block to channel coding is denoted by c[0], c[1], c[2], c[3], ..., c[K-1] where K is the number of bits to encode. After encoding the bits are denoted by d[0], d[1], d[2], ..., d[N-1], where N = 2^n and the purpose of this function is to determine n.

Parameters:

Name Type Description Default
K int

Number of bits in input bit sequence.

required
E int

Rate matching output length. It is stated by the higher layers (MAC, scheduler) before channel encoding - in the transmission planning phase.

required
n_max int

In polar encoding is the maximum exponent of 2 for the encoded block length N. It limits how large a single block can be. In 5G NR for user data: n_max = 11, for control info: n_max = 9.

required

Returns:

Type Description
int

The predcited n.

Source code in src\encoder.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
def determine_n(self, K: int, E: int, n_max: int) -> int:
    """ 
    The bit sequence input for a given code block to channel coding is denoted by c[0], c[1], c[2], c[3], ..., c[K-1] where K is the
    number of bits to encode. After encoding the bits are denoted by d[0], d[1], d[2], ..., d[N-1], where N = 2^n and the purpose of 
    this function is to determine n.

    Parameters
    ----------
    K : int
        Number of bits in input bit sequence.
    E : int
        Rate matching output length. It is stated by the higher layers (MAC, scheduler) before channel encoding - in the transmission planning phase.
    n_max : int
        In polar encoding is the maximum exponent of 2 for the encoded block length N. It limits how large a single block can be. In 5G NR for user data: n_max = 11, for control info: n_max = 9.

    Returns
    -------
    int
        The predcited n.
    """

    if E < K:
        raise ValueError(f"E = {E} is less than K = {K}: too few bits to hold the information")
    if E > 2**n_max:
        raise ValueError(f"E = {E} exceeds maximum block length 2**{n_max} = {2**n_max}")

    if ( E <= (9/8) * pow(2, ceil(log2(E))-1) ) and ( (K / E) < 9/16 ):
        n1 = ceil(log2(E)) - 1
    else:
        n1 = ceil(log2(E))

    R_min = 1/8
    n2 = ceil(log2(K / R_min))

    n_min = 5 # default is 5 
    n = max(min(n1, n2, n_max), n_min)

    return n

encode(msg, E)

Function for encoding using polar code, function does not anticipate the presence of parity bits in message.

Parameters:

Name Type Description Default
msg NDArray[uint8]

Message bits sequence to be encoded.

required
E int

Rate matching output length. It is stated by the higher layers (MAC, scheduler) before channel encoding - in the transmission planning phase.

required

Returns:

Type Description
NDArray[uint8]

Encoded bits sequence.

Source code in src\encoder.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
def encode(self, msg: NDArray[np.uint8], E: int) -> NDArray[np.uint8]:
    """
    Function for encoding using polar code, function does not anticipate the presence of parity bits in message.

    Parameters
    ----------
    msg : NDArray[np.uint8]
        Message bits sequence to be encoded.
    E : int
        Rate matching output length. It is stated by the higher layers (MAC, scheduler) before channel encoding - in the transmission planning phase.

    Returns
    -------
    NDArray[np.uint8]
        Encoded bits sequence.
    """

    K = msg.size
    n = self.determine_n(K=K, E=E, n_max=9)
    N = pow(2, n)

    # permutation_pattern = self.interleave(K=K, i_il=False, pi_max_il=self.pi_max_il)
    Q = self.Q[self.Q < N]
    #frozen_bits_idxes = Q[:N-K]
    message_bits_idxes = Q[N-K:]
    u = np.zeros(N, dtype=np.uint8)
    u[message_bits_idxes] = msg

    k = 1
    while k < N:
        for i in range(0, N, 2*k):
            u[i:i+k] = np.mod(u[i:i+k] + u[i+k:i+2*k], 2)
        k *= 2

    return u

interleave(K, i_il, pi_max_il)

Function is doing interleaving to distribute errors on the output of decoder and increase efficiency of coding.

Parameters:

Name Type Description Default
K int

Number of bits in input bit sequence.

required
i_il bool

When set to False no interleaving is occuring.

required
pi_max_il NDArray[uint8]

Representing fixed interleaving pattern (table) stated in 5G standard.

required

Returns:

Type Description
NDArray[uint8]

The created interleaving pattern.

Source code in src\encoder.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
def interleave(self, K: int, i_il: bool, pi_max_il: NDArray[np.uint8]) -> NDArray[np.uint8]:
    """
    Function is doing interleaving to distribute errors on the output of decoder and increase efficiency of coding.

    Parameters
    ----------
    K : int
        Number of bits in input bit sequence.
    i_il : bool
        When set to False no interleaving is occuring.
    pi_max_il : NDArray[np.uint8]
        Representing fixed interleaving pattern (table) stated in 5G standard.

    Returns
    -------
    NDArray[np.uint8]
        The created interleaving pattern.
    """

    K_max_il = pi_max_il.size     # number of entries in table of fixed interleaving pattern
    pi = np.empty(K, dtype=np.uint8)

    if not i_il:
        pi = np.arange(K, dtype=np.uint8)
    else:
        k = 0
        for m in range(K_max_il):
            if pi_max_il[m] >= K_max_il - K:
                pi[k] = pi_max_il[m] - (K_max_il - K)
                k += 1

    return pi