This is not a specific physical channel, but this sequence (variation of the sequence) are used in many way to generate a specific sequence itself (e.g, Downlink Reference Signal) or to scramble the data of a specific channel. The Pseudo-Random Sequence used for LTE is a type of Gold Sequence defined as follows in 36.211 7.2 Pseudo-random sequence generation. (If you are not familiar with the concep of Gold Sequence, refer to Gold Code page)
The picture below is the definition from 36.211 clause 7.2, with the cinit formulas of a few channels attached. Only the initial value of the second m-sequence changes from one use to another, and that single number decides the whole output.

36.211 clause 7.2. The first m-sequence x1 always starts from 1 followed by 30 zeros. The second m-sequence x2 starts from the 31 bits of cinit, and the output c(n) is taken after NC = 1600 steps.
Followings are the list of topics to be discovered in this page.
- What is this used for ?
- How to implement ?
- Example Sequences
- Special Chat with Victor : LTE Pseudo Random Sequence in terms of Gold Code Concept
- Reference
What is this used for ?
The same generator serves many channels, so the useful question is what makes one use different from another. The answer is the initial value cinit: each channel builds it from its own mix of the cell identity, the slot number, the RNTI and other parameters.
What are we use this for ? There are several different application for this sequence as listed below.
- Generation of Downlink Reference Signal : Two of this Pseudo Random Sequence (Gold Sequence) is used
- Scrambling of PDSCH
- Scrambling of PMCH
- Scrambling of PDCCH
- Generation of PUSCH DMRS (e.g, PUSCH DMRS - 1RB)
The table below lists the cinit of the most common uses, from 36.211 v19.3.0. For the downlink reference signal, one sequence gives two bits per QPSK symbol, c(2m) and c(2m+1), rather than two separate sequences.
Use | 36.211 clause | cinit | Re-initialised |
PDSCH scrambling | 6.3.1 | nRNTI 214 + q 213 + ⌊ns/2⌋ 29 + NIDcell | every subframe |
PMCH scrambling | 6.3.1 | ⌊ns/2⌋ 29 + NIDMBSFN | every subframe |
PBCH scrambling | 6.6.1 | NIDcell | every frame with nf mod 4 = 0 |
PCFICH scrambling | 6.7.1 | (⌊ns/2⌋ + 1)(2NIDcell + 1) 29 + NIDcell | every subframe |
PDCCH scrambling | 6.8.2 | ⌊ns/2⌋ 29 + NIDcell | every subframe |
PHICH scrambling | 6.9.1 | (⌊ns/2⌋ + 1)(2NIDcell + 1) 29 + NIDcell | every subframe |
Cell-specific RS | 6.10.1.1 | 210(7(ns + 1) + l + 1)(2NIDcell + 1) + 2NIDcell + NCP | every OFDM symbol |
PUSCH scrambling | 5.3.1 | nRNTI 214 + q 213 + ⌊ns/2⌋ 29 + NIDcell | every subframe |
PUSCH DMRS cyclic shift nPN | 5.5.2.1.1 | ⌊NIDcell/30⌋ 25 + fssPUSCH | every frame |
Two patterns stand out. The PCFICH, the PHICH and the CRS multiply by (2NIDcell + 1), so their sequences differ between neighbour cells. The data channels put the RNTI in the top bits, so two UEs in one cell get different sequences. The slot term changes the sequence from subframe to subframe, which spreads inter-cell interference over time.
One generator for many channels : only cinit changes.Cell ID in every cinit : neighbour cells get different sequences.RNTI in the data channels : each UE gets its own scrambling.
How to implement ?
I will show you a couple of different ways of implementing this pseudo random sequence here. Depending on the language that you use and your programming style, you would have a little bit different code. Matlab communication package and srsLTE API is verified code, but my MatLab code is not verified but I hope it is written correctly.
All four implementations below compute the same two recursions from 36.211 clause 7.2. They differ in memory use and in how much of the arithmetic they hide in a library, and the section Example Sequences checks that they agree.
Matlab Communication Package
If you have access to Matlab Communication Toolbox, you can implement this sequence as shown below. (This Matlab code clip is from the book : Understanding LTE with Matlab)

comm.GoldSequence set up for 36.211 clause 7.2. The polynomial vectors encode x31 + x3 + 1 and x31 + x3 + x2 + x + 1, and 'Shift', 1600 is NC.
The polynomial vectors list the coefficients from x31 down to x0. So [1 zeros(1, 27) 1 0 0 1] is x31 + x3 + 1, the recursion of x1, and [1 zeros(1, 27) 1 1 1 1] is the recursion of x2. The second initial condition comes from an input port, so the same object can take a new cinit for every call.
srsLTE
The srsLTE code below is the direct form of the definition. It stores the full arrays x1 and x2 of length NC + length + 31, runs both recursions, and then adds the two arrays from index NC.
Following is the implementation in srsLTE.
void srslte_sequence_set_LTE_pr(srslte_sequence_t *q, uint32_t seed) {
int n;
uint32_t *x1, *x2;
x1 = calloc(Nc + q->len + 31, sizeof(uint32_t));
if (!x1) {
perror("calloc");
return;
}
x2 = calloc(Nc + q->len + 31, sizeof(uint32_t));
if (!x2) {
free(x1);
perror("calloc");
return;
}
for (n = 0; n < 31; n++) {
x2[n] = (seed >> n) & 0x1;
}
x1[0] = 1;
for (n = 0; n < Nc + q->len; n++) {
x1[n + 31] = (x1[n + 3] + x1[n]) & 0x1;
x2[n + 31] = (x2[n + 3] + x2[n + 2] + +x2[n+1] + x2[n]) & 0x1;
}
for (n = 0; n < q->len; n++) {
q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1;
}
free(x1);
free(x2);
}
The seed bits fill x2(0) to x2(30) with the least significant bit first, which matches cinit = Σ x2(i) 2i. The expression "+ +x2[n+1]" contains a unary plus, which C accepts, so the line still adds the four terms of the x2 recursion.
My own MatLab code
Following is the Matlab code that I wrote using Matlab default function only. This would be very inefficient at machine level. You may not see this kind of implement at professional code example. But I wrote the code to make it look as closer to the way described in 3GPP document as possible. The purpose of this code is to give you better understanding of the 3GPP spec.
clear all;
% Initial condition of the polynomia x1(). This is fixed value as described in 36.211 7.2
x1_init = [1 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 ...
0];
% Initial condition of the polynomia x2().
% This is supposed to be used as c_init as described in 36.211 7.2
% But for simplicity, I just se the arbitrary value for now
x2_init = [0 0 0 0 0 0 1 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 ...
0];
% Mpn is the length of the final sequence c()
Mpn = 12*10;
% Nc as defined in 36.211 7.2
Nc = 1600;
% Create a vector(array) for x1() and x2() all initialized with 0
x1 = zeros(1,Nc + Mpn + 31);
x2 = zeros(1,Nc + Mpn + 31);
% Create a vector(array) for c() all initialized with 0
c = zeros(1,Mpn);
% Initialize x1() and x2()
x1(1:31) = x1_init;
x2(1:31) = x2_init;
% generate the m-sequence : x1()
for n = 1 : (Mpn+Nc)
x1(n+31) = mod(x1(n+3) + x1(n),2);
end;
% generate the m-sequence : x2()
for n = 1 : (Mpn+Nc)
x2(n+31) = mod(x2(n+3) + x2(n+2) + x2(n+1) + x2(n),2);
end;
% generate the resulting sequence (Gold Sequence) : c()
for n = 1 : Mpn
c(n)= mod(x1(n+Nc) + x2(n+Nc),2);
end;
% Following has no meaning in practice, but I just plotted the result just to give you
% overall pattern
subplot(3,1,1);
stem(x1);xlim([1 length(x1)]); ylabel('x1(n)');
subplot(3,1,2);
stem(x2);xlim([1 length(x2)]); ylabel('x2(n)');
subplot(3,1,3);
stem(c);xlim([1 length(c)]); ylabel('c(n)');

MATLAB indexes arrays from 1, so x1(1) in the code is x1(0) in the specification, and c(n) = x1(n+Nc) + x2(n+Nc) with n = 1 is c(0) of the specification. The code sets x2_init with a single 1 in the 7th position, which is cinit = 26 = 64. The plot above shows the long x1 and x2 arrays and the 120 output bits c(n).
Code from Victor Ivanov
Following is the code written by Victor Ivanov (vic.m.ivanov[at]gmail.com ) and shared here with permission by him. Depending on your background, it may be a little bit difficult to understand comparing to the two other examples shown above. But in terms of shift register logic this code would be more relavant. That is, this code would better represent the hardware implementation of the sequence.
Following is the comments from Victor when he was sharing the code with me. I always like to read some comments from experts, coming directly out of his mind without considering much on formal writing. Once we try thinking of formal writing, it tend to dry and less lively :). I hope this give some insight for other readers as well.
Having looked at the examples, it struck me that both the Matlab as well as the one from srsLTE, while easy to understand, use a lot of memory as they allocate space for at least (Nc + Mpn) to perform the computation after which only the last Mpn elements are taken into account. They both make use of traditional additions making them slow. You've already put a disclaimer on that so that's ok. But more importantly, with the hardware based implementation of gold sequence generation using LFSRs (explained here: GoldCode ) initially I found it difficult to relate how the 3GPP examples fit together with the LFSR logic.
So I thought you might be interested in adding the following C function that I quickly drafted to your page for the scrambling sequence generation. It can allocates memory for only Mpn bits and works entirely with bitwise operations making it at least twice and up to several times faster to compute the scrambling sequence 'c'.
#include <stdint.h>
#include <stdlib.h>
uint8_t* generate_sequence(uint32_t seed, uint32_t length) {
int Nc = 1600;
int n;
uint32_t x1, x2; // m-sequence 'registers'
uint32_t x1_fb, x2_fb; // LFSR feedback values
uint8_t *c;
c = malloc(length * sizeof(uint8_t));
x1 = 0x1;
x2 = seed;
for (n = 0; n < Nc + length; n++) {
if (n >= Nc) {
// Only start taking values for 'c' after seeding
c[n - Nc] = (x1 ^ x2) & 0x1;
}
// Advance the 1st m-sequence
x1_fb = ((x1 >> 0) ^ (x1 >> 3)) & 0x1;
x1 = (x1 >> 1) | (x1_fb << 30);
// Advance the 2nd m-sequence
x2_fb = ((x2 >> 0) ^ (x2 >> 1) ^ (x2 >> 2) ^ (x2 >> 3)) & 0x1;
x2 = (x2 >> 1) | (x2_fb << 30);
}
return c;
}
Each m-sequence here is a 31-bit register. Bit 0 holds x(n) and bit 30 holds x(n+30), so the feedback x1(n+31) is bit 0 XOR bit 3, and the register shifts right with the feedback entering at bit 30. The register form needs only the output array, which is why it saves the NC + length words of the array versions.
Four implementations, one definition : 36.211 clause 7.2.Seed bit i is x2(i) : least significant bit first.Register form : no arrays of length NC needed.
Example Sequences
Do the four implementations really produce the same bits? A Python version of the 36.211 definition and a Python version of the register code from Victor Ivanov give identical output for every cinit tried, including 0, 1, 64, 12345 and 230 + 7.
The table below gives the first 16 bits c(0) to c(15) for a few cinit values. The value 1 is the PDCCH of PCI 1 in slot 0, the value 1537 is the PCFICH of the same cell, and 24579 is the CRS of PCI 1 in symbol 0 of slot 0 with normal cyclic prefix. The value 1638401 is the PDSCH of RNTI 100 in PCI 1, codeword 0, slot 0.
cinit | Use | c(0) to c(15) |
0 | no x2 contribution | 0000001000011010 |
1 | PDCCH, PCI 1, slot 0 | 0000001010000011 |
64 | x2_init of the MATLAB code above | 0001111000000110 |
1537 | PCFICH, PCI 1, slot 0 | 0110000011000001 |
24579 | CRS, PCI 1, slot 0, symbol 0 | 1110010001110010 |
1638401 | PDSCH, RNTI 100, PCI 1, slot 0 | 1101001110011100 |
Values 0 and 1 differ only from c(8) onward, although their cinit differ in one bit. That is the reason for NC = 1600: without the 1600 warm-up steps, two close cinit values would give sequences that agree for many bits. Over 10000 bits of cinit = 1, the output holds 4822 ones, close to the half that a random-looking sequence should have.
The warm-up can be measured. Without it, with NC = 0, the sequences for cinit = 0 and cinit = 1 differ in only 10 of their first 100 bits, at positions 0, 31, 59 and a few later ones. With NC = 1600 they differ in 42 of the first 100 bits, close to the 50 expected from two unrelated sequences.
The same check works between cells. Mapping 0 to +1 and 1 to -1, the correlation over 1000 bits is 44 between the PDCCH sequences of PCI 1 and PCI 2 in slot 0, and 62 between their PCFICH sequences, cinit = 1537 and 2562. Both are small against the 1000 that identical sequences would give, so a UE that descrambles with the wrong cell gets noise rather than a valid channel.
All implementations agree : checked for several cinit values.NC = 1600 decorrelates close seeds : one changed bit changes the whole output.About half the bits are 1 : 4822 of 10000 for cinit = 1.
Special Chat with Victor : LTE Pseudo Random Sequence in terms of Gold Code Concept
I had some chat with Victor in email about LTE Pseudo Random Sequence in terms of Gold Code Concept and I thought the comment / explanation can be helpful (very practical explanation) for other readers, especially for the person like me who is not a real expert on this low layer implementation. So I decided to share the chat here with his permission of course.
[Victor] (...) it's not immediately obvious why it works and how it fits with the Gold Sequence LFSR diagram",
[Sharetechnot] Sorry if I confused you, in my understanding LFSR, m-Sequence, Gold Sequence is a TYPE of sequence generation algorithm which has a certain kind of characteristics, they do not indicate any specific sequence of numbers.
Gold Sequence is generated by combining two m-Sequence (m-Sequence is a type of LFSR) as illustrated in my Gold Sequence page (number of shift register and wiring may vary as long as it meets a certain set of characterstics).
In LTE PRS, I think c[] is a type of Gold Sequence which is made up of two m-Sequence (x1[], x2[]).
[Victor] No problem at all. I too have mostly been using it to understand / study it. My research is actually in computer microarchitecture for 5G. It's difficult to say how it's currently implemented in real hardware as a lot of it is proprietary information of chip manufacturers and hardly any of it is available in the public domain.
Your understanding of the Gold Sequence is correct. My confusion did not come from your Gold Code diagram itself, but the question I was trying to answer to myself was "How do I implement the LTE sequence generator as gold code in hardware with LFSRs?". Which was difficult to answer from the Matlab and srsLTE code as they do not describe LFSR logic but rather in-memory computation of arrays.
But since Gold Code does, in fact, combine two m-sequences to generate the Gold sequence and each m-sequence can be easily implemented (in hardware) with a linear feedback shift register (LFSR), like the two on your Gold Code page. And the way we describe which individual bits are used in the feedback logic of the LFSR is by generator polynomials. In fact, it's the generator polynomials that tells us exactly what the wiring of the LFSR is. In the 3GPP LTE PHY specs, the two equations for x1(n+31)=... and x2(n+31)=... essentially describe (in a non-obvious way) the two generator polynomials for the two m-sequences that the LTE Gold Code generator uses:
G(m1) = x^3 + 1 (derived from x1(n+31)=...)
G(m2) = x^3 + x^2 + x^1 + 1 (derived from x2(n+31)=...)
Once we know these, along with the fact that in 3GPP LTE the two m-sequences are 31 bits wide (as specified in chapter 7.2) we can go back to your Gold Code circuit diagram and create the same diagram with 31 [D] cells (each [D] cell stores a single bit) and making our feedback wiring based on based on the above generator polynomials (see attached diagram for the LTE Gold Code generator).
You could have different wiring and it would still produce a valid Gold Code sequence, but if the wiring is different it will produce a different sequence. Thus, there can only be one exact wiring in LTE that can be used which is described by the above generator polynomials.
But to have the circuit actually generate any bit sequence at all it must have an initial value. For example, if the Gold Code circuit that you have on your page had a value of 0 stored in each [D] cell for both the top and bottom LFSR, then the output for c[n] will always be 0, regardless of how many clock cycles pass and it won't generate any sequence at all.
This is why 3GPP specifies the _initial_ values for the m1 and m2 sequences. Assuming the LTE PRS generator is implemented with two shift registers (as in your Gold Code diagram), the initial value for the 1st m-sequence LFSR is always set to 0x1, meaning that all the left-most 30 [D] cells of the shift register will hold a value of 0, and the right-most [D] cell will have a value of 1.
The _initial_ value of the 2nd m-sequence LFSR is the binary value for c_init which varies for each channel (xPDSCH, xPDCH, etc) and device, and the way it's computed is described in the specs for each channel.
And before we start taking the values for c[n] we let the circuit shuffle around for Nc=1600 cycles to induce extra randomness for the initial state. We can then start taking the bit values coming out of the circuit for c[n].
The example binary number (00...101101) that I gave in my previous email is completely arbitrary and not related to LTE specifically, but it serves well to demonstrate how the code works and how it relates to the Gold Code circuit that you have (which for me was difficult to comprehend initially). And since the code uses binary shift operators, we can immediately see how the two real shift registers of the Gold Code generator would behave (if implemented with LFSR logic).
In short, the chat reaches the same picture as the table in the first section. The wiring of both LFSRs is fixed by the two polynomials, the first register always starts from 1, and the only thing a channel chooses is the starting value of the second register.
Gold sequence = two m-sequences XORed : x1 and x2 in 36.211.Fixed wiring, variable start : cinit is the start of the second register.NC = 1600 warm-up : the output is taken after 1600 shifts.
Reference
[1] 3GPP TS 36.211 v19.3.0 - clause 7.2, Pseudo-random sequence generation, and the scrambling and reference-signal clauses listed in the table above