コード例 #1
0
    def ldpcOuterEncode(self, messages):
        """
        Perform outer encoding of codewords
        :param messages: messages to be outer-encoded
        """

        # Create aliases for several parameters
        numBins = self.__numBins
        L = self.__L
        M = self.__M
        K = self.__K

        # Establish important parameters
        self.__OuterCodes = [FGG.Triadic8(16) for i in range(numBins)]
        txcodewords = 0  # list of all codewords transmitted
        codewords = []  # list of codewords to transmitted by bin
        sTrue = []  # list of signals sent by various bins

        # Outer encode each message
        for i in range(numBins):
            cdwds = self.__OuterCodes[i].encodemessages(
                messages[i]) if len(messages[i]) > 0 else [np.zeros(L * M)]
            for cdwd in cdwds:  # ensure that each codeword is valid
                self.__OuterCodes[i].testvalid(cdwd)
            codewords.append(
                cdwds)  # add encoded messages to list of codewords
            txcodewords = np.vstack(
                (txcodewords,
                 cdwds)) if not np.isscalar(txcodewords) else cdwds.copy()

            # Combine codewords to form signal to transmit
            if K[i] == 0:  # do nothing if there are no users in this bin
                tmp = np.zeros(L * M).astype(np.float64)
            else:  # otherwise, add all codewords together
                tmp = np.sum(cdwds, axis=0)
            sTrue.append(tmp)  # store true signal for future reference

        return txcodewords, sTrue
コード例 #2
0
def simulateSingleClass(EbNodB):
    simCount = 100  # number of simulations
    msgDetected1 = 0
    msgDetected2 = 0
    K1Sum = 0
    K2Sum = 0
    numMC = 0

    for simIndex in range(simCount):

        Ka = 64
        K1 = 0

        K1 = np.sum(np.random.randn(Ka) > 0)
        K2 = Ka - K1

        K1Sum += K1
        K2Sum += K2

        print('K1: ', K1)
        print('K2: ', K2)

        B1 = 128  # Payload size of every active user in group 1
        B2 = 128  # Payload size of every active user in group 2

        L1 = 16  # Number of sections/sub-blocks in group 1
        L2 = 16  # Number of sections/sub-blocks in group 2

        n = 38400  # Total number of channel uses (real d.o.f)
        T = 10  # Number of AMP iterations
        J1 = 16  # Length of each coded sub-block
        J2 = 16  # Length of each coded sub-block
        M1 = 2**J1  # Length of each section
        M2 = 2**J2  # Length of each section

        numBPiter = 1  # Number of BP iterations on outer code. 1 seems to be good enough & AMP theory including state evolution valid only for one BP iteration
        # EbNodB = 2.4 # Energy per bit. With iterative extension, operating EbN0 falls to 2.05 dB for 25 users with 1 round SIC

        # EbN0 in linear scale
        EbNo = 10**(EbNodB / 10)
        P1 = 2 * B1 * EbNo / n
        P2 = 2 * B2 * EbNo / n
        s_n = 1

        # We assume equal power allocation for all the sections. Code has to be modified a little to accomodate non-uniform power allocations
        Phat1 = n * P1 / L1
        Phat2 = n * P2 / L2
        d1 = np.sqrt(n * P1 / L1)
        d2 = np.sqrt(n * P2 / L2)

        print('Simulation Number: ' + str(simIndex))

        # Generate active users message sequences
        messages1 = np.random.randint(2, size=(K1, B1))
        messages2 = np.random.randint(2, size=(K2, B2))

        # Outer-encode the message sequences
        codewords1 = OuterCode1.encodemessages(messages1)
        for codeword1 in codewords1:
            OuterCode1.testvalid(codeword1)
        codewords2 = OuterCode2.encodemessages(messages2)
        for codeword2 in codewords2:
            OuterCode2.testvalid(codeword2)

        # Convert indices to sparse representation
        # sTrue: True state
        sTrue1 = np.sum(codewords1, axis=0)
        sTrue2 = np.sum(codewords2, axis=0)

        # Generate the binned SPARC codebook
        Ab1, Az1 = sparc_codebook(L1, M1, n, P1)
        Ab2, Az2 = sparc_codebook(L2, M2, n, P2)

        # Generate our transmitted signal X
        x = d1 * Ab1(sTrue1) + d2 * Ab2(sTrue2)

        # Generate random channel noise and thus also received signal y
        noise = np.random.randn(n, 1) * s_n
        y = (x + noise)

        z = y.copy()
        s1 = np.zeros((L1 * M1, 1))
        s2 = np.zeros((L2 * M2, 1))

        K1ht = Ka
        K2ht = Ka
        confident = False

        for t in range(T):
            # compute effective observations
            r1 = amp_effective_observation(z, s1, P1, L1, Az1)
            r2 = amp_effective_observation(z, s2, P2, L2, Az2)

            # AMP state updates
            s1 = amp_state_update(r1, z, P1, L1, K1ht, Ka, numBPiter,
                                  OuterCode1, confident)
            s2 = amp_state_update(r2, z, P2, L2, K2ht, Ka, numBPiter,
                                  OuterCode2, confident)

            # Estimate K1, K2
            if not confident:
                k1ht, k2ht, confident = amp_estimate_k_distribution(
                    s1, s2, L1, M1, Ka, t)
                if confident:  # employ estimate after 2 amp iterations
                    K1ht = k1ht
                    K2ht = k2ht
                    if k1ht != K1:
                        numMC += 1
                        print('ERROR: K1, K2 misestimated.')

            # AMP residual
            z = amp_residual(y, z, s1, s2, d1, d2, Ab1, Ab2)

        # continue

        # raise Exception()
        print('Graph Decode')

        # Decoding with Graph
        originallist1 = codewords1.copy()
        originallist2 = codewords2.copy()
        qq1 = int(K1ht * 1.5) if confident else int(Ka * 1.5 / 2)
        qq2 = int(K2ht * 1.5) if confident else int(Ka * 1.5 / 2)
        recoveredcodewords1 = OuterCode1.decoder(s1, qq1)
        recoveredcodewords2 = OuterCode2.decoder(s2, qq2)

        # Calculation of per-user prob err
        matches1 = FGG.numbermatches(originallist1, recoveredcodewords1)
        matches2 = FGG.numbermatches(originallist2, recoveredcodewords2)

        print('Group 1: ' + str(matches1) + ' out of ' + str(K1))
        print('Group 2: ' + str(matches2) + ' out of ' + str(K2))
        msgDetected1 = msgDetected1 + matches1
        msgDetected2 = msgDetected2 + matches2

    # errorRate1= (K1*simCount - msgDetected1)/(K1*simCount)
    # errorRate2= (K2*simCount - msgDetected2)/(K2*simCount)
    errorRate1 = (K1Sum - msgDetected1) / K1Sum
    errorRate2 = (K2Sum - msgDetected2) / K2Sum

    print("Per user probability of error (Group 1) = ", errorRate1)
    print("Per user probability of error (Group 2) = ", errorRate2)
    print("Average PUPE =  ", 0.5 * (errorRate1 + errorRate2))

    return errorRate1, errorRate2, 0.5 * (errorRate1 + errorRate2), numMC
コード例 #3
0
import numpy as np
import FactorGraphGeneration as FGG
from pyfht import block_sub_fht

OuterCode1 = FGG.Triadic8(16)
OuterCode2 = FGG.Triadic8(16)


def sparc_codebook(L, M, n, P):
    Ax, Ay, _ = block_sub_fht(n, M, L, seed=None,
                              ordering=None)  # seed must be explicit

    def Ab(b):
        return Ax(b).reshape(-1, 1) / np.sqrt(n)

    def Az(z):
        return Ay(z).reshape(-1, 1) / np.sqrt(n)

    return Ab, Az


def approximateVector(x, K):

    # normalize initial value of x
    xOrig = x / np.linalg.norm(x, ord=1)

    # create vector to hold best approximation of x
    xHt = xOrig.copy()
    u = np.zeros(len(xHt))

    # run approximation algorithm
コード例 #4
0
import ccsfg
import FactorGraphGeneration as FG
import ccsinnercode as ccsic
import numpy as np

# Initialize CCS-AMP Graph
Graph = FG.Triadic8(16)

# Simulation Parameters
Ka = 25  # Number of active users
w = 128  # Payload size of each active user (per user message length)
N = 38400  # Total number of channel uses (real d.o.f)
listSize = Ka + 10  # List size retained for each section after AMP converges
numAmpIter = 6  # Number of AMP iterations
numBPIter = 1  # Number of BP iterations to perform
BPonOuterGraph = True  # Indicates whether to perform BP on outer code.  If 0, AMP uses Giuseppe's uninformative prior
maxSims = 2  # Number of Simulations to Run

EbNodB = 2.4  # Energy per bit in decibels
EbNo = 10**(EbNodB / 10)  # Eb/No in linear scale
P = 2 * w * EbNo / N  # transmit power
std = 1  # Noise standard deviation
errorRate = 0.0  # track error rate across simulations

# Run CCS-AMP maxSims times
for idxsim in range(maxSims):
    print('Starting simulation %d of %d' % (idxsim + 1, maxSims))

    # Reset the graph
    Graph.reset()
コード例 #5
0
errorRate = 0.0  # track error rate across simulations

# Assign power to occupancy estimation and data transmission tasks
pM = 80
dmsg = np.sqrt(N * P * N / (pM + N) / L) if NUM_BINS > 1 else np.sqrt(N * P /
                                                                      L)
dbid = np.sqrt(N * P * pM / (pM + N)) if NUM_BINS > 1 else 0
assert np.abs(L * dmsg**2 + dbid**2 -
              N * P) <= 1e-3, "Total power constraint violated."

# Average of maxSims trials
for idxsim in range(maxSims):
    print('Starting simulation %d of %d' % (idxsim + 1, maxSims))

    # Initialze outer codes
    OuterCodes = [FGG.Triadic8(16) for i in range(NUM_BINS)]

    # Generate messages for all Ka users
    usrmessages = np.random.randint(2, size=(Ka, w))

    # Split users into bins based on the first couple of bits in their messages
    w0 = int(np.ceil(np.log2(NUM_BINS)))
    binIds = np.matmul(usrmessages[:, 0:w0], 2**
                       np.arange(w0)[::-1]) if w0 > 0 else np.zeros(Ka)
    K = np.array([np.sum(binIds == i) for i in range(NUM_BINS)]).astype(int)

    # Group usrmessages by bin
    messages = [usrmessages[np.where(binIds == i)[0]] for i in range(NUM_BINS)]

    # Transmit bin identifier across channel
    rxK = dbid * K + np.random.randn(NUM_BINS) * std
コード例 #6
0
import FactorGraphGeneration as FG
import ccsinnercode as ccsic
import numpy as np
import time

# Simulation Parameters
K = 100  # number of active users
N = 38400  # number of channel uses (real d.o.f)
w = 128  # length of each user's uncoded message
numAMPIter = 10  # number of AMP iterations to perform
numBPIter = 1  # number of BP iterations to perform
listSize = K + 10  # list size retained per section after AMP converges
nstd = 1  # AWGN noise standard deviation
numSims = 2  # number of trials to average over per point on the graph
OuterGraph = FG.Triadic8(16)  # factor graph associated with outer LDPC code
SNRs = np.arange(start=1.5, stop=4.6, step=0.5)  # SNRs in (dB) to test over
SNRs = np.array([2.5])
errorrates = np.zeros(
    (4, len(SNRs)))  # data structure for storing PUPE results
runtimes = np.zeros(
    (4, len(SNRs)))  # data structure for storing runtime results

# Iterate over each SNR
for idxsnr in range(len(SNRs)):

    # Compute power
    EbNo = 10**(SNRs[idxsnr] / 10)
    P = 2 * w * EbNo / N

    # Average over maxSims trials
    for idxsim in range(numSims):
コード例 #7
0
def simulate(Ka, NUM_BINS, EbNodB, GENIE_AIDED):
    """
    Run coded demixing simulation
    :param Ka: total number of users
    :param NUM_BINS: total number of bins
    :param EbNodB: Eb/No in dB
    :param GENIE_AIDED: flag of whether to use genie-aided estimate of K
    """

    B = 128  # length of each user's message in bits
    L = 16  # number of sections
    M = 2**L  # length of each section
    n = 38400  # number of channel uses (real dof)
    numBPiter = 1  # Number of BP iterations on outer code
    numSICIter = 2  # Number of SIC iterations - WARNING: code must be modified if numSICIter != 2
    gamma = 0.7 if numSICIter == 2 else 1  # Percentage of codewords to recover on the first round of SIC
    simCount = 100  # number of trials to average over
    errorRate = 0  # store error rate
    delta = 5  # constant number of extra codewords to retain

    # Compute number of AMP iterations
    numAMPIter = min(max(10, 10 + 3 * int((Ka - 50) / 25)), 24)

    # Compute signal and noise power parameters
    EbNo = 10**(EbNodB / 10)
    P = 2 * B * EbNo / n
    s_n = 1

    # Assign power to occupancy estimation and data transmission tasks
    pM = 80
    dcs = np.sqrt(n * P * n / (pM + n) / L) if NUM_BINS > 1 else np.sqrt(n *
                                                                         P / L)
    dbid = np.sqrt(n * P * pM / (pM + n)) if NUM_BINS > 1 else 0
    assert np.abs(L * dcs**2 + dbid**2 -
                  n * P) <= 1e-3, "Total power constraint violated."

    # run simCount trials
    for simIndex in range(simCount):
        print('**********Simulation Number: ' + str(simIndex))
        """*********************************************************************************
        Step 1: users generate messages and stochastically partition themselves into groups. 
        **********************************************************************************"""

        # Generate messages for all Ka users
        usrmessages = np.random.randint(2, size=(Ka, B))

        # Split users into bins based on the first couple of bits in their messages
        w0 = int(np.ceil(np.log2(NUM_BINS)))
        binIds = np.matmul(usrmessages[:, 0:w0], 2**
                           np.arange(w0)[::-1]) if w0 > 0 else np.zeros(Ka)
        K = np.array([np.sum(binIds == i)
                      for i in range(NUM_BINS)]).astype(int)

        # Group messages by bin
        messages = [
            usrmessages[np.where(binIds == i)[0]] for i in range(NUM_BINS)
        ]
        """***************************************************************
        Step 2: receiver estimates the number of users present in each bin
        ***************************************************************"""

        # Transmit bin identifier across channel
        rxK = dbid * K + np.random.randn(NUM_BINS) * s_n

        # Perform LMMSE bin occupancy estimation
        Kht = estimate_bin_occupancy(
            Ka, dbid, rxK, K, s_n, GENIE_AIDED) if NUM_BINS > 1 else K.copy()
        """*******************************************************************
        Step 3: outer/inner message encoding and transmission over AWGN channel
        ********************************************************************"""

        # Generate outer graphs
        OuterCodes = []
        for i in range(NUM_BINS):
            OuterCodes.append(FGG.Triadic8(16))

        # Define data structures to hold encoding/decoding parameters
        txcodewords = 0  # list of all codewords transmitted
        codewords = []  # list of codewords to transmitted by bin
        sTrue = []  # list of signals sent by various bins
        Ab = []  # list of sensing matrices used by various bins
        Az = []  # list of sensing matrices transposed used by various bins

        # Bin-Specific Encoding Operations
        for i in range(NUM_BINS):

            # Outer encode each message
            cdwds = OuterCodes[i].encodemessages(
                messages[i]) if len(messages[i]) > 0 else [np.zeros(L * M)]
            for cdwd in cdwds:  # ensure that each codeword is valid
                OuterCodes[i].testvalid(cdwd)
            codewords.append(
                cdwds)  # add encoded messages to list of codewords

            # Store codewords in 'txcodewords' for error computation
            if K[i] > 0:
                txcodewords = np.vstack(
                    (txcodewords,
                     cdwds)) if not np.isscalar(txcodewords) else cdwds.copy()

            # Combine codewords to form signal to transmit
            if K[i] == 0:  # do nothing if there are no users in this bin
                tmp = np.zeros(L * M).astype(np.float64)
            else:  # otherwise, add all codewords together
                tmp = np.sum(cdwds, axis=0)
            sTrue.append(tmp)  # store true signal for future reference

            # Generate the binned SPARC codebook
            a, b = sparc_codebook(L, M, n)
            Ab.append(a)
            Az.append(b)

        # Generate transmitted signal X
        x = 0.0
        for i in range(NUM_BINS):
            x += dcs * Ab[i](sTrue[i])

        # Transmit signal X through AWGN channel
        y = x + np.random.randn(n, 1) * s_n
        """********************************************************
        Step 4: outer/inner decoding and message recovery using SIC
        ********************************************************"""

        # reset number of matches between tx and rx codewords
        matches = 0

        # Run numSICIter iterations of SIC
        for idxsiciter in range(numSICIter):
            print('Starting SIC iteration ' + str(idxsiciter))
            """***********************
            Step 5: Inner AMP decoding
            ***********************"""

            # Prepare for inner AMP decoding
            z = y.copy()  # initialize AMP residual
            s = [np.zeros((L * M, 1))
                 for i in range(NUM_BINS)]  # initialize AMP states

            # AMP Inner decoder
            for idxampiter in range(numAMPIter):

                # Update the state of each bin individually
                s = [
                    amp_state_update(z, s[i], P, L, Az[i], Kht[i], numBPiter,
                                     OuterCodes[i]) for i in range(NUM_BINS)
                ]

                # compute residual jointly
                z = amp_residual(y, z, s, dcs, Ab)
            """*************************
            Step 6: Outer graph decoding
            *************************"""

            # Prepare for outer graph decoding
            recoveredcodewords = dict()

            # Graph-based outer decoder
            for idxbin in range(NUM_BINS):
                if Kht[idxbin] == 0: continue

                # Produce list of recovered codewords with their associated likelihoods
                recovered, likelihoods = OuterCodes[idxbin].decoder(
                    s[idxbin],
                    int(4 * Kht[idxbin] + delta),
                    includelikelihoods=True)

                # Compute what the first w0 bits should be based on bin number
                binIDBase2 = np.binary_repr(idxbin)
                binIDBase2 = binIDBase2 if len(binIDBase2) == w0 else (
                    w0 - len(binIDBase2)) * '0' + binIDBase2
                firstW0bits = np.array([
                    binIDBase2[i] for i in range(len(binIDBase2))
                ]).astype(int)

                # Enforce CRC consistency and add recovered codewords to data structure indexed by likelihood
                for idxcdwd in range(len(likelihoods)):

                    # Extract first part of message from codeword
                    firstinfosection = OuterCodes[idxbin].infolist[0] - 1
                    sparsemsg = recovered[idxcdwd][firstinfosection *
                                                   M:(firstinfosection + 1) *
                                                   M]

                    # Find index of nonzero entry and convert to binary representation
                    idxnonzero = np.where(sparsemsg > 0.0)[0][0]
                    idxnonzerobin = np.binary_repr(idxnonzero)

                    # Add trailing zeros to base-2 representation
                    if len(idxnonzerobin) < 16:
                        idxnonzerobin = (
                            16 - len(idxnonzerobin)) * '0' + idxnonzerobin

                    # Extract first w0 bits and determine bin ID
                    msgfirstW0bits = np.array(
                        [idxnonzerobin[i] for i in range(w0)]).astype(int)

                    # Enforce CRC consistency
                    if (msgfirstW0bits == firstW0bits).all() or (NUM_BINS
                                                                 == 1):
                        recoveredcodewords[likelihoods[idxcdwd]] = np.hstack(
                            (recovered[idxcdwd], idxbin))

            # sort dictionary of recovered codewords in descending order of likelihood
            sortedcodewordestimates = sorted(recoveredcodewords.items(),
                                             key=lambda x: -x[0])

            # recover percentage of codewords based on SIC iteration
            numCdwds = np.ceil(gamma *
                               Ka).astype(int) if idxsiciter == 0 else (
                                   Ka - np.ceil(gamma * Ka).astype(int))
            sortedcodewordestimates = sortedcodewordestimates[0:numCdwds]

            # remove contribution of recovered users from received signal and prepare for PUPE computation
            codewordestimates = 0
            for idxcdwd in range(len(sortedcodewordestimates)):

                # add codeword to numpy array of rx codewords for PUPE computation
                codewordestimates = np.vstack((
                                        codewordestimates, sortedcodewordestimates[idxcdwd][1][0:L*M]))  \
                                        if not np.isscalar(codewordestimates) \
                                        else sortedcodewordestimates[idxcdwd][1][0:L*M].copy()

                # SIC remove contribution of recovered codeword
                idxcdwdbin = sortedcodewordestimates[idxcdwd][1][-1].astype(
                    int)  # extract bin index as an integer
                y = y - dcs * Ab[idxcdwdbin](
                    sortedcodewordestimates[idxcdwd][1]
                    [0:L * M])  # remove codeword's contribution to rx signal y
                Kht[idxcdwdbin] = K[idxcdwdbin] - 1 if K[
                    idxcdwdbin] > 0 else 0  # decrement estimated number of users in codeword's bin

            # Update number of matches
            matches += FGG.numbermatches(txcodewords, codewordestimates)
            print(
                str(matches) + ' matches after SIC iteration ' +
                str(idxsiciter))
        """*****************
        Step 7: Compute PUPE
        *****************"""

        # Compute error rate
        errorRate += (Ka - matches) / (Ka * simCount)
        print('Cumulative Error Rate: ' + str(errorRate * simCount /
                                              (simIndex + 1)))

    return errorRate
コード例 #8
0
def simulate(EbNodB):
    Ka = 64
    B = 128
    L = OuterCodes[0].varcount
    M = OuterCodes[0].sparseseclength

    n=38400 # Total number of channel uses (real d.o.f)
    T=10 # Number of AMP iterations
    numBPiter = 1  # Number of BP iterations on outer code. 1 seems to be good enough & AMP theory including state evolution valid only for one BP iteration
    simCount = 100 # number of simulations

    # EbN0 in linear scale
    EbNo = 10**(EbNodB/10)
    P = 2*B*EbNo/n
    σ_n = 1
    
    # Compute power multiplier for bin identifier bits
    desiredBinIDPowerMultiplier = 5
    pM = desiredBinIDPowerMultiplier*NUM_BINS*B/(B*NUM_BINS - (desiredBinIDPowerMultiplier - 1)*NUM_BINS**2)

    # We assume equal power allocation for all the sections. Code has to be modified a little to accomodate non-uniform power allocations
    dcs = np.sqrt(n*P*B/(pM*NUM_BINS + B)/L)
    dbid = np.sqrt(n*P*pM*NUM_BINS/(pM*NUM_BINS + B)/NUM_BINS)

    if np.abs(L*dcs**2 + NUM_BINS*dbid**2 - n*P) > 1e-3:
        raise Exception('Total power constraint not met')

    errorRates = np.zeros(NUM_BINS)

    for simIndex in range(simCount):
        print('******************************Simulation Number: ' + str(simIndex))
        
        # Randomly assign users to groups
        K = np.zeros(NUM_BINS).astype(int)
        for i in range(Ka):
            K[np.random.randint(NUM_BINS)] += 1
        
        # Define bin LUT
        binIdLUT = np.eye(NUM_BINS) * dbid

        # Send bin identifiers
        binIdBits = np.matmul(K, binIdLUT)

        # Transmit bin identifier across channel
        rxBinIdBits = binIdBits + np.random.randn(NUM_BINS) * σ_n
        
        # Estimate Ki
        Kht = np.zeros(NUM_BINS).astype(int)
        for i in range(NUM_BINS):
            Kht[i] = round(np.inner(binIdLUT[i, :], rxBinIdBits) / (dbid**2))
        
        print('True K: ' + str(K))
        print('Estimated K: ' + str(Kht))

        # Generate active users message sequences
        messages = []
        for i in range(NUM_BINS):
            messages.append(np.random.randint(2, size=(K[i], B)))

        # Outer-encode the message sequences
        codewords = []
        sTrue = []
        Ab = []
        Az = []
        for i in range(NUM_BINS):
            # Outer-encode the message sequences
            cdwds = OuterCodes[i].encodemessages(messages[i])
            for cdwd in cdwds:
                OuterCodes[i].testvalid(cdwd)
            codewords.append(OuterCodes[i].encodemessages(messages[i]))

            # Convert indices to sparse representation
            sTrue.append(np.sum(cdwds, axis=0))

            # Generate the binned SPARC codebook
            a, b = sparc_codebook(L, M, n, P)
            Ab.append(a)
            Az.append(b)

        
        # Generate our transmitted signal X
        x = 0.0
        for i in range(NUM_BINS):
            x += dcs*Ab[i](sTrue[i])
        
        # Generate random channel noise and thus also received signal y
        noise = np.random.randn(n, 1) * σ_n
        y = (x + noise)

        z = y.copy()
        
        s = []
        for i in range(NUM_BINS):
            s.append(np.zeros((L*M, 1)))

        for t in range(T):
            print(np.sqrt(np.sum(z**2)/n))
            for i in range(NUM_BINS):
                s[i] = amp_state_update(z, s[i], P, L, Ab[i], Az[i], Kht[i], numBPiter, OuterCodes[0])
            z = amp_residual(y, z, s, dcs, Ab)

        print('Graph Decode')
        
        # Decoding with Graph
        for i in range(NUM_BINS):
            original = codewords[i].copy()
            recovered = OuterCodes[i].decoder(s[i], int(Kht[i] * 1.5))
            matches = FGG.numbermatches(original, recovered)
            print('Group ' + str(i+1) + ': ' + str(matches) + ' out of ' + str(K[i]))
            # msgDetected[i] += matches
            errorRates[i] += ((K[i] - matches)/(K[i])) / simCount


    for i in range(NUM_BINS):
        # errorRates[i] = (K[i]*simCount - msgDetected[i]) / (K[i] * simCount)
        print("Per user probability of error (Group " + str(i+1) + ") = ", errorRates[i])   

    # return errorRate1, errorRate2, 0.5*(errorRate1 + errorRate2)
    return errorRates, np.average(errorRates)
コード例 #9
0
import numpy as np
import FactorGraphGeneration as FGG
from pyfht import block_sub_fht

NUM_BINS = 2

# Generate outer graphs
OuterCodes = []
for i in range(NUM_BINS):
    OuterCodes.append(FGG.Triadic8(16))

def sparc_codebook(L, M, n,P):
    Ax, Ay, _ = block_sub_fht(n, M, L, seed=None, ordering=None) # seed must be explicit
    def Ab(b):
        return Ax(b).reshape(-1, 1) / np.sqrt(n)
    def Az(z):
        return Ay(z).reshape(-1, 1) / np.sqrt(n) 
    return Ab, Az

def approximateVector(x, K):    

    # normalize initial value of x
    xOrig = x / np.linalg.norm(x, ord=1)
    
    # create vector to hold best approximation of x
    xHt = xOrig.copy()
    u = np.zeros(len(xHt))
    
    # run approximation algorithm
    while np.amax(xHt) > (1/K):
        minIndices = np.argmin([(1/K)*np.ones(xHt.shape), xHt], axis=0)
コード例 #10
0
    def simulate(self, Ktot, EbNodB, numSims):
        """
        Run a coded demixing simulation.
        :param Ktot: total number of active users
        :param EbNodB: Eb/No in dB scale
        :param numSims: number of trials to average the results over
        """

        # Create alias for certain parameters
        w = self.__w
        n = self.__n
        L = self.__L
        pM = self.__pM
        numBins = self.__numBins

        # Compute required power parameters
        EbNo = 10**(EbNodB / 10)
        P = 2 * w * EbNo / n
        std = 1
        dmsg = np.sqrt(n * P * n / (pM + n) /
                       L) if numBins > 1 else np.sqrt(n * P / L)
        dbid = np.sqrt(n * P * pM / (pM + n)) if numBins > 1 else 0
        assert np.abs(L * dmsg**2 + dbid**2 -
                      n * P) <= 1e-3, "Total power constraint violated."

        # Compute empirical PUPE averaged over numSims trials
        errorRate = 0.0
        matches = 0
        for idxsim in range(numSims):
            print('Starting simulation %d of %d' % (idxsim + 1, numSims))

            # Generate messages for all Ktot users
            usrmessages = np.random.randint(2, size=(Ktot, w))

            # Split users into bins based on the first couple of bits in their messages
            w0 = int(np.ceil(np.log2(numBins)))
            self.__w0 = w0
            binIds = np.matmul(usrmessages[:, 0:w0], 2**
                               np.arange(w0)[::-1]) if w0 > 0 else np.zeros(K)
            K = np.array([np.sum(binIds == i)
                          for i in range(numBins)]).astype(int)
            self.__K = K.copy()

            # Group usrmessages by bin
            messages = [
                usrmessages[np.where(binIds == i)[0]] for i in range(numBins)
            ]

            # Transmit bin identifier across channel
            rxK = dbid * K + np.random.randn(numBins) * std

            # Estimate the number of users per bin
            Kht = self.estimateBinOccupancy(Ktot, dbid, rxK, std)
            self.__Kht = Kht.copy()

            # Outer-encode user signals
            txcodewords, sTrue = self.outerEncode(messages)

            # Inner-encode user signals
            x = self.innerEncode(dmsg, sTrue)

            # Transmit over channel
            y = x + std * np.random.randn(n, 1)

            # Inner-decoding
            s = self.innerDecode(y, dmsg)

            # Outer-decoding
            codewordestimates = self.outerDecode(s, Ktot)

            # Compute number of matches
            matches = FGG.numbermatches(txcodewords, codewordestimates)
            errorRate += (Ktot - matches) / (Ktot * numSims)
            print(str(matches) + ' matches')

        return errorRate
コード例 #11
0
ファイル: FG-Demixing.py プロジェクト: vamsi128/CCS-AMP-Code
def simulate(EbNodB, case):
    simCount = 100  # number of simulations

    # EbN0 in linear scale
    EbNo = 10**(EbNodB / 10)
    P1 = 2 * B1 * EbNo / n
    P2 = 2 * B2 * EbNo / n
    σ_n = 1
    #Generate the power allocation and set of tau coefficients

    # We assume equal power allocation for all the sections. Code has to be modified a little to accomodate non-uniform power allocations
    Phat1 = n * P1 / L1
    Phat2 = n * P2 / L2
    d1 = np.sqrt(n * P1 / L1)
    d2 = np.sqrt(n * P2 / L2)

    msgDetected1 = 0
    msgDetected2 = 0
    totalTime = 0

    for simIndex in range(simCount):
        print('Simulation Number: ' + str(simIndex))

        # Generate active users message sequences
        tx_message1 = np.random.randint(2, size=(K1, B1))
        tx_message2 = np.random.randint(2, size=(K2, B2))

        # Outer-encode the message sequences
        encoded_tx_message_indices = Tree_encode(tx_message1, K1,
                                                 messageBlocks, G, L1, J)
        codewords = OuterCode.encodemessages(tx_message2)

        # Convert indices to sparse representation
        # sTrue: True state
        sTrue1 = convert_indices_to_sparse(encoded_tx_message_indices, L1, J,
                                           K1)
        sTrue2 = np.sum(codewords, axis=0).reshape(-1, 1)

        # Generate the binned SPARC codebook
        Ab1, Az1 = sparc_codebook(L1, M, n, P1)
        Ab2, Az2 = sparc_codebook(L2, M, n, P2)

        # Generate our transmitted signal X
        x = d1 * Ab1(sTrue1) + d2 * Ab2(sTrue2)

        # Generate random channel noise and thus also received signal y
        noise = np.random.randn(n, 1) * σ_n
        y = (x + noise).reshape(-1, 1)

        tic = time.time()

        z = y.copy()
        z1 = y.copy()
        z2 = y.copy()
        s1 = np.zeros((L1 * M, 1))
        s2 = np.zeros((L2 * M, 1))

        if case == 0:
            # Decode group 1 first
            for t in range(T):
                s1 = amp_state_update(z1, s1, P1, L1, M, Ab1, Az1, K1, G,
                                      messageBlocks, 1, numBPiter, OuterCode)
                z1 = amp_residual(y, z1, s1, s2, d1, 0, Ab1, Ab2)

            # Interference cancellation
            yUpdated = y - Ab1(s1)
            z2 = yUpdated.copy()

            # Decode group 2
            for t in range(T):
                s2 = amp_state_update(z2, s2, P2, L2, M, Ab2, Az2, K2, G,
                                      messageBlocks, 2, numBPiter, OuterCode)
                z2 = amp_residual(yUpdated, z2, s1, s2, 0, d2, Ab1, Ab2)

        elif case == 1:
            for t in range(T):
                s1 = amp_state_update(z, s1, P1, L1, M, Ab1, Az1, K1, G,
                                      messageBlocks, 1, numBPiter, OuterCode)
                s2 = amp_state_update(z, s2, P2, L2, M, Ab2, Az2, K2, G,
                                      messageBlocks, 2, numBPiter, OuterCode)

                z = amp_residual(y, z, s1, s2, d1, d2, Ab1, Ab2)

        else:
            for t in range(T):
                s1 = amp_state_update(z1, s1, P1, L1, M, Ab1, Az1, K1, G,
                                      messageBlocks, 1, numBPiter, OuterCode)
                s2 = amp_state_update(z2, s2, P2, L2, M, Ab2, Az2, K2, G,
                                      messageBlocks, 2, numBPiter, OuterCode)

                z1 = amp_residual(y, z1, s1, s2, d1, 0, Ab1, Ab2)
                z2 = amp_residual(y, z2, s1, s2, 0, d2, Ab1, Ab2)

        # Convert decoded sparse vector into vector of indices
        cs_decoded_tx_message1 = convert_sparse_to_indices(
            s1, L1, J, listSize1)

        # Tree decoder to decode individual messages from lists output by AMP
        Paths1 = Tree_decoder(cs_decoded_tx_message1, G, L1, J, B1, listSize1)

        # Re-align paths to the correct order
        perm1 = np.argsort(
            np.array([0, 1, 2, 6, 7, 8, 12, 3, 4, 5, 9, 10, 11, 15, 13, 14]))
        Paths1 = Paths1[:, perm1]

        # If tree deocder outputs more than K valid paths, retain only K of them
        if Paths1.shape[0] > K1:
            Paths1 = pick_topKminusdelta_paths(Paths1, cs_decoded_tx_message1,
                                               s1, J, K1, 0)

        # Extract the message indices from valid paths in the tree
        Tree_decoded_indices1 = extract_msg_indices(Paths1,
                                                    cs_decoded_tx_message1, L1,
                                                    J)

        print('Graph Decode')

        # Decoding wiht Graph
        originallist = codewords.copy()
        recoveredcodewords = FGG.decoder(OuterCode, s2, 2 * K2)

        toc = time.time()
        totalTime = totalTime + toc - tic
        #print(totalTime)

        # Calculation of per-user prob err
        simMsgDetected1 = 0
        simMsgDetected2 = 0
        for i in range(K1):
            simMsgDetected1 = simMsgDetected1 + np.equal(
                encoded_tx_message_indices[i, :],
                Tree_decoded_indices1).all(axis=1).any()
        matches = FGG.numbermatches(originallist, recoveredcodewords)

        print('Group 1: ' + str(simMsgDetected1) + ' out of ' + str(K1))
        print('Group 2: ' + str(matches) + ' out of ' + str(K2))
        msgDetected1 = msgDetected1 + simMsgDetected1
        msgDetected2 = msgDetected2 + matches

    errorRate1 = (K1 * simCount - msgDetected1) / (K1 * simCount)
    errorRate2 = (K2 * simCount - msgDetected2) / (K2 * simCount)
    avgTime = totalTime / simCount
    return errorRate1, errorRate2, avgTime
コード例 #12
0
ファイル: FG-Demixing.py プロジェクト: vamsi128/CCS-AMP-Code
# # Coded Demxing
#
# This notebook implements coded Demixing using the CCS-AMP encoder/decoder for multi-class unsourced random access using Hadamard design matrices.
#

# In[ ]:

import numpy as np
import math
#import matplotlib.pyplot as plt
import time
import sys
import FactorGraphGeneration as FGG

OuterCode = FGG.Graph62()

# ## Fast Hadamard Transforms
#
# The ```PyFHT_local``` code can all be found in `pyfht`, which uses a C extension to speed up the fht function.
# Only one import suffices, with the latter being much faster.

# In[ ]:

# import PyFHT_local
from pyfht import block_sub_fht

# # Outer Tree encoder
#
# This function encodes the payloads corresponding to users into codewords from the specified tree code.
#