def conv_encode(message_bits, trellis, termination = 'term', puncture_matrix=None): """ Encode bits using a convolutional code. Parameters ---------- message_bits : 1D ndarray containing {0, 1} Stream of bits to be convolutionally encoded. trellis: pre-initialized Trellis structure. termination: {'cont', 'term'}, optional Create ('term') or not ('cont') termination bits. puncture_matrix: 2D ndarray containing {0, 1}, optional Matrix used for the puncturing algorithm Returns ------- coded_bits : 1D ndarray containing {0, 1} Encoded bit stream. """ k = trellis.k n = trellis.n total_memory = trellis.total_memory rate = float(k)/n code_type = trellis.code_type if puncture_matrix is None: puncture_matrix = np.ones((trellis.k, trellis.n)) number_message_bits = np.size(message_bits) if termination == 'cont': inbits = message_bits number_inbits = number_message_bits number_outbits = int(number_inbits/rate) else: # Initialize an array to contain the message bits plus the truncation zeros if code_type == 'rsc': inbits = message_bits number_inbits = number_message_bits number_outbits = int((number_inbits + k * total_memory)/rate) else: number_inbits = number_message_bits + total_memory + total_memory % k inbits = np.zeros(number_inbits, 'int') # Pad the input bits with M zeros (L-th terminated truncation) inbits[0:number_message_bits] = message_bits number_outbits = int(number_inbits/rate) outbits = np.zeros(number_outbits, 'int') if puncture_matrix is not None: p_outbits = np.zeros(number_outbits, 'int') else: p_outbits = np.zeros(int(number_outbits* puncture_matrix[0:].sum()/np.size(puncture_matrix, 1)), 'int') next_state_table = trellis.next_state_table output_table = trellis.output_table # Encoding process - Each iteration of the loop represents one clock cycle current_state = 0 j = 0 for i in range(int(number_inbits/k)): # Loop through all input bits current_input = bitarray2dec(inbits[i*k:(i+1)*k]) current_output = output_table[current_state][current_input] outbits[j*n:(j+1)*n] = dec2bitarray(current_output, n) current_state = next_state_table[current_state][current_input] j += 1 if code_type == 'rsc' and termination == 'term': term_bits = dec2bitarray(current_state, trellis.total_memory) term_bits = term_bits[::-1] for i in range(trellis.total_memory): current_input = bitarray2dec(term_bits[i*k:(i+1)*k]) current_output = output_table[current_state][current_input] outbits[j*n:(j+1)*n] = dec2bitarray(current_output, n) current_state = next_state_table[current_state][current_input] j += 1 j = 0 for i in range(number_outbits): if puncture_matrix[0][i % np.size(puncture_matrix, 1)] == 1: p_outbits[j] = outbits[i] j = j + 1 return p_outbits
def _acs_traceback(r_codeword, trellis, decoding_type, path_metrics, paths, decoded_symbols, decoded_bits, tb_count, t, count, tb_depth, current_number_states): k = trellis.k n = trellis.n number_states = trellis.number_states number_inputs = trellis.number_inputs branch_metric = 0.0 next_state_table = trellis.next_state_table output_table = trellis.output_table pmetrics = np.empty(number_inputs) index_array = np.empty([number_states, 2], 'int') # Loop over all the current states (Time instant: t) for state_num in range(current_number_states): # Using the next state table find the previous states and inputs # leading into the current state (Trellis) number_found = _where_c(next_state_table, number_states, number_inputs, state_num, index_array) # Loop over all the previous states (Time instant: t-1) for i in range(number_found): previous_state = index_array[i, 0] previous_input = index_array[i, 1] # Using the output table, find the ideal codeword i_codeword = output_table[previous_state, previous_input] i_codeword_array = dec2bitarray(i_codeword, n) # Compute Branch Metrics if decoding_type == 'hard': branch_metric = hamming_dist(r_codeword.astype(int), i_codeword_array.astype(int)) elif decoding_type == 'soft': neg_LL_0 = np.log(np.exp(r_codeword) + 1) # negative log-likelihood to have received a 0 neg_LL_1 = neg_LL_0 - r_codeword # negative log-likelihood to have received a 1 branch_metric = np.where(i_codeword_array, neg_LL_1, neg_LL_0).sum() elif decoding_type == 'unquantized': i_codeword_array = 2*i_codeword_array - 1 branch_metric = euclid_dist(r_codeword, i_codeword_array) # ADD operation: Add the branch metric to the # accumulated path metric and store it in the temporary array pmetrics[i] = path_metrics[previous_state, 0] + branch_metric # COMPARE and SELECT operations # Compare and Select the minimum accumulated path metric path_metrics[state_num, 1] = pmetrics.min() # Store the previous state corresponding to the minimum # accumulated path metric min_idx = pmetrics.argmin() paths[state_num, tb_count] = index_array[min_idx, 0] # Store the previous input corresponding to the minimum # accumulated path metric decoded_symbols[state_num, tb_count] = index_array[min_idx, 1] if t >= tb_depth - 1: current_state = path_metrics[:,1].argmin() # Traceback Loop for j in reversed(range(1, tb_depth)): dec_symbol = decoded_symbols[current_state, j] previous_state = paths[current_state, j] decoded_bitarray = dec2bitarray(dec_symbol, k) decoded_bits[t - tb_depth + 1 + (j - 1) * k + count:t - tb_depth + 1 + j * k + count] = decoded_bitarray current_state = previous_state paths[:,0:tb_depth-1] = paths[:,1:] decoded_symbols[:,0:tb_depth-1] = decoded_symbols[:,1:]
def __init__(self, memory, g_matrix, feedback=None, code_type='default', polynomial_format='MSB'): [self.k, self.n] = g_matrix.shape self.code_type = code_type self.total_memory = memory.sum() self.number_states = pow(2, self.total_memory) self.number_inputs = pow(2, self.k) self.next_state_table = np.zeros([self.number_states, self.number_inputs], 'int') self.output_table = np.zeros([self.number_states, self.number_inputs], 'int') if isinstance(feedback, int): warn('Trellis will only accept feedback as a matrix in the future. ' 'Using the backwards compatibility version that may contain bugs for k > 1 or with LSB format.', DeprecationWarning) if code_type == 'rsc': for i in range(self.k): g_matrix[i][i] = feedback # Compute the entries in the next state table and the output table for current_state in range(self.number_states): for current_input in range(self.number_inputs): outbits = np.zeros(self.n, 'int') # Compute the values in the output_table for r in range(self.n): output_generator_array = np.zeros(self.k, 'int') shift_register = dec2bitarray(current_state, self.total_memory) for l in range(self.k): # Convert the number representing a polynomial into a # bit array generator_array = dec2bitarray(g_matrix[l][r], memory[l] + 1) # Loop over M delay elements of the shift register # to compute their contribution to the r-th output for i in range(memory[l]): outbits[r] = (outbits[r] + \ (shift_register[i + l] * generator_array[i + 1])) % 2 output_generator_array[l] = generator_array[0] if l == 0: feedback_array = (dec2bitarray(feedback, memory[l] + 1)[1:] * shift_register[0:memory[l]]).sum() shift_register[1:memory[l]] = \ shift_register[0:memory[l] - 1] shift_register[0] = (dec2bitarray(current_input, self.k)[0] + feedback_array) % 2 else: feedback_array = (dec2bitarray(feedback, memory[l] + 1) * shift_register[ l + memory[l - 1] - 1:l + memory[l - 1] + memory[l] - 1]).sum() shift_register[l + memory[l - 1]:l + memory[l - 1] + memory[l] - 1] = \ shift_register[l + memory[l - 1] - 1:l + memory[l - 1] + memory[l] - 2] shift_register[l + memory[l - 1] - 1] = \ (dec2bitarray(current_input, self.k)[l] + feedback_array) % 2 # Compute the contribution of the current_input to output outbits[r] = (outbits[r] + \ (np.sum(dec2bitarray(current_input, self.k) * \ output_generator_array + feedback_array) % 2)) % 2 # Update the ouput_table using the computed output value self.output_table[current_state][current_input] = \ bitarray2dec(outbits) # Update the next_state_table using the new state of # the shift register self.next_state_table[current_state][current_input] = \ bitarray2dec(shift_register) else: if polynomial_format == 'MSB': bit_order = -1 elif polynomial_format in ('LSB', 'Matlab'): bit_order = 1 else: raise ValueError('polynomial_format must be "LSB", "MSB" or "Matlab"') if feedback is None: feedback = np.identity(self.k, int) if polynomial_format in ('LSB', 'Matlab'): feedback *= 2**memory.max() max_values_lign = memory.max() + 1 # Max number of value on a delay lign # feedback_array[i] holds the i-th bit corresponding to each feedback polynomial. feedback_array = np.zeros((max_values_lign, self.k, self.k), np.int8) for i in range(self.k): for j in range(self.k): binary_view = dec2bitarray(feedback[i, j], max_values_lign)[::bit_order] feedback_array[:max_values_lign, i, j] = binary_view[-max_values_lign-2:] # g_matrix_array[i] holds the i-th bit corresponding to each g_matrix polynomial. g_matrix_array = np.zeros((max_values_lign, self.k, self.n), np.int8) for i in range(self.k): for j in range(self.n): binary_view = dec2bitarray(g_matrix[i, j], max_values_lign)[::bit_order] g_matrix_array[:max_values_lign, i, j] = binary_view[-max_values_lign-2:] # shift_regs holds on each column the state of a shift register. # The first row is the input of each shift reg. shift_regs = np.empty((max_values_lign, self.k), np.int8) # Compute the entries in the next state table and the output table for current_state in range(self.number_states): for current_input in range(self.number_inputs): current_state_array = dec2bitarray(current_state, self.total_memory) # Set the first row as the input. shift_regs[0] = dec2bitarray(current_input, self.k) # Set the other rows based on the current_state idx = 0 for idx_mem, mem in enumerate(memory): shift_regs[1:mem+1, idx_mem] = current_state_array[idx:idx + mem] idx += mem # Compute the output table outputs_array = np.einsum('ik,ikl->l', shift_regs, g_matrix_array) % 2 self.output_table[current_state, current_input] = bitarray2dec(outputs_array) # Update the first line based on the feedback polynomial np.einsum('ik,ilk->l', shift_regs, feedback_array, out=shift_regs[0]) shift_regs %= 2 # Update current state array and compute next state table idx = 0 for idx_mem, mem in enumerate(memory): current_state_array[idx:idx + mem] = shift_regs[:mem, idx_mem] idx += mem self.next_state_table[current_state, current_input] = bitarray2dec(current_state_array)