def test_convolutional_code(): # Lin.Costello.04, p. 454--456. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b1101, 0b1111]]) assert (code.num_output_bits, code.num_input_bits) == (2, 1) assert np.array_equal(code.constraint_lengths, [3]) assert np.array_equal(code.memory_order, 3) assert np.array_equal(code.overall_constraint_length, 3) # Lin.Costello.04, p. 456--458. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b11, 0b10, 0b11], [0b10, 0b1, 0b1]]) assert (code.num_output_bits, code.num_input_bits) == (3, 2) assert np.array_equal(code.constraint_lengths, [1, 1]) assert np.array_equal(code.memory_order, 1) assert np.array_equal(code.overall_constraint_length, 2) # Ryan.Lin.09, p. 154. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b111, 0b101]]) assert (code.num_output_bits, code.num_input_bits) == (2, 1) assert np.array_equal(code.constraint_lengths, [2]) assert np.array_equal(code.memory_order, 2) assert np.array_equal(code.overall_constraint_length, 2) # Ibid. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b111, 0b101]], feedback_polynomials=[0b111]) assert (code.num_output_bits, code.num_input_bits) == (2, 1) assert np.array_equal(code.constraint_lengths, [2]) assert np.array_equal(code.memory_order, 2) assert np.array_equal(code.overall_constraint_length, 2)
def test_convolutional_stream_encoder(): # Abrantes.10, p. 307. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b111, 0b101]]) convolutional_encoder = komm.ConvolutionalStreamEncoder(code) assert np.array_equal(convolutional_encoder([1, 0, 1, 1, 1, 0, 1, 1, 0, 0]), [1,1, 1,0, 0,0, 0,1, 1,0, 0,1, 0,0, 0,1, 0,1, 1,1]) # Lin.Costello.04, p. 454--456. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b1101, 0b1111]]) convolutional_encoder = komm.ConvolutionalStreamEncoder(code) assert np.array_equal(convolutional_encoder([1, 0, 1, 1, 1, 0, 0, 0]), [1,1, 0,1, 0,0, 0,1, 0,1, 0,1, 0,0, 1,1]) # Lin.Costello.04, p. 456--458. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b11, 0b10, 0b11], [0b10, 0b1, 0b1]]) convolutional_encoder = komm.ConvolutionalStreamEncoder(code) assert np.array_equal(convolutional_encoder([1,1, 0,1, 1,0, 0,0]), [1,1,0, 0,0,0, 0,0,1, 1,1,1]) # Ryan.Lin.09, p. 154. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b111, 0b101]]) convolutional_encoder = komm.ConvolutionalStreamEncoder(code) assert np.array_equal(convolutional_encoder([1, 0, 0, 0]), [1,1, 1,0, 1,1, 0,0]) # Ibid. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b111, 0b101]], feedback_polynomials=[0b111]) convolutional_encoder = komm.ConvolutionalStreamEncoder(code) assert np.array_equal(convolutional_encoder([1, 1, 1, 0]), [1,1, 1,0, 1,1, 0,0])
def test_terminated_convolutional_code(): convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b1, 0b11]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=3, mode='zero-termination') assert (code.length, code.dimension, code.minimum_distance) == (8, 3, 3) assert np.array_equal(code.generator_matrix, [[1, 1, 0, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0, 0], [0, 0, 0, 0, 1, 1, 0, 1]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=3, mode='direct-truncation') assert (code.length, code.dimension, code.minimum_distance) == (6, 3, 2) assert np.array_equal( code.generator_matrix, [[1, 1, 0, 1, 0, 0], [0, 0, 1, 1, 0, 1], [0, 0, 0, 0, 1, 1]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=3, mode='tail-biting') assert (code.length, code.dimension, code.minimum_distance) == (6, 3, 3) assert np.array_equal( code.generator_matrix, [[1, 1, 0, 1, 0, 0], [0, 0, 1, 1, 0, 1], [0, 1, 0, 0, 1, 1]]) # Lin.Costello.04, p. 586--587. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b111, 0b101]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=6, mode='tail-biting') assert (code.length, code.dimension, code.minimum_distance) == (12, 6, 3) assert np.array_equal(code.generator_matrix[0, :], [1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0]) # Lin.Costello.04, p. 587--590. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b111, 0b101]], feedback_polynomials=[0b111]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=5, mode='tail-biting') assert (code.length, code.dimension, code.minimum_distance) == (10, 5, 3) gen_mat = [[1, 0, 0, 0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 1, 0, 1], [0, 1, 0, 0, 1, 0, 0, 0, 0, 1], [0, 1, 0, 1, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 0, 1, 0]] assert np.array_equal(code.generator_matrix, gen_mat)
def test_convolutional_stream_decoder_2(feedforward_polynomials, feedback_polynomials, recvword, message_hat): code = komm.ConvolutionalCode(feedforward_polynomials, feedback_polynomials) L = len(message_hat) // code.num_input_bits recvword = np.concatenate([recvword, np.zeros(code.num_output_bits*L)]) convolutional_decoder = komm.ConvolutionalStreamDecoder(code, traceback_length=L, input_type='hard') message_hat = np.pad(message_hat, (len(message_hat), 0), mode='constant') assert np.array_equal(message_hat, convolutional_decoder(recvword))
def test_convolutional_stream_decoder(): # Abrantes.10, p. 307. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b111, 0b101]]) traceback_length = 12 convolutional_decoder = komm.ConvolutionalStreamDecoder(code, traceback_length, input_type='hard') recvword = np.array([1,1, 0,0, 0,0, 0,0, 1,0, 0,1, 0,0, 0,1, 0,1, 1,1]) recvword_ = np.concatenate([recvword, np.zeros(traceback_length*code.num_output_bits, dtype=np.int)]) message_hat = convolutional_decoder(recvword_) message_hat_ = message_hat[traceback_length :] assert np.array_equal(message_hat_, [1, 0, 1, 1, 1, 0, 1, 1, 0, 0])
def test_terminated_convolutional_code_viterbi(): # Lin.Costello.04, p. 522--523. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b011, 0b101, 0b111]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=5, mode='zero-termination') recvword = np.array( [1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1]) message_hat = code.decode(recvword, method='viterbi_hard') assert np.array_equal(message_hat, [1, 1, 0, 0, 1]) # Ryan.Lin.09, p. 176--177. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b111, 0b101]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=4, mode='direct-truncation') recvword = np.array([-0.7, -0.5, -0.8, -0.6, -1.1, +0.4, +0.9, +0.8]) message_hat = code.decode(recvword, method='viterbi_soft') assert np.array_equal(message_hat, [1, 0, 0, 0]) # Abrantes.10, p. 307. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b111, 0b101]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=10, mode='direct-truncation') recvword = np.array( [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1]) message_hat = code.decode(recvword, method='viterbi_hard') assert np.array_equal(message_hat, [1, 0, 1, 1, 1, 0, 1, 1, 0, 0]) # Abrantes.10, p. 313. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b111, 0b101]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=5, mode='direct-truncation') recvword = -np.array( [-0.6, +0.8, +0.3, -0.6, +0.1, +0.1, +0.7, +0.1, +0.6, +0.4]) message_hat = code.decode(recvword, method='viterbi_soft') assert np.array_equal(message_hat, [1, 0, 1, 0, 0])
def test_terminated_convolutional_golay(): # Lin.Costello.04, p. 602. feedforward_polynomials = [[3, 0, 1, 0, 3, 1, 1, 1], [0, 3, 1, 1, 2, 3, 1, 0], [2, 2, 3, 0, 0, 2, 3, 1], [0, 2, 0, 3, 2, 2, 2, 3]] convolutional_code = komm.ConvolutionalCode(feedforward_polynomials) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=3, mode='tail-biting') assert (code.length, code.dimension, code.minimum_distance) == (24, 12, 8)
def test_terminated_convolutional_code_encoders(mode, feedforward_polynomials): convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=feedforward_polynomials) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=5, mode=mode) for i in range(2**code.dimension): message = komm.int2binlist(i, width=code.dimension) assert np.array_equal( code.encode(message, method='generator_matrix'), code.encode(message, method='finite_state_machine'))
def test_convolutional_space_state_representation(): code = komm.ConvolutionalCode(feedforward_polynomials=[[0o7, 0o5]]) A = code.state_matrix B = code.control_matrix C = code.observation_matrix D = code.transition_matrix assert np.array_equal(A, [[0, 1], [0, 0]]) assert np.array_equal(B, [[1, 0]]) assert np.array_equal(C, [[1, 0], [1, 1]]) assert np.array_equal(D, [[1, 1]]) # Heide Gluesing-Luerssen: On the Weight Distribution of Convolutional Codes, p. 9. code = komm.ConvolutionalCode(feedforward_polynomials=[[0b1111, 0b1101]]) A = code.state_matrix B = code.control_matrix C = code.observation_matrix D = code.transition_matrix assert np.array_equal(A, [[0, 1, 0], [0, 0, 1], [0, 0, 0]]) assert np.array_equal(B, [[1, 0, 0]]) assert np.array_equal(C, [[1, 0], [1, 1], [1, 1]]) assert np.array_equal(D, [[1, 1]])
def test_terminated_convolutional_code_bcjr(): # Abrantes.10, p. 434--437. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b111, 0b101]]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=4, mode='zero-termination') recvword = -np.array([ +0.3, +0.1, -0.5, +0.2, +0.8, +0.5, -0.5, +0.3, +0.1, -0.7, +1.5, -0.4 ]) message_llr = code.decode(recvword, method='bcjr', output_type='soft', SNR=1.25) assert np.allclose(-message_llr, [1.78, 0.24, -1.97, 5.52], atol=0.05) message_hat = code.decode(recvword, method='bcjr', output_type='hard', SNR=1.25) assert np.allclose(message_hat, [1, 1, 0, 1]) # Lin.Costello.04, p. 572--575. convolutional_code = komm.ConvolutionalCode( feedforward_polynomials=[[0b11, 0b1]], feedback_polynomials=[0b11]) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=3, mode='zero-termination') recvword = -np.array([+0.8, +0.1, +1.0, -0.5, -1.8, +1.1, +1.6, -1.6]) message_llr = code.decode(recvword, method='bcjr', output_type='soft', SNR=0.25) assert np.allclose(-message_llr, [0.48, 0.62, -1.02], atol=0.05) message_hat = code.decode(recvword, method='bcjr', output_type='hard', SNR=0.25) assert np.allclose(message_hat, [1, 1, 0])
def test_terminated_convolutional_code_zero_termination( feedforward_polynomials, feedback_polynomials): convolutional_code = komm.ConvolutionalCode(feedforward_polynomials, feedback_polynomials) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=5, mode='zero-termination') for message_int in range(2**code.dimension): print(message_int, 2**code.dimension) message = komm.int2binlist(message_int, width=code.dimension) tail = np.dot(message, code._tail_projector) % 2 input_sequence = komm.pack(np.concatenate([message, tail]), width=convolutional_code._num_input_bits) _, fs = convolutional_code._finite_state_machine.process( input_sequence, initial_state=0) assert fs == 0
def create_conv_codes(): """ Creates rate 1/2 convolutional code with [0o7, 0o5] as the feedforward polynomial Parameters ---------- m : positive integer (>=3) t : number of bit errors to be corrected Returns ------- instance of the BCH code """ code = komm.ConvolutionalCode(feedforward_polynomials=[[0o7, 0o5]]) # the traceback depth in the Viterbi algorithm # usually 6 times the constraint length (3 in this case) tblen = 18 return code, tblen
def test_convolutional_space_state_representation_2(feedforward_polynomials, feedback_polynomials): code = komm.ConvolutionalCode(feedforward_polynomials, feedback_polynomials) n, k, nu = code.num_output_bits, code.num_input_bits, code.overall_constraint_length A = code.state_matrix B = code.control_matrix C = code.observation_matrix D = code.transition_matrix input_bits = np.random.randint(2, size=100*k) output_bits = np.empty(n * input_bits.size // k, dtype=np.int) s = np.zeros(nu, dtype=np.int) for t, u in enumerate(np.reshape(input_bits, newshape=(-1, k))): s, v = (np.dot(s, A) + np.dot(u, B)) % 2, (np.dot(s, C) + np.dot(u, D)) % 2 output_bits[t*n : (t+1)*n] = v convolutional_encoder = komm.ConvolutionalStreamEncoder(code) assert np.array_equal(output_bits, convolutional_encoder(input_bits))
import numpy as np import komm # ---- Parameters feedforward_polynomials = [[0o117, 0o155]] L = 1000 snr = 2.0 decoding_method = 'viterbi_soft' # ---- convolutional_code = komm.ConvolutionalCode(feedforward_polynomials) code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=L) awgn = komm.AWGNChannel(snr=snr) bpsk = komm.PAModulation(2) soft_or_hard = getattr(code, '_decode_' + decoding_method).input_type message = np.random.randint(2, size=L) codeword = code.encode(message) sentword = bpsk.modulate(codeword) recvword = awgn(sentword) demodulated = bpsk.demodulate(recvword, decision_method=soft_or_hard) message_hat = code.decode(demodulated, method=decoding_method) print(f'{np.count_nonzero(message != message_hat)} / {len(message)}')
def main(): # param specification SNR = np.arange(-5, 10, 1) modulation = komm.PSKModulation(4) tx_bin = np.random.randint(2, size=1200) tblen = 36 # hard decision simulation decision_method = "hard" code = komm.ConvolutionalCode(feedforward_polynomials=[[0o7, 0o5]]) BER = [] param = [] p = multiprocessing.dummy.Pool(len(SNR)) for i in range(0, len(SNR)): temp = sim_param(tx_bin, SNR[i], modulation, code, tblen, decision_method) param.append(temp) BER = p.map(CCODE_simulation, param) p.close() p.join() plt.figure() plt.title("Comparison between Ccode with soft and hard decision") plt.yscale('log') plt.plot(SNR, BER, label='(0o7,0o5) ccode with hard decision') # soft decision simulation decision_method = "soft" code = komm.ConvolutionalCode(feedforward_polynomials=[[0o7, 0o5]]) BER = [] param = [] p = multiprocessing.dummy.Pool(len(SNR)) for i in range(0, len(SNR)): temp = sim_param(tx_bin, SNR[i], modulation, code, tblen, decision_method) param.append(temp) BER = p.map(CCODE_simulation, param) p.close() p.join() plt.plot(SNR, BER, label='(0o7,0o5) ccode with soft decision') plt.legend() plt.xlabel("SNR") plt.ylabel("BER") plt.figure() plt.yscale('log') plt.title("Comparison among different Ccode with soft decision") plt.plot(SNR, BER, label='(0o7,0o5) ccode') # (0o155,0o117) simulation decision_method = "soft" code = komm.ConvolutionalCode(feedforward_polynomials=[[0o155, 0o117]]) BER = [] param = [] p = multiprocessing.dummy.Pool(len(SNR)) for i in range(0, len(SNR)): temp = sim_param(tx_bin, SNR[i], modulation, code, tblen, decision_method) param.append(temp) BER = p.map(CCODE_simulation, param) p.close() p.join() plt.plot(SNR, BER, label='(0o155,0o117) ccode') # (0o155,0o117,0o127) simulation decision_method = "soft" code = komm.ConvolutionalCode( feedforward_polynomials=[[0o155, 0o117, 0o127]]) BER = [] param = [] p = multiprocessing.dummy.Pool(len(SNR)) for i in range(0, len(SNR)): temp = sim_param(tx_bin, SNR[i], modulation, code, tblen, decision_method) param.append(temp) BER = p.map(CCODE_simulation, param) p.close() p.join() plt.plot(SNR, BER, label='(0o155,0o117,0o127) ccode') plt.xlabel("SNR") plt.ylabel("BER") plt.legend() plt.show()
def main(): # param specification SNR = 0 modulation = komm.PSKModulation(4) tx_bin = np.random.randint(2, size=1200) decision_method = "soft" param = [] # Convolution param (0o7,0o5) tblen = 18 C_code = komm.ConvolutionalCode(feedforward_polynomials=[[0o7, 0o5]]) BCH_code = komm.BCHCode(3, 1) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(4, 3) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(5, 7) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(6, 13) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) # Convolution param (0o155,0o117) tblen = 36 C_code = komm.ConvolutionalCode(feedforward_polynomials=[[0o155, 0o117]]) BCH_code = komm.BCHCode(3, 1) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(4, 3) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(5, 7) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(6, 13) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) # Convolution param (0o155,0o117,0o127) tblen = 36 C_code = komm.ConvolutionalCode( feedforward_polynomials=[[0o155, 0o117, 0o127]]) BCH_code = komm.BCHCode(3, 1) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(4, 3) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(5, 7) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BCH_code = komm.BCHCode(6, 13) param.append( con_param(tx_bin, SNR, modulation, BCH_code, C_code, tblen, decision_method)) BER = [] for i in range(0, len(param), 4): temp = [ format(sim_CON(param[i]), '.4f'), format(sim_CON(param[i + 1]), '.4f'), format(sim_CON(param[i + 2]), '.4f'), format(sim_CON(param[i + 3]), '.4f') ] BER.append(temp) columns = ['(7,4)BCH', '(15,5)BCH', '(31,6)BCH', '(63,10)BCH'] rows = ['(0o7,0o5)', '(0o155,0o117)', '(0o155,0o117,0o127)'] plt.table(cellText=BER, rowLabels=rows, colLabels=columns, loc='center') plt.axis('tight') plt.axis('off') plt.title( "Comparison among different combination of BCH code and Conv code") plt.show()
def main(): Result = [] SNR = 3 modulation = komm.PSKModulation(4) tx_bin = np.random.randint(2, size = 1200) # convolutional code Ccode = komm.ConvolutionalCode(feedforward_polynomials=[[0o7, 0o5]]) tblen = 18 method = "soft" Cparam = convolution_simulation.sim_param(tx_bin, SNR, modulation, Ccode, tblen, method) BER = format(convolution_simulation.CCODE_simulation(Cparam), '.4f') Result.append([BER,'1/2']) Ccode = komm.ConvolutionalCode(feedforward_polynomials=[[0o155, 0o117]]) tblen = 36 method = "soft" Cparam = convolution_simulation.sim_param(tx_bin, SNR, modulation, Ccode, tblen, method) BER = format(convolution_simulation.CCODE_simulation(Cparam), '.4f') Result.append([BER,'1/2']) Ccode = komm.ConvolutionalCode(feedforward_polynomials=[[0o155, 0o117, 0o127]]) tblen = 36 method = "soft" Cparam = convolution_simulation.sim_param(tx_bin, SNR, modulation, Ccode, tblen, method) BER = format(convolution_simulation.CCODE_simulation(Cparam), '.4f') Result.append([BER,'1/3']) # BCH code BCH_encoder = komm.BCHCode(3, 1) BCH_param = BCH_simulation.sim_param(tx_bin, SNR, modulation, BCH_encoder) BER = format(BCH_simulation.sim_BCH(BCH_param), '.4f') Result.append([BER,'4/7']) BCH_encoder = komm.BCHCode(4, 3) BCH_param = BCH_simulation.sim_param(tx_bin, SNR, modulation, BCH_encoder) BER = format(BCH_simulation.sim_BCH(BCH_param), '.4f') Result.append([BER,'5/15']) BCH_encoder = komm.BCHCode(5, 7) BCH_param = BCH_simulation.sim_param(tx_bin, SNR, modulation, BCH_encoder) BER = format(BCH_simulation.sim_BCH(BCH_param), '.4f') Result.append([BER,'6/31']) BCH_encoder = komm.BCHCode(6, 13) BCH_param = BCH_simulation.sim_param(tx_bin, SNR, modulation, BCH_encoder) BER = format(BCH_simulation.sim_BCH(BCH_param), '.4f') Result.append([BER,'10/63']) # ARQ BER = format(ARQ_simulation.ARQ_simulation(tx_bin, modulation, SNR), '.4f') Result.append([BER, '7/8']) columns = ['BER','Code rate'] rows = ['(0o7,0o5)','(0o155,0o117)','(0o155,0o117,0o127)','(7,4)BCH','(15,5)BCH','(31,6)BCH','(63,10)BCH','ARQ'] plt.table(cellText = Result, rowLabels = rows, colLabels = columns, loc='center') plt.axis('tight') plt.axis('off') plt.title("Comparison among different FEC code") plt.show()
def test_convolutional_stream_encoder_2(feedforward_polynomials, feedback_polynomials, message, codeword): code = komm.ConvolutionalCode(feedforward_polynomials, feedback_polynomials) convolutional_encoder = komm.ConvolutionalStreamEncoder(code) assert np.array_equal(convolutional_encoder(message), codeword)