<?xml-model href='http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng' schematypens='http://relaxng.org/ns/structure/1.0'?><TEI xmlns="http://www.tei-c.org/ns/1.0">
	<teiHeader>
		<fileDesc>
			<titleStmt><title level='a'>Parallel Trellis-Stage-Combining BCJR for High-Throughput CUDA Decoder of CCSDS SCPPM</title></titleStmt>
			<publicationStmt>
				<publisher>IEEE</publisher>
				<date>03/01/2025</date>
			</publicationStmt>
			<sourceDesc>
				<bibl> 
					<idno type="par_id">10588914</idno>
					<idno type="doi"></idno>
					
					<author>Amaael Antonini</author><author>Egor Glukhov</author><author>Richard Wesel</author><author>Dariush Divsalar</author><author>Jon Hamkins</author>
				</bibl>
			</sourceDesc>
		</fileDesc>
		<profileDesc>
			<abstract><ab><![CDATA[The Consultative Committee for Space Data Systems (CCSDS) standard for high photon efficiency uses a serially-concatenated (SC) code to encode pulse position modulated laser light.  A  convolutional encoder serves as the outer code and an accumulator serves as the inner code.  These two component codes are connected through an interleaver. This coding scheme is called Serially Concatenated convolutionally coded Pulse Position Modulation (SCPPM) and it is used for NASA's Deep Space Optical Communications (DSOC) experiment. For traditional decoding that traverses the trellis forwards and backwards according to the Bahl Cocke Jelinek and Raviv (BCJR) algorithm, the latency is on the order of the length of the trellis, which has 10,080 stages for the rate 2/3 DSOC code. This paper presents a novel alternative approach that simultaneously processes all trellis stages, successively combining pairs of stages into a meta-stage. This approach has latency that is on the order of the log base-2 of the number of stages. The new decoder is implemented using the Compute Unified Device Architecture (CUDA) platform on an Nvidia Graphics Processing Unit (GPU). Compared to Field Programmable Gate Array (FPGA) implementations, the GPU implementation offers easier development, scalability, and portability across GPU models. The GPU implementation provides a dramatic increase in speed that facilitates more thorough simulation as well as enables a shift from FPGA to GPU processors for DSOC ground stations.]]></ab></abstract>
		</profileDesc>
	</teiHeader>
	<text><body xmlns="http://www.tei-c.org/ns/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink">
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="1.">INTRODUCTION</head><p>The Consultative Committee for Space Data Systems (CCSDS) standard uses a Serially Concatenated convolutionally coded Pulse Position Modulation (SCPPM) that features a convolutional code with only four states but 7560 trellis stages for rate-1/2. Traditional decoders work sequentially 979-8-3503-5597-0/25/$31.00 &#169;2025 IEEE through these many stages, constraining throughput. This paper presents an alternative method that simultaneously processes all trellis stages allowing a dramatic increase in throughput and lowering the latency of decoding. Parallel trellis processing can be realized on both Graphics Processing Unit (GPU) and Field Programmable Gate Array (FPGA) implementations. GPU implementation can provide multiple benefits: easier development, scalability, and portability across GPU models. With the rapid advancement of technology, the same implementation remains functional on future GPU devices and compiler versions.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Background</head><p>Convolutional codes are typically decoded via the Viterbi algorithm <ref type="bibr">[1]</ref>, <ref type="bibr">[2]</ref> that minimizes the frame error rate (FER), or the algorithm introduced by Bahl, Cocke, Jelinek, and Raviv <ref type="bibr">[3]</ref> (BCJR), that minimizes the symbol error rate. Low delay requirements have been a limiting factor for Viterbi decoders. Several works have achieved a level of parallelism to address this problem. Fettweis and Meyr <ref type="bibr">[4]</ref> combined every P stages of an K-stage trellis using a smaller trellis per each of the M states, and achieved a linear speedup of P . Mohammadidoost and Hashemi <ref type="bibr">[5]</ref> optimized the memory access for both the surviving path and the trace-back path on a GPU. Peng et al. <ref type="bibr">[6]</ref> introduce a method to achieve a high throughput also using GPU. Their method is flexible enough for application on general block codes and is shown to attain a throughput of up to 1.8 Gb/s on convolutional codes. Zhihui et al. <ref type="bibr">[7]</ref> and Hanif et al. <ref type="bibr">[8]</ref> show that part of the computations can be done independently. In <ref type="bibr">[7]</ref> a sequence is split into smaller segments and the processing of each segment is further split into an independent part and a dependent part. A matrix representation of the process is used in <ref type="bibr">[8]</ref> that allows a GPU to exploit the independence of some operations. Seshadri and Sundberg <ref type="bibr">[9]</ref> compare convolutional codes with Low Density Parity Check (LDPC) codes under delay constraints and show that convolutional codes outperform LDPC in the more restrictive regime. An FPGA version of a Viterbi decoder is also provided by Ben Asher et al. in <ref type="bibr">[10]</ref>, with parallelism that can be tuned via a parameter P . Concatenated convolutional codes like the SCPPM code are often decoder iteratively, see the parallel concatenated Turbo codes by Berrou et al. <ref type="bibr">[11]</ref> and serially concatenated codes by Benedetto et al. <ref type="bibr">[12]</ref>. In iterative decoding, two or more decoders alternate to produce a-posteriori probabilities that are used as input to the other decoders in the next</p><p>Information Source Append CRC Pulse Position Modulator Convolutional Encoder Accumulator Interleaver Channel PPM Symbol Log Likelihoods Soft BCJR Accumulator De-interleaver Soft BCJR CC ENCODER DECODER CRC Check Poisson Channel Interleave Figure 1: SCPPM Encoder model. The information generates a bit sequence to which a 32-bit error detecting CRC sequence and two zeros are appended, to obtain a K-bit, e.g. K = 7560 when the rate is 1/2. The K-bit sequence is encoded with an outer convolutional code and the output is interleaved with a quadratic interleaver. The interleaved sequence is encoded with a two-state recursive convolutional code or accumulator, and the output sequence is modulated with pulse-position modulation.</p><p>iteration. The process repeats until a stopping condition is met. The SCPPM code stops when no error is detected by an error detecting sequence or when the maximum number of iterations is exceeded. The serially concatenated (SC) pulseposition modulation (PPM) code consists of two serially concatenated convolutional codes with an interleaver between the two codes and is depicted in Fig. <ref type="figure">1</ref>.</p><p>A convolutional code is a linear block code that encodes an information sequence into another coded sequence of symbols. The input sequence could be a sequence of bits, and the outputs could be bits or words comprised of two or more bits each. A convolutional code (CC) consists of a set of states {0, . . . , M -1} and two sets of linear functions</p><p>}, where f i maps an input symbol to one or more output symbols and h i defines a state transition that maps input symbol from source state i to a destination state j. The ratio of k input symbols to n output symbols per encoding operation defines the code rate k n . The model of the SCPPM encoder is depicted in the left side of Fig. 1. At the beginning, an error detecting 32-bit cyclic redundancy check (CRC) code sequence is appended to the information sequence. Then, the information sequence, with the 32-bit CRC sequence, is encoded with a four-state, nonrecursive, zero-terminated convolutional code, which will be called the "outer code." The output of the outer code is interleaved with a quadratic interleaver, and the interleaved sequence is encoded with a two state recursive convolutional Transmitter SCPPM Iterative Decoder SCPPM Encoder Receiver Free Space Optics The transmitter emits a pulse of light at each symbol's pulsed slot, and the receiver counts the number of photos received at each slot. The input to the decoder are the photon counts for every slot of every symbol.</p><p>code, which will be called the inner code or accumulator.</p><p>The output sequence of the inner code is split into symbols that are between two and eight bits long, and each symbol is modulated with a pulse position modulation.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Contribution</head><p>Serially concatenated convolutional codes are traditionally decoded by message-passing decoders, with a separate BCJR decoder implemented for each component convolutional code. Each component BCJR decoder takes as input the output of the other component BCJR decoders and the channel symbol probabilities, according to the encoding graph.</p><p>Each decoder computes new a-posteriori probabilities that are passed along to the other component BCJR decoders.</p><p>The BJCR decoders traditionally compute the reliabilities by working sequentially through the trellis first in the forward direction and then in the backward direction <ref type="bibr">[3]</ref>. This paper presents a method to break the BCJR algorithm <ref type="bibr">[3]</ref> dependency on the values at each previous stage and instead simultaneously compute many stages to increase throughput and lower the latency of decoding.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Organization</head><p>The rest of the paper proceeds as follows: Sec. 2 describes the SCPPM code and a version of the BCJR algorithm by Bahl et al. <ref type="bibr">[3]</ref> used by the standard SCPPM decoder. Sec. 3 introduces our method to transform the BCJR algorithm to allow higher parallelism and lower the decoding time. Sec. 4 describes the implementation of the algorithms using a GPU and CUDA. Sec. 5 shows simulation results in terms of runtime performance and frame error rate vs. average photon rates, and Sec. 6 concludes the paper.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.">THE SCPPM CODE</head><p>Let the input of a code be a sequence with entries in a finite field U and outputs from a finite field F , which could be the as U . A K-symbol input sequence U = U 0 , U 1 , . . . , U K-1 is mapped to an N output sequence X where N = K n k . In this work, the value of k will be k = 1 and the output symbols are n-symbol words. Given an initial state S 0 , a convolutional code maps a K-symbol input sequence U to a unique output sequence X and a unique sequence of state S 1 , S 2 , . . . , S K , via the output and state transition functions. If the code is terminated, additional symbols are appended to the input symbol sequence U, to ensure that the last state S end , generally same as S 0 , is reached. In the next two sections, we will call the input to the inner code a K-bit sequence U and the output a N -bit sequence X, which is mapped to M -ary PPM symbols C 1 , C</p><p>2 , . . . with M &#8712; {4, 8, 32, 64, 128, 256} each encoding m bits, where m &#8712; {2, 3, . . . , 8}. The encoder's modulated output is a vector of symbols C 1 , . . . , C N/m , where symbol C i is a Time Symbol Times Symbol Symbol Symbol Pulsed Slot Non-pulsed Slots Slot Times Codeword Time Each symbol consists of 3-bits, that represent a position in 0, 1, . . . , 7. The 1 st modulated symbol is 011 = 3, the 3 rd modulated symbol is 010 = 2, the i-th modulated symbol is 100 = 4, and the last symbol is 101 = 5. A pulse is transmitted for each symbol, at positions 3, 2, 4, 5 for the 1 st , 3 rd , i th and last symbols respectively. No pulse is sent at any of the other slot positions on each symbol.</p><p>and C i has a single 1 entry. For convenience, each m-bits symbol constructed from the output of the inner code will be called an edge E, where E &#8712; {0, 1, . . . , 2 m -1} and the input to the inner code will also be grouped into symbols</p><p>Since the inner code is rate 1, the value of k for the inner code is will be k = m.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Channel Model</head><p>The channel model is a Poisson channel defined by a background noise rate of K b average photons per non-pulsed PPM slot and K s + K b average photons per pulsed PPM slot.</p><p>The received signal for each transmitted symbol i is vector Y i,j and for each PPM slot j &#8712; {0, . . . , 2 m -1} Y i,j is modeled by the probability mass functions (p.m.f.) Pr(Y i,j = y | C i,j = 0) and Pr(Y i,j = y | C i,j = 1) given by:</p><p>From now on, denote by p i,j (y) &#8796; Pr(Y i,j = y | C i,j = 1) the channel's p.m.f. in Eq. ( <ref type="formula">2</ref>).</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>The BCJR Algorithm</head><p>The BCJR algorithm of Bahl et al. <ref type="bibr">[3]</ref> is a standard component of the decoder of concatenated codes because it produces a-posteriori probabilities of its input and output sequences.</p><p>The inputs to the BCJR algorithm are the a-priori probabilities of the input and output sequences, where one of the two might be missing. The channel sequence symbol probabilities in (1) and ( <ref type="formula">2</ref>) provide the output symbol probabilities for the inner-most decoder. In serially concatenated codes, the information sequence symbol a-posteriori probabilities are the output of only the outer-most decoder, thus the outermost decoder does not get updated a-priori probabilities of the information sequence from other decoders. The outputs of the BCJR algorithm are the vector of a-posteriori probabilities of the input sequence U 1 , U 2 , . . . , U K given by Pr(U i = u | Y = y) for each u &#8712; U and the vector of a-posteriori probabilities of the output sequence X 1 , X 2 , . . . , X nK given by Pr(X i = x | Y = y) for each x &#8712; F . Given code functions f i and the channel p.m.f., we can directly compute the probabilities Pr(Y i = y i | C i,j = 1) via:</p><p>For the rest of this section we explain how to compute the output probabilities Pr(</p><p>) and a-priori probabilities Pr(U i = u; I) produced by the outer decoder, where I stands for intrinsic input probabilities. Note that for the inner decoder the input sequence U is the output sequence of the outer decoder. In the next two sections we will refer to the input of the inner decoder by</p><p>and the output a sequence of edges</p><p>that would be produced by the inner are not used and thus are omitted. These probabilities are straightforward to obtain, see <ref type="bibr">[12]</ref>. Next we express the channel probabilities</p><p>as functions of the input and state S i , that is, as</p><p>and each state s &#8712; {1, 2, . . . , M } as follows:</p><p>We are interested in the conditional probabilities: Pr(U i = u | Y = y), which may be obtained from the joint probabilities Pr(U i = u, Y = y), i = 1, 2, . . . , N and the marginal Pr(Y = y) by:</p><p>) BCJR on Outer Decoder Convolutional De-interleave BCJR on Inner Code (Accumulator) Check CRC interleave Soft Extrinsic From Channel Soft Intrinsic Soft Intrinsic Soft Extrinsic </p><p>The inner decoder produces "extrinsic" log-likelihood ratios of its input, which is de-interleaved and used as input by the outer decoder. The outer decoder produces an estimate of the input bits and extrinsic log-likelihood ratios of its output sequence. If the estimate sequence is not a codeword of the CRC code, the extrinsic output of the outer code is interleaved and combined as intrinsic input with the channel probability logs and used as input in next iterations by the inner decoder. This process continues until a codeword of the CRC code is found or the max iterations are exceeded.</p><p>The bottom Pr(Y = y) is a constant given Y that can be ignored in many cases, or it can be computed via u&#8712;U Pr(U i = u, Y = y). Then, is suffices to compute the probabilities Pr(U i = u, Y = y) as follows.</p><p>= s e:fs(u)=e</p><p>Since every next output is E i = f s (u) and every next state is S i+1 = h si (u), then the event {U i = u, S i = s} guarantees that Pr(Y = y, U i = u, S i = s, S i+1 &#824; = h s (u)) = 0, and:</p><p>The rest of this section focuses on computing the probabilities:</p><p>Let the beginning state of an edge e be b(e) and the end state be t(e). Also denote by Y j i = y i , Y i+1 , . . . , Y j , then:</p><p>1 ) as functions of the channel signal Y, the channel p.m.f and the a-priori probabilities</p><p>) may be computed by:</p><p>&#8226; Pr(</p><p>Since</p><p>. . , N/m are obtained from the channel via equations ( <ref type="formula">1</ref>), ( <ref type="formula">2</ref>) and <ref type="bibr">(7)</ref>.</p><p>Then:</p><p>= Pr(S i-1 = b(e), Y i-1</p><p>&#8226; Pr(</p><p>Computing the probabilities (25), ( <ref type="formula">26</ref>) and (27)</p><p>Let the input symbol U i consists of m bits, that is:</p><p>, with b j &#8712; {0, 1}. Denote each bit of U i by b i,j . We wish to compute the probabilities of each bit: by:</p><p>The probabilities</p><p>via Eq. ( <ref type="formula">9</ref>), with:</p><p>The values of &#963; i,j (b), for b = 0, 1 and j = 1, 2, . . . , n, i = 1, 2, . . . , N/n may be obtained from &#945; i-1 (b(e)), &#947; i (e), &#946; i (t(e)) as follows: </p><p>We have considered a set of edges that necessarily includes repeated edge patterns. That is, if the number of inputs is 2 k and the number of states is 2 &#957; , then there are 2 &#957; 2 k edges to consider. If the length of the edges is n &lt; &#957; +k then there are 2 &#957;+k-n edges with the same bit sequence. A different form that unambiguously accounts for all edges.</p><p>The values of &#963; i,j (b) may be computed using &#955; i,j (s &#8242; , s, b)</p><p>instead of &#947; i (e) as follows:</p><p>&#8226; Pr(</p><p>&#8226; Pr(</p><p>Let the input that produces edge e as output be u(e) &#8796; f -1 b(e) (e). Then, for each edge e and each i = 1, 2, . . . , N/n the values of &#947; i (e) are computed from the channel probabilities Pr(Y i = y i | E i = e) and the a-priori probabilities Pr(U i = u(e)) as follows:</p><p>Note that two edges e and e &#8242; may have the same value but have different source state b(e) &#824; = b(e &#8242; ) or destination state t(e) &#824; = t(e &#8242; ). In such case, we will still treat them as different so that the source and destination states of each edge are unique and the event {S i-1 = b(e)} is unambiguous. However, the channel probabilities will be shared by these edges.</p><p>Let &#947; i (s &#8242; , u) &#8796; &#947; i (f s &#8242; (u)), then the probabilities &#955; i,j (s, s &#8242; , b) may be computed from the values of &#947; i (e) or &#947; i (s &#8242; , u) as Figure <ref type="figure">6</ref>: Binary tree representation of the process to compute the values of &#945; i (s) for each i = 1, 2, . . . , N/m in a logarithmic number of steps, represented by the tree depth. First the values of &#948; i2 j+1 ,i2 j+1 +2 j (s &#8242; , s) are obtained for j = 1, 2, . . . , L, and each i = 1, 2, . . . , 2 L-j and each s, s &#8242; = 1, 2, . . . , M and then used to compute all &#945; i (s).</p><p>follows:</p><p>The values of &#945; i (s) and &#946; i (s) are generally computed recursively, where &#945; i (s), s = 1, . . . , M are used to obtain &#945; i+1 (s) and &#946; i+1 (s), s = 1, . . . , M are used to obtain &#946; i (s), via the Forward and Backwards algorithm <ref type="bibr">[3]</ref>. In this paper, we develop an algorithm to break the recursive dependencies, which is explained in the next section. The standard method to compute &#945; i (s) and &#946; i (s) for all i = 1, . . . , N and all s = 1, . . . , M follows:</p><p>1 , then:</p><p>The values of &#946; i (s) are computed starting from &#946; N/n (s) backwards as follows:</p><p>and the event {Y N i+1 = y N i+1 } is conditionally independent of {Y i = y i , S i-1 = s} given {S i = s &#8242; }, then:</p><p>Equation ( <ref type="formula">61</ref>) concludes the review of the standard method to obtain the values of &#945; i (s), &#946; i (s) and &#947; i (e) needed to compute each &#963; i,j (b). However, with the recursive equations ( <ref type="formula">54</ref>) and (61) the values of &#945; i (s) need to be computed before the values of &#945; i+1 (s) and the values of &#946; i (s) need to be computed before the values of &#946; i-1 (s), for each i = 1, 2, . . . , N and each s = 1, 2, . . . , M . In the next section, we break this dependency to enable computing the values of &#945; i (s) and &#946; i (s) for many values of i at the same time. The same values of &#948; i2 j+1 ,i2 j+1 +2 j (s &#8242; , s) used to compute each &#945; i (s) are used to compute each &#946; i (s).</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3.">TRELLIS REDUCTION OPERATIONS</head><p>In this section, we describe a method to compute the values of &#945; i (s), &#946; i (s) for many stages i simultaneously. The goal is to break the dependency of &#945; i+1 (s) on &#945; i (s) and of &#946; i-i (s) on &#946; i (s) and enable most of the speedup that parallel processing hardware would provide if these values could be computed independently.</p><p>The proposed method consists of a sequence of trellis reduction steps. These steps are shown in Fig. <ref type="figure">5</ref>. At each step values of &#948; i,i+1 (s &#8242; , s) of a "reduced" trellis, that skips every other stage, are computed from pairs of these values of an original trellis. First the values of &#948; i,i+1 (s &#8242; , s) are computed as follows:</p><p>Pr( </p><p>where j can be any single value from 0, 1, . . . , k -1. Given the values of &#948; i,i+1 (s &#8242; , s) for all i and all s of an original trellis, the values of &#948; j,j+2 (s &#8242; , s) of a new trellis that joins every two stages of the original trellis may be obtained by the following recursion:</p><p>Equation ( <ref type="formula">68</ref>) provides a method to compute the &#948; i,i+2 (s, s &#8242; ) given the values of deltas &#948; i,i+1 (s, s &#8242; ) and &#948; i+1,i+2 (s, s &#8242; ) of an original trellis. The initial values of &#948; i,i+1 (s, s &#8242; ) are obtained from Eq. ( <ref type="formula">62</ref>) and Eq. ( <ref type="formula">68</ref>). Then the values of &#948; i,i+2 (s, s &#8242; ) are obtained using Eq. ( <ref type="formula">68</ref>), which become the values of &#948; i,i+1 (s, s &#8242; ) on a new trellis with half the stages.</p><p>To avoid describing the trellis we are operating on, we will define by &#948; i,i+2 (s &#8242; , s) the values of &#948; i,i+1 (s &#8242; , s) on the new trellis obtained after the first trellis reduction step, then define &#948; i,i+4 (s, s &#8242; ) the values of the new trellis after the second reduction step, and so on. Note that the values of i must be a multiple of number stages of the original trellis that are combined in the most recent "new trellis," and must be a power of 2.</p><p>For ease of notation suppose that n = 1 and the number of trellis stages is a power of 2 given by N = 2 L+1 for some L.</p><p>The method to construct all values of &#948; i,j (s &#8242; , s) of the form &#948; 2 l i,2 l i+2 l (s &#8242; , s) is illustrated in the trees at the top of Fig. <ref type="figure">6</ref> and Fig. <ref type="figure">7</ref>, and is summarized in the following equations: The steps to construct such &#948; i,j (r, s &#8242; ) where i = 2 l and j = 2 l-1 (i + 1) are as follows:</p><p>. . . . . .</p><p>The &#945; i (s) and &#946; i (s), i = 1, 2, . . . , 2 L+1 , s = 1, 2, . . . , M may also be computed are also computed in a logarithmic number of steps, using the values of &#948; 2 l i,2 l i+2 l (s &#8242; , s), l = 0, 1, . . . , L, once the values of &#948; 0,2 L(s &#8242; , s) and &#948; 2 L ,2 L+1(s &#8242; , s) are obtained. This process is illustrated in the bottom trees of Fig. <ref type="figure">6</ref> and Fig. <ref type="figure">7</ref>. To start set</p><p>s, 0), then, for each j = 0, 1, . . . , L -1 and each i = 0, 1, . . . , 2 L-j compute:</p><p>With Eq. (72) and Eq. ( <ref type="formula">73</ref>) the values of &#945; 2 j+1 -2 j (s) and &#946; i2 j+1 -2 j (s) for fixed j can be computed in parallel, starting from j = L, L -1, . . . , 1, where L = log 2 (N ). This method allows to compute the &#946; i (s) and &#946; i (s) from which future values in a logarithmic number of given</p><p>3.7 3.8 3.9 4 4.1 4.2 4.3 4.4 4.5 K s (dB) 2 4 6 8 10 12 14 16 20 22 24 26 28 30 32 34 Average iterations GPU with 15120 stages CPU with 15120 stages GPU with 2 14 = 16384 stages CPU with 2 14 = 16384 stages by L = log 2 (N ).</p><p>The same holds for the &#948; i2 j ,(i+1)2 j (s &#8242; , s) values.</p><p>In the case where the code length is not a power of 2, like the case of the SCPPM code with standard length N = 15120, two sets of &#948; 2 l i,2 l i+2 l (s &#8242; , s) may need to be computed, one to compute all &#945; i (s) and one to compute all &#946; i (s). The set to compute the values of &#945; i (s) starts at the first stage, with i = 0, 1, . . . , 2 L-j for fixed j, and the set to compute the values of &#946; i (s) starts at the last stage N . That is, computing instead &#948; N -2 l i,N -2 l i+2 l (s &#8242; , s) for i = 0, 1, . . . , 2 L-j for fixed j. However, if N is multiple of a power of 2, say 2 l with l &lt; L, then majority of the values of &#948; 2 j i,2 j i+2 j (s &#8242; , s) may be re-used, that is, all for which j &#8804; l.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4.">GPU IMPLEMENTATION VIA CUDA</head><p>The Graphics Processing Unit is a massively parallel computing device with thread numbers rising to thousands. Thread is a single unit of execution that completes instructions sequentially. While threads are not completely independent, separate cores use the same instructions making development easier.</p><p>We choose CUDA as it allows control of individual threads in contrast to other programming platforms supporting GPU such as PyTorch. Synchronization may be performed even on a subset of threads and memory is manually managed. Moreover, using CUDA's finer memory management interface we utilized data locality in trellis reduction operations.</p><p>GPU groups threads into Streaming Multiprocessors (SMs) that can be used to process relevant tasks using the same data. Additionally, synchronization within an SM is faster, compared to synchronization of all threads on a GPU. While "global" memory is accessible from all threads, each SM contains an additional faster "shared" memory accessible only from threads within an SM. Another memory level, "local", is only available within a thread and is the fastest. The whole workload is divided among available SMs while only the most accessed data is stored at local and shared </p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>levels.</head><p>A naive implementation of the trellis reduction algorithm, as described in Algorithm 1, stores all data in global memory and assigns each thread a stage to process. As global memory is significantly larger than the size of all required variables, this approach is easily scaled up for larger number of stages, but runtime is limited by the memory bandwidth.</p><p>The memory hierarchy suggests further optimizations. Large arrays with rare accesses including the &#945; i (s) and &#946; i (s) values are located in global memory, while the &#947; i (e) values could remain local to the thread as the values are unused by other threads. On the other hand, the values of &#948; i,j (s &#8242; , s) are both compute-intensive and used by multiple threads. We place it in shared memory by exploiting the tree structure of trellis.</p><p>The upper part of trellis as seen in Fig. <ref type="figure">6</ref> is divided into blocks equal to the desired amount of SMs. Each block uses only its own shared memory. This approach not only improves memory access time but also removes the need for synchronization between SMs during trellis processing, as separate branches of the tree can be computed independently.</p><p>Shared memory usage acts as the main constraint for the implementation on modern Nvidia GPU architectures. The data structure containing the values of &#948; i,j (s &#8242; , s) is proportional in size to the code length and is divided between SMs. Given a GPU with enough SMs, any code length can be decoded using our implementation.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.">SIMULATION RESULTS</head><p>To verify the functionality of the proposed GPU implementation we compare GPU and baseline CPU implementations in terms of codeword error rate (CWER) performance. For the GPU implementation, we used 32 SMs with 256 threads each. CWER is measured by running each simulation until 100 codeword errors are observed (except for the last point in the GPU with N = 2 14 stages and N = 15120, where the number of errors is about 50). We run the original BCJR algorithm on the CPU and the trellis reduction algorithm on the GPU using CUDA as described in Section Performance results in of codeword error rate vs. average photons per pulsed slots K s (dB) are presented in Fig. <ref type="figure">8</ref>. The data was obtained with K b = 0 dB and with 4 PPM. The curves are essentially identical, verifying the equivalent functioning of CPU and GPU decoders. Using this simulation framework, Fig. <ref type="figure">9</ref> shows the average number of iterations required to decode a single codeword. The maximum number of iterations permitted is 32. As the noise is decreases, the expected number of iterations also decreases. The curves further confirm that the CPU and GPU implementations require the same number of iterations to achieve decoding. Thus, the runtime of a given number of iterations can be used to estimate runtime for a given K s value using either Fig. <ref type="figure">10</ref> or Fig. <ref type="figure">11</ref>.</p><p>To evaluate the runtime benefits of the GPU implementation over the CPU implementation, we decode 1000 codewords with 10 iterations required to decode a single codeword on average. In total 10000 iterations are performed to obtain a single data point. Results are gathered for GPU and CPU implementations and shown in Fig. <ref type="figure">10</ref> and Fig. <ref type="figure">11</ref>. These graphs show the same data; one uses a linear scale for the Y-axis and the other uses a log scale. We used powers of 2 for the values of N to demonstrate how runtime increases as a function of N for these two implementations. Both figures show the significant decrease in runtime achieved by the GPU implementation as compared with the CPU implementation. More stages allow for more parallelism so that the GPU runtime remains relatively constant even as N increases as long as there are sufficient hardware resources. The exact difference can be seen on the log scale graph in Fig. <ref type="figure">11</ref>. Even for 2 8 = 256 stages, GPU provides 38% speed-up. The benefit rises to 15 times runtime reduction with 2 14 = 16384 stages.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.">CONCLUSIONS</head><p>This work shows an efficient method to execute in parallel many of the computations of the BCJR algorithm that are generally computed sequentially. Provided sufficient hardware resource, a GPU can effectively use the benefits of the trellis reduction algorithm to significantly reduce the decoding time of each codeword. The GPU implementation decode also offers greater portability than other hardware implementations like an FPGA. The runtime of the GPU implementation is improved up to an order of magnitude compared to CPU when the blocklength reaches 2 14 -bits.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Future Work</head><p>The current version of the algorithm relies on normalization of the values to maintain numerical stability. The log domain version of the algorithm has better stability properties, but the latest implementation does not attain the run-time performance of the original version. In the future, we plan to explore optimizations of the log domain implementation and better memory management to improve the run-time performance. Further improvement in the run-time performance may be attained by an integer version of the log domain algorithm, aided by look-up tables.</p><p>Dariush Divsalar received the Ph.D. degree in electrical engineering from UCLA, in 1978. Since then, he has been with the Jet Propulsion Laboratory (JPL), California Institute of Technology (Caltech), Pasadena, where he is a Fellow. At JPL, he has been involved with developing state-of-the-art technology for advanced deep-space communications systems and future NASA space exploration. Since 1986, he has taught graduate courses in communications and coding at UCLA and Caltech. He </p></div></body>
		</text>
</TEI>
