def test_001_interleaving_works(self): NUM_TESTED_SYMBOLS = 2000 # randomize message msg = numpy.random.bytes(40) + chr(numpy.random.randint(0,1<<4)) # randomize interleaving seqeuence interleaving = [random.randrange(648) for i in xrange(NUM_TESTED_SYMBOLS)] + [647] # Encode the message using a reference encoder refEnc = ldpc.MatrixLDPCEncoder(ldpc.getWifiLDPC648(1,2), 1) refSeq = rf.vectorus() refEnc.setPacket(msg) refEnc.encode(648, refSeq) # Encode the message using an InterleavedEncoder innerEnc = ldpc.MatrixLDPCEncoder(ldpc.getWifiLDPC648(1,2), 1) interleavingVec = rf.vectorus(interleaving) enc = rf.codes.InterleavedEncoder(innerEnc, interleavingVec) enc.setPacket(msg) out = [] tmpOut = rf.vectorus() numRemaining = NUM_TESTED_SYMBOLS while(numRemaining > 0): print "remaining", numRemaining numNew = random.randrange(1, min(10, numRemaining)+1) enc.encode(numNew, tmpOut) out.extend(list(tmpOut)) numRemaining -= numNew # compare actual sequence to anticipated sequence for i in xrange(NUM_TESTED_SYMBOLS): self.assertEqual(out[i], refSeq[interleaving[i]], "output sequence doesn't match computed output at index %d" % i)
def test_003_Decoder(self): PACKET_LENGTH_BITS = 96 * 3 NUM_PASSES = 5 NUM_LAST_CODE_STEP_SYMBOLS = 2 BEAM_WIDTH = 16 codeParams = reference.CodeParams(salsaNumRounds=12, hashWordSize=64, numBitsPerCodingStep=3, symbolSizeBits=10, transmittedPointPrecisionBits=16, lookaheadDepth=0) # get packet packet = numpy.random.bytes(PACKET_LENGTH_BITS / 8) assert (PACKET_LENGTH_BITS % codeParams.numBitsPerCodingStep == 0) # decide on symbol schedule numCodingSteps = PACKET_LENGTH_BITS / codeParams.numBitsPerCodingStep cppSpineValueIndices = wireless.vectorus() for codeStep in xrange(numCodingSteps - 1): for i in xrange(NUM_PASSES): cppSpineValueIndices.push_back(codeStep) # For last code step for i in xrange(NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS): cppSpineValueIndices.push_back(numCodingSteps - 1) # Create C++ encoder and mapper cppEncoder = spinal.CodeFactory( codeParams.numBitsPerCodingStep, numCodingSteps, codeParams.symbolSizeBits) \ .salsa().encoder() cppMapper = wireless.LinearMapper( codeParams.symbolSizeBits, codeParams.transmittedPointPrecisionBits) cppEncoderSymbols = wireless.vectorus() cppMapperSymbols = wireless.vectori() # Encode with C++ encoder cppEncoder.setPacket(packet) cppEncoder.encode(cppSpineValueIndices, cppEncoderSymbols) cppMapper.process(cppEncoderSymbols, cppMapperSymbols) # Decode with C++ decoder cppDecoder = spinal.CodeFactory( codeParams.numBitsPerCodingStep, numCodingSteps, codeParams.symbolSizeBits) \ .salsa() \ .linear(codeParams.transmittedPointPrecisionBits) \ .beamDecoder(BEAM_WIDTH, NUM_PASSES, NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS) cppDecoder.add(cppSpineValueIndices, cppMapperSymbols) decodedPacket = cppDecoder.decode() self.assertEquals(decodedPacket.packet, packet)
def test_002_Encoder(self): PACKET_LENGTH_BITS = 192 NUM_PASSES = 5 NUM_LAST_CODE_STEP_SYMBOLS = 2 codeParams = reference.CodeParams(salsaNumRounds = 12, hashWordSize = 64, numBitsPerCodingStep = 4, symbolSizeBits = 16, transmittedPointPrecisionBits = 16, lookaheadDepth = 0) # get packet packet = numpy.random.bytes(PACKET_LENGTH_BITS / 8) assert(PACKET_LENGTH_BITS % codeParams.numBitsPerCodingStep == 0) # decide on symbol schedule numCodingSteps = PACKET_LENGTH_BITS / codeParams.numBitsPerCodingStep numSymbolsForCodingStep = numpy.ones([numCodingSteps], dtype=numpy.uint32) numSymbolsForCodingStep *= NUM_PASSES numSymbolsForCodingStep[-1] *= NUM_LAST_CODE_STEP_SYMBOLS # Create C++ encoder cppEncoder = spinal.CodeFactory( codeParams.numBitsPerCodingStep, numCodingSteps, codeParams.symbolSizeBits) \ .salsa().encoder() cppSymbols = wireless.vectorus() # Convert symbol schedule to spine value indices array cppSpineValueIndices = wireless.vectorus() for codeStep in xrange(numCodingSteps): for i in xrange(numSymbolsForCodingStep[codeStep]): cppSpineValueIndices.push_back(codeStep) # Encode with c++ encoder cppEncoder.setPacket(packet) cppEncoder.encode(cppSpineValueIndices, cppSymbols) # Encode with python encoder pyEncoder = reference.Encoder(codeParams) pySymbols = pyEncoder.encode(packet, numSymbolsForCodingStep) # Check the two encoders produced the same symbols self.assertTrue(pySymbols == list(cppSymbols))
def test_002_Encoder(self): PACKET_LENGTH_BITS = 192 NUM_PASSES = 5 NUM_LAST_CODE_STEP_SYMBOLS = 2 codeParams = reference.CodeParams(salsaNumRounds=12, hashWordSize=64, numBitsPerCodingStep=4, symbolSizeBits=16, transmittedPointPrecisionBits=16, lookaheadDepth=0) # get packet packet = numpy.random.bytes(PACKET_LENGTH_BITS / 8) assert (PACKET_LENGTH_BITS % codeParams.numBitsPerCodingStep == 0) # decide on symbol schedule numCodingSteps = PACKET_LENGTH_BITS / codeParams.numBitsPerCodingStep numSymbolsForCodingStep = numpy.ones([numCodingSteps], dtype=numpy.uint32) numSymbolsForCodingStep *= NUM_PASSES numSymbolsForCodingStep[-1] *= NUM_LAST_CODE_STEP_SYMBOLS # Create C++ encoder cppEncoder = spinal.CodeFactory( codeParams.numBitsPerCodingStep, numCodingSteps, codeParams.symbolSizeBits) \ .salsa().encoder() cppSymbols = wireless.vectorus() # Convert symbol schedule to spine value indices array cppSpineValueIndices = wireless.vectorus() for codeStep in xrange(numCodingSteps): for i in xrange(numSymbolsForCodingStep[codeStep]): cppSpineValueIndices.push_back(codeStep) # Encode with c++ encoder cppEncoder.setPacket(packet) cppEncoder.encode(cppSpineValueIndices, cppSymbols) # Encode with python encoder pyEncoder = reference.Encoder(codeParams) pySymbols = pyEncoder.encode(packet, numSymbolsForCodingStep) # Check the two encoders produced the same symbols self.assertTrue(pySymbols == list(cppSymbols))
def _get_puncturing(punctureSpec, numStreams, forEncoder): # Choose puncturing import wireless if punctureSpec['type'] == '8-way-v2': puncturing = wireless.codes.StridedPuncturingSchedule( numStreams, punctureSpec['numLastCodeStep']) elif punctureSpec['type'] == 'static': puncturing = wireless.codes.StaticPuncturingSchedule() schedule = wireless.vectorus(punctureSpec['schedule']) puncturing.set(schedule) else: raise RuntimeError, 'unknown puncturing type %s' % punctureSpec['type'] # Choose the repetition ratio for the puncturing if punctureSpec.has_key('encoderToSymbolRate'): encoderRate, symbolRate = punctureSpec['encoderToSymbolRate'] if forEncoder: repeatRatio = encoderRate else: repeatRatio = symbolRate else: repeatRatio = 1 # Wrap the puncturing schedule with repetition, if neccessary if repeatRatio != 1: return wireless.codes.RepeatingPuncturingSchedule(puncturing, repeatRatio) else: return puncturing
def test_004_one_iteration_result_check(self): P = 0.94 code = rf.codes.ldpc.getWifiLDPC648(1,2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) encodedBits = rf.vectorus() packet = '2659df41ec49b827bd494aaed625201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf20ca09'.decode('hex') expected_packet = {1:'2659df41ec09ba273f4d5baed621201cabbb2a75d5fcfd5f2c03c242796cb108271d54a81bcf30ca09'.decode('hex'), 2:'2659df41ec49b827bf4d4aeed621201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf30ca09'.decode('hex'), 3:'2659df41ec49b827bd494aaed625201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf30ca09'.decode('hex'), 4:'2659df41ec49b827bd494aaed625201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf20ca09'.decode('hex')} encoder.setPacket(packet) encoder.encode(648,encodedBits) symVector = rf.vector_symbol() noisyVector = rf.vector_symbol() for b in list(encodedBits): symVector.push_back(b) noisifier = rf.channels.BscChannel(1 - P) noisifier.seed(numpy.array([134123], dtype=numpy.uint32)) noisyBits = noisifier.process(symVector, noisyVector) # convert encodedBits into LLR values. logLLR = math.log(P/(1.0-P)) encodedLLRs = rf.vectorf() for i in xrange(648): encodedLLRs.push_back(2.0 * logLLR * noisyVector[i] - logLLR) for num_iters in sorted(expected_packet.keys()): decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, num_iters) decoder.add(encodedLLRs) res = decoder.decode() #print res.packet[:41].encode('hex') self.assertEquals(res.packet, expected_packet[num_iters])
def test_003_decode_with_AWGN_noise_over_BPSK(self): SNR_dB = 0 code = rf.codes.ldpc.getWifiLDPC648(1,2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) encodedBits = rf.vectorus() packet = numpy.random.bytes(((648/2)+7)/8) encoder.setPacket(packet) encoder.encode(648,encodedBits) # Convert into symbols with 20 bit precision symbols = rf.vector_symbol() mapper = rf.mappers.LinearMapper(1,20) mapper.process(encodedBits, symbols) # Apply AWGN noise noisySymbols = rf.vector_symbol() n0 = mapper.getAveragePower() / math.pow(10.0, SNR_dB/10.0) noisifier = rf.channels.SymbolAwgnChannel(n0) noisifier.seed(numpy.array([numpy.random.randint(0,1<<31)], dtype=numpy.uint32)) noisifier.process(symbols,noisySymbols) # Soft-demap demapper = rf.demappers.GrayDemapper(rf.mappers.GrayMapper(1, 20), 1) receivedLLRs = rf.vectorf() demapper.process(noisySymbols, n0, receivedLLRs) # Decode decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, 10) decoder.add(receivedLLRs) res = decoder.decode() self.assertEquals(res.packet[:40], packet[:40]) self.assertEquals(ord(res.packet[40]) & 0x0F, ord(packet[40]) & 0x0F)
def test_002_decode_with_BSC_noise(self): P = 0.96 NUM_EXPERIMENTS = 20 code = rf.codes.ldpc.getWifiLDPC648(1,2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) for experimentInd in xrange(NUM_EXPERIMENTS): encodedBits = rf.vectorus() packet = numpy.random.bytes(((648/2)+7)/8) encoder.setPacket(packet) encoder.encode(648,encodedBits) symVector = rf.vector_symbol() noisyVector = rf.vector_symbol() for b in list(encodedBits): symVector.push_back(b) noisifier = rf.channels.BscChannel(1 - P) noisifier.seed(numpy.array([numpy.random.randint(0,1<<31)], dtype=numpy.uint32)) noisyBits = noisifier.process(symVector, noisyVector) # convert encodedBits into LLR values. logLLR = math.log(P/(1.0-P)) encodedLLRs = rf.vectorf() for i in xrange(648): encodedLLRs.push_back(2.0 * logLLR * noisyVector[i] - logLLR) decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, 50) decoder.add(encodedLLRs) res = decoder.decode() self.assertEquals(res.packet[:40], packet[:40]) self.assertEquals(ord(res.packet[40]) & 0x0F, ord(packet[40]) & 0x0F)
def test_001_interleaving_works(self): NUM_TESTED_SYMBOLS = 2000 # randomize message msg = numpy.random.bytes(40) + chr(numpy.random.randint(0, 1 << 4)) # randomize interleaving seqeuence interleaving = [ random.randrange(648) for i in xrange(NUM_TESTED_SYMBOLS) ] + [647] # Encode the message using a reference encoder refEnc = ldpc.MatrixLDPCEncoder(ldpc.getWifiLDPC648(1, 2), 1) refSeq = rf.vectorus() refEnc.setPacket(msg) refEnc.encode(648, refSeq) # Encode the message using an InterleavedEncoder innerEnc = ldpc.MatrixLDPCEncoder(ldpc.getWifiLDPC648(1, 2), 1) interleavingVec = rf.vectorus(interleaving) enc = rf.codes.InterleavedEncoder(innerEnc, interleavingVec) enc.setPacket(msg) out = [] tmpOut = rf.vectorus() numRemaining = NUM_TESTED_SYMBOLS while (numRemaining > 0): print "remaining", numRemaining numNew = random.randrange(1, min(10, numRemaining) + 1) enc.encode(numNew, tmpOut) out.extend(list(tmpOut)) numRemaining -= numNew # compare actual sequence to anticipated sequence for i in xrange(NUM_TESTED_SYMBOLS): self.assertEqual( out[i], refSeq[interleaving[i]], "output sequence doesn't match computed output at index %d" % i)
def test_001_no_repetitions(self): NUM_TESTED_LOCATIONS = 500 for modulus in xrange(1, 30): for numLastValueSymbols in [1, 2, 7]: punc = spinal.StridedPuncturingSchedule( modulus, numLastValueSymbols) numSymbolsFullPass = modulus - 1 + numLastValueSymbols spineIndices = wireless.vectorus() proto = spinal.StridedProtocol(1, modulus, NUM_TESTED_LOCATIONS, numLastValueSymbols, 1) lastNumSymbols = 0 nextNumSymbols = proto.numSymbolsNextDecode(0) while (nextNumSymbols != 0): # How many symbols were added? numAddedSymbols = nextNumSymbols - lastNumSymbols self.assertNotEqual(numAddedSymbols, 0, "Protocol did not advance!") if nextNumSymbols != NUM_TESTED_LOCATIONS: self.assertGreaterEqual( numAddedSymbols, numSymbolsFullPass / 8, "Expected the number of symbols between decodes to fit the puncturing" ) self.assertLessEqual( numAddedSymbols, (numSymbolsFullPass + 7) / 8, "Expected the number of symbols between decodes to fit the puncturing" ) # Get the spine indices from the puncturing schedule punc.batchNext(numAddedSymbols, spineIndices) # Make sure that the sequence in spineIndices is strictly # increasing for i in xrange(spineIndices.size() - 1): self.assertGreaterEqual( spineIndices[i + 1], spineIndices[i], "Expected the spine location between decodes to be a non-decreasing sequence, but location %d violates this" % (lastNumSymbols + i)) # Advance to next protocol demand proto.setResult(0, nextNumSymbols, False) lastNumSymbols = nextNumSymbols nextNumSymbols = proto.numSymbolsNextDecode(0)
def test_004_one_iteration_result_check(self): P = 0.94 code = rf.codes.ldpc.getWifiLDPC648(1, 2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) encodedBits = rf.vectorus() packet = '2659df41ec49b827bd494aaed625201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf20ca09'.decode( 'hex') expected_packet = { 1: '2659df41ec09ba273f4d5baed621201cabbb2a75d5fcfd5f2c03c242796cb108271d54a81bcf30ca09' .decode('hex'), 2: '2659df41ec49b827bf4d4aeed621201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf30ca09' .decode('hex'), 3: '2659df41ec49b827bd494aaed625201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf30ca09' .decode('hex'), 4: '2659df41ec49b827bd494aaed625201cabfb2a75d5fc7d5f2c03c242794cb108271d54881bcf20ca09' .decode('hex') } encoder.setPacket(packet) encoder.encode(648, encodedBits) symVector = rf.vector_symbol() noisyVector = rf.vector_symbol() for b in list(encodedBits): symVector.push_back(b) noisifier = rf.channels.BscChannel(1 - P) noisifier.seed(numpy.array([134123], dtype=numpy.uint32)) noisyBits = noisifier.process(symVector, noisyVector) # convert encodedBits into LLR values. logLLR = math.log(P / (1.0 - P)) encodedLLRs = rf.vectorf() for i in xrange(648): encodedLLRs.push_back(2.0 * logLLR * noisyVector[i] - logLLR) for num_iters in sorted(expected_packet.keys()): decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, num_iters) decoder.add(encodedLLRs) res = decoder.decode() #print res.packet[:41].encode('hex') self.assertEquals(res.packet, expected_packet[num_iters])
def test_001_no_repetitions(self): NUM_TESTED_LOCATIONS = 500 for modulus in xrange(1,30): for numLastValueSymbols in [1,2,7]: punc = spinal.StridedPuncturingSchedule(modulus,numLastValueSymbols) numSymbolsFullPass = modulus - 1 + numLastValueSymbols spineIndices = wireless.vectorus() proto = spinal.StridedProtocol(1, modulus, NUM_TESTED_LOCATIONS, numLastValueSymbols, 1) lastNumSymbols = 0 nextNumSymbols = proto.numSymbolsNextDecode(0) while(nextNumSymbols != 0): # How many symbols were added? numAddedSymbols = nextNumSymbols - lastNumSymbols self.assertNotEqual(numAddedSymbols, 0, "Protocol did not advance!") if nextNumSymbols != NUM_TESTED_LOCATIONS: self.assertGreaterEqual(numAddedSymbols, numSymbolsFullPass / 8, "Expected the number of symbols between decodes to fit the puncturing") self.assertLessEqual(numAddedSymbols, (numSymbolsFullPass + 7) / 8, "Expected the number of symbols between decodes to fit the puncturing") # Get the spine indices from the puncturing schedule punc.batchNext(numAddedSymbols, spineIndices) # Make sure that the sequence in spineIndices is strictly # increasing for i in xrange(spineIndices.size() - 1): self.assertGreaterEqual(spineIndices[i+1], spineIndices[i], "Expected the spine location between decodes to be a non-decreasing sequence, but location %d violates this" % (lastNumSymbols + i)) # Advance to next protocol demand proto.setResult(0, nextNumSymbols, False) lastNumSymbols = nextNumSymbols nextNumSymbols = proto.numSymbolsNextDecode(0)
def test_001_decode_without_noise(self): code = rf.codes.ldpc.getWifiLDPC648(1, 2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) encodedBits = rf.vectorus() packet = numpy.random.bytes(((648 / 2) + 7) / 8) encoder.setPacket(packet) encoder.encode(648, encodedBits) # convert encodedBits into LLR values. encodedLLRs = rf.vectorf() for i in xrange(648): encodedLLRs.push_back(8.0 * encodedBits[i] - 4.0) decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, 5) decoder.add(encodedLLRs) res = decoder.decode() self.assertEquals(res.packet[:40], packet[:40]) self.assertEquals(ord(res.packet[40]) & 0x0F, ord(packet[40]) & 0x0F)
def test_001_decode_without_noise(self): code = rf.codes.ldpc.getWifiLDPC648(1,2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) encodedBits = rf.vectorus() packet = numpy.random.bytes(((648/2)+7)/8) encoder.setPacket(packet) encoder.encode(648,encodedBits) # convert encodedBits into LLR values. encodedLLRs = rf.vectorf() for i in xrange(648): encodedLLRs.push_back(8.0* encodedBits[i] - 4.0) decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, 5) decoder.add(encodedLLRs) res = decoder.decode() self.assertEquals(res.packet[:40], packet[:40]) self.assertEquals(ord(res.packet[40]) & 0x0F, ord(packet[40]) & 0x0F)
def test_001_repetitions_are_correct(self): """ Make sure that the stream positions output by the repetition puncturing schedule are indeed repetitions of the original puncturing schedule. """ NUM_CODE_STEPS = 20 TESTED_POSITIONS = 100 NUM_REPETITION_SET = [1, 2, 3, 6] for numRepetitions in NUM_REPETITION_SET: for numLastStepSymbolsPerPass in xrange(1, 4): punc = spinal.StridedPuncturingSchedule( NUM_CODE_STEPS, numLastStepSymbolsPerPass) punc2 = spinal.StridedPuncturingSchedule( NUM_CODE_STEPS, numLastStepSymbolsPerPass) repeatedPunc = spinal.RepeatingPuncturingSchedule( punc2, numRepetitions) indices = wireless.vectorus() # Run twice, once without resetting and another time after # resetting the puncturing schedules for resetIter in xrange(2): punc.batchNext(TESTED_POSITIONS, indices) unrepeated = list(indices) repeatedPunc.batchNext(TESTED_POSITIONS * numRepetitions, indices) repeated = list(indices) for i in range(len(repeated)): self.assertEqual( repeated[i], unrepeated[i / numRepetitions], "location %d in repeated schedule should match location %d in original schedule" % (i, i / numRepetitions)) # We reset to check that the repeating puncturing schedule # works well after a reset punc.reset() repeatedPunc.reset()
def test_001_test_vectors_encode(self): # input and output bits were prepared using CML, using Cdma2000 scenario # number 5. messageStr = file('turbo-message-1530.dat').read() codewordStr = file('turbo-interleaved-1530.dat').read() # get encoder enc = rf.codes.strider.StriderTurboCode.createEncoder(1530) enc.setPacket(messageStr) # encode encoderOutput = rf.vectorus() enc.encode(7668, encoderOutput) # compare number of bits self.assertEqual(7668, encoderOutput.size(), "encoder didn't produce the expected number of bits") # compare to test vector for i in xrange(encoderOutput.size()): self.assertEqual((ord(codewordStr[i / 8]) >> (i % 8)) & 0x1, encoderOutput[i], 'output differs on bit %d' % i)
def test_002_decode_with_BSC_noise(self): P = 0.96 NUM_EXPERIMENTS = 20 code = rf.codes.ldpc.getWifiLDPC648(1, 2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) for experimentInd in xrange(NUM_EXPERIMENTS): encodedBits = rf.vectorus() packet = numpy.random.bytes(((648 / 2) + 7) / 8) encoder.setPacket(packet) encoder.encode(648, encodedBits) symVector = rf.vector_symbol() noisyVector = rf.vector_symbol() for b in list(encodedBits): symVector.push_back(b) noisifier = rf.channels.BscChannel(1 - P) noisifier.seed( numpy.array([numpy.random.randint(0, 1 << 31)], dtype=numpy.uint32)) noisyBits = noisifier.process(symVector, noisyVector) # convert encodedBits into LLR values. logLLR = math.log(P / (1.0 - P)) encodedLLRs = rf.vectorf() for i in xrange(648): encodedLLRs.push_back(2.0 * logLLR * noisyVector[i] - logLLR) decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, 50) decoder.add(encodedLLRs) res = decoder.decode() self.assertEquals(res.packet[:40], packet[:40]) self.assertEquals( ord(res.packet[40]) & 0x0F, ord(packet[40]) & 0x0F)
def test_001_repetitions_are_correct(self): """ Make sure that the stream positions output by the repetition puncturing schedule are indeed repetitions of the original puncturing schedule. """ NUM_CODE_STEPS = 20 TESTED_POSITIONS = 100 NUM_REPETITION_SET = [1,2,3,6] for numRepetitions in NUM_REPETITION_SET: for numLastStepSymbolsPerPass in xrange(1,4): punc = spinal.StridedPuncturingSchedule(NUM_CODE_STEPS, numLastStepSymbolsPerPass) punc2 = spinal.StridedPuncturingSchedule(NUM_CODE_STEPS, numLastStepSymbolsPerPass) repeatedPunc = spinal.RepeatingPuncturingSchedule(punc2, numRepetitions) indices = wireless.vectorus() # Run twice, once without resetting and another time after # resetting the puncturing schedules for resetIter in xrange(2): punc.batchNext(TESTED_POSITIONS, indices) unrepeated = list(indices) repeatedPunc.batchNext(TESTED_POSITIONS * numRepetitions, indices) repeated = list(indices) for i in range(len(repeated)): self.assertEqual(repeated[i], unrepeated[i/numRepetitions], "location %d in repeated schedule should match location %d in original schedule" %(i, i/numRepetitions)) # We reset to check that the repeating puncturing schedule # works well after a reset punc.reset() repeatedPunc.reset()
def test_003_decode_with_AWGN_noise_over_BPSK(self): SNR_dB = 0 code = rf.codes.ldpc.getWifiLDPC648(1, 2) encoder = rf.codes.ldpc.MatrixLDPCEncoder(code, 1) encodedBits = rf.vectorus() packet = numpy.random.bytes(((648 / 2) + 7) / 8) encoder.setPacket(packet) encoder.encode(648, encodedBits) # Convert into symbols with 20 bit precision symbols = rf.vector_symbol() mapper = rf.mappers.LinearMapper(1, 20) mapper.process(encodedBits, symbols) # Apply AWGN noise noisySymbols = rf.vector_symbol() n0 = mapper.getAveragePower() / math.pow(10.0, SNR_dB / 10.0) noisifier = rf.channels.SymbolAwgnChannel(n0) noisifier.seed( numpy.array([numpy.random.randint(0, 1 << 31)], dtype=numpy.uint32)) noisifier.process(symbols, noisySymbols) # Soft-demap demapper = rf.demappers.GrayDemapper(rf.mappers.GrayMapper(1, 20), 1) receivedLLRs = rf.vectorf() demapper.process(noisySymbols, n0, receivedLLRs) # Decode decoder = rf.codes.ldpc.MatrixLDPCDecoder(code, 10) decoder.add(receivedLLRs) res = decoder.decode() self.assertEquals(res.packet[:40], packet[:40]) self.assertEquals(ord(res.packet[40]) & 0x0F, ord(packet[40]) & 0x0F)
def test_003_Decoder(self): PACKET_LENGTH_BITS = 96*3 NUM_PASSES = 5 NUM_LAST_CODE_STEP_SYMBOLS = 2 BEAM_WIDTH = 16 codeParams = reference.CodeParams(salsaNumRounds = 12, hashWordSize = 64, numBitsPerCodingStep = 3, symbolSizeBits = 10, transmittedPointPrecisionBits = 16, lookaheadDepth = 0) # get packet packet = numpy.random.bytes(PACKET_LENGTH_BITS / 8) assert(PACKET_LENGTH_BITS % codeParams.numBitsPerCodingStep == 0) # decide on symbol schedule numCodingSteps = PACKET_LENGTH_BITS / codeParams.numBitsPerCodingStep cppSpineValueIndices = wireless.vectorus() for codeStep in xrange(numCodingSteps - 1): for i in xrange(NUM_PASSES): cppSpineValueIndices.push_back(codeStep) # For last code step for i in xrange(NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS): cppSpineValueIndices.push_back(numCodingSteps - 1) # Create C++ encoder and mapper cppEncoder = spinal.CodeFactory( codeParams.numBitsPerCodingStep, numCodingSteps, codeParams.symbolSizeBits) \ .salsa().encoder() cppMapper = wireless.LinearMapper(codeParams.symbolSizeBits, codeParams.transmittedPointPrecisionBits) cppEncoderSymbols = wireless.vectorus() cppMapperSymbols = wireless.vectori() # Encode with C++ encoder cppEncoder.setPacket(packet) cppEncoder.encode(cppSpineValueIndices, cppEncoderSymbols) cppMapper.process(cppEncoderSymbols, cppMapperSymbols) # Decode with C++ decoder cppDecoder = spinal.CodeFactory( codeParams.numBitsPerCodingStep, numCodingSteps, codeParams.symbolSizeBits) \ .salsa() \ .linear(codeParams.transmittedPointPrecisionBits) \ .beamDecoder(BEAM_WIDTH, NUM_PASSES, NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS) cppDecoder.add(cppSpineValueIndices, cppMapperSymbols) decodedPacket = cppDecoder.decode() self.assertEquals(decodedPacket.packet, packet)
def test_001_Punctured_Encoder(self): PACKET_LENGTH_BITS = 192 NUM_PASSES = 5 NUM_LAST_CODE_STEP_SYMBOLS = 2 codeParams = spinal.reference.CodeParams(salsaNumRounds = 12, hashWordSize = 64, numBitsPerCodingStep = 4, symbolSizeBits = 10, transmittedPointPrecisionBits = 10, lookaheadDepth = 0) # get packet packet = numpy.random.bytes(PACKET_LENGTH_BITS / 8) assert(PACKET_LENGTH_BITS % codeParams.numBitsPerCodingStep == 0) numCodingSteps = PACKET_LENGTH_BITS / codeParams.numBitsPerCodingStep totalNumSymbols = (numCodingSteps - 1 + NUM_LAST_CODE_STEP_SYMBOLS) * NUM_PASSES # decide on symbol schedule cppSpineValueIndices = wireless.vectorus() for codeStep in xrange(numCodingSteps - 1): for i in xrange(NUM_PASSES): cppSpineValueIndices.push_back(codeStep) # For last code step for i in xrange(NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS): cppSpineValueIndices.push_back(numCodingSteps - 1) # Make c++ encoder without puncturing cppEncoder = spinal.CodeFactory( codeParams.numBitsPerCodingStep, numCodingSteps, codeParams.symbolSizeBits) \ .salsa().encoder() unpuncturedSymbols = wireless.vectorus() # Encode unpunctured with C++ encoder cppEncoder.setPacket(packet) cppEncoder.encode(cppSpineValueIndices, unpuncturedSymbols) # Make puncturing schedule punc = spinal.StridedPuncturingSchedule(numCodingSteps, NUM_LAST_CODE_STEP_SYMBOLS) # Make encoder with puncturing puncturedEncoder = spinal.PuncturedEncoder(cppEncoder, punc) # Encode with puncturing puncturedSymbols = wireless.vectorus() puncturedEncoder.setPacket(packet) puncturedEncoder.encode(totalNumSymbols, puncturedSymbols) # Make a dictionary from spine value to all locations that are produced # from that spine value d = {} punc.reset() for i in xrange(totalNumSymbols): d.setdefault(punc.next(), []).append(i) # Check the two encoders produced the same symbols (taking into account # the puncturing schedule) for codeStep in xrange(numCodingSteps - 1): for i in xrange(NUM_PASSES): self.assertEqual(unpuncturedSymbols[codeStep * NUM_PASSES + i], puncturedSymbols[ d[codeStep][i] ], "location %d should contain the %dth sample from spine value %d, but does not match" \ % (d[codeStep][i], i, codeStep)) # last codestep codeStep = (numCodingSteps - 1) for i in xrange(NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS): self.assertEqual(unpuncturedSymbols[codeStep * NUM_PASSES + i], puncturedSymbols[ d[codeStep][i] ], "location %d should contain the %dth sample from spine value %d, but does not match" \ % (d[codeStep][i], i, codeStep))