5g-polar
Version:
5G NR Polar code
235 lines (220 loc) • 11.5 kB
JavaScript
const assert = require('assert');
const {kron, multiply} = require('mathjs');
const linspace = (start, stop, step = 1) => {
const arr = [];
for (let t = start; t < stop; t += step) { arr.push(t); }
return arr;
};
// generators
const g_poly = l => {
if (l == '24A') {
return [1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1];
} else if (l == '24B') {
return [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1];
} else if (l == '24C') {
return [1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1];
} else if (l == 16) {
return [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
} else if (l == 11) {
return [1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1];
} else if (l == 6) {
return [1, 1, 0, 0, 0, 0, 1];
}
return null;
};
// crc attachment
const crc = (a, g) => {
b = [...a];
for (let i = 0; i < g.length - 1; ++i) { b.push(0); }
for (let i = 0; i < a.length; ++i) {
if (b[i] !== 0) {
for (let j = 0; j < g.length; ++j) { b[i + j] ^= g[j]; }
}
}
return b, b.slice(a.length); // b and p
};
// code block segmentation
const cb_seg_crc = (a, g, I = 2) => {
const A = a.length;
assert(A <= 1706);
const C = I === 1 ? 2 : 1;
const A_prime = Math.ceil(A/C) * C;
const a_prime = Array(A_prime);
for (let i = 0; i < A_prime - A; ++i) { a_prime[i] = 0; }
for (let i = A_prime - A; i < A_prime; ++i) { a_prime[i] = a[i - (A_prime - A)]; }
let s = 0;
const c = Array(C);
for (let r = 0; r < C; ++r) {
c[r] = Array(A_prime / C);
for (let k = 0; k < A_prime / C; ++k) {
c[r][k] = a_prime[s];
s += 1;
}
_, p = crc(c[r], g);
c[r].push(...p);
}
return c;
};
// input bits interleaving
const interleaving_input = (c, itlv_input = false) => {
if (itlv_input === false) { return c; } // no interleaving
const pattern = [0, 2, 4, 7, 9, 14, 19, 20, 24, 25, 26, 28, 31, 34, 42, 45, 49, 50, 51, 53, 54, 56, 58, 59, 61, 62, 65, 66, 67, 69, 70, 71, 72, 76, 77, 81, 82, 83, 87, 88, 89, 91, 93, 95, 98, 101, 104, 106, 108, 110, 111, 113, 115, 118, 119, 120, 122, 123, 126, 127, 129, 132, 134, 138, 139, 140, 1, 3, 5, 8, 10, 15, 21, 27, 29, 32, 35, 43, 46, 52, 55, 57, 60, 63, 68, 73, 78, 84, 90, 92, 94, 96, 99, 102, 105, 107, 109, 112, 114, 116, 121, 124, 128, 130, 133, 135, 141, 6, 11, 16, 22, 30, 33, 36, 44, 47, 64, 74, 79, 85, 97, 100, 103, 117, 125, 131, 136, 142, 12, 17, 23, 37, 48, 75, 80, 86, 137, 143, 13, 18, 38, 144, 39, 145, 40, 146, 41, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163];
const K = c.length;
const K_IL_max = 164;
const pi = Array(K);
const K_delta = K_IL_max - K;
let k = 0;
for (let m = 0; m < K_IL_max; ++m) {
if (pattern[m] >= K_delta) { pi[k++] = pattern[m] - K_delta; }
}
const c_prime = Array(K);
for (let k = 0; k < K; ++k) { c_prime[k] = c[pi[k]]; }
return c_prime;
};
// 5.4.1.1 Sub-block interleaving
const interleaving_subblock = N => {
// const N = d.length;
// const N = (Math.floor((2 - 1)/32) + 1) * 32;
const J = Array(N);
const P = [0,1,2,4,3,5,6,7,8,16,9,17,10,18,11,19,12,20,13,21,14,22,15,23,24,25,26,28,27,29,30,31]; // Table 5.4.1.1-1: Sub-block interleaver pattern
for (let n = 0; n < N; ++n) {
let i = Math.floor(32 * n / N);
J[n] = P[i] * (N / 32) + mod(n, N / 32);
}
return J;
};
const calc_N = (K, E, n_max) => {
// N is the mother code block length for the specified number of input bits (K), number of rate-matched output bits (E) and maximum value of n (NMAX).
const log2e = Math.ceil(Math.log2(E));
const R_min = 0.125;
const n_min = 5;
const n_1 = (E <= 9 / 8 * Math.pow(2, log2e - 1) && K / E < 9 / 16) ? log2e - 1 : log2e;
const n_2 = Math.ceil(Math.log2( K / R_min));
const n = Math.max(Math.min(n_1, n_2, n_max), n_min);
const N = Math.pow(2, n);
return N;
};
const calc_frozen = (K, E, n_max) => {
const N = calc_N(K, E, n_max);
const n_PC = (K >= 18 && K <= 25) ? 3 : 0;
const n_PC_wm = (n_PC === 3 && E - K > 189) ? 1 : 0;
const seq = [0,1,2,4,8,16,32,3,5,64,9,6,17,10,18,128,12,33,65,20,256,34,24,36,7,129,66,512,11,40,68,130,19,13,48,14,72,257,21,132,35,258,26,513,80,37,25,22,136,260,264,38,514,96,67,41,144,28,69,42,516,49,74,272,160,520,288,528,192,544,70,44,131,81,50,73,15,320,133,52,23,134,384,76,137,82,56,27,97,39,259,84,138,145,261,29,43,98,515,88,140,30,146,71,262,265,161,576,45,100,640,51,148,46,75,266,273,517,104,162,53,193,152,77,164,768,268,274,518,54,83,57,521,112,135,78,289,194,85,276,522,58,168,139,99,86,60,280,89,290,529,524,196,141,101,147,176,142,530,321,31,200,90,545,292,322,532,263,149,102,105,304,296,163,92,47,267,385,546,324,208,386,150,153,165,106,55,328,536,577,548,113,154,79,269,108,578,224,166,519,552,195,270,641,523,275,580,291,59,169,560,114,277,156,87,197,116,170,61,531,525,642,281,278,526,177,293,388,91,584,769,198,172,120,201,336,62,282,143,103,178,294,93,644,202,592,323,392,297,770,107,180,151,209,284,648,94,204,298,400,608,352,325,533,155,210,305,547,300,109,184,534,537,115,167,225,326,306,772,157,656,329,110,117,212,171,776,330,226,549,538,387,308,216,416,271,279,158,337,550,672,118,332,579,540,389,173,121,553,199,784,179,228,338,312,704,390,174,554,581,393,283,122,448,353,561,203,63,340,394,527,582,556,181,295,285,232,124,205,182,643,562,286,585,299,354,211,401,185,396,344,586,645,593,535,240,206,95,327,564,800,402,356,307,301,417,213,568,832,588,186,646,404,227,896,594,418,302,649,771,360,539,111,331,214,309,188,449,217,408,609,596,551,650,229,159,420,310,541,773,610,657,333,119,600,339,218,368,652,230,391,313,450,542,334,233,555,774,175,123,658,612,341,777,220,314,424,395,673,583,355,287,183,234,125,557,660,616,342,316,241,778,563,345,452,397,403,207,674,558,785,432,357,187,236,664,624,587,780,705,126,242,565,398,346,456,358,405,303,569,244,595,189,566,676,361,706,589,215,786,647,348,419,406,464,680,801,362,590,409,570,788,597,572,219,311,708,598,601,651,421,792,802,611,602,410,231,688,653,248,369,190,364,654,659,335,480,315,221,370,613,422,425,451,614,543,235,412,343,372,775,317,222,426,453,237,559,833,804,712,834,661,808,779,617,604,433,720,816,836,347,897,243,662,454,318,675,618,898,781,376,428,665,736,567,840,625,238,359,457,399,787,591,678,434,677,349,245,458,666,620,363,127,191,782,407,436,626,571,465,681,246,707,350,599,668,790,460,249,682,573,411,803,789,709,365,440,628,689,374,423,466,793,250,371,481,574,413,603,366,468,655,900,805,615,684,710,429,794,252,373,605,848,690,713,632,482,806,427,904,414,223,663,692,835,619,472,455,796,809,714,721,837,716,864,810,606,912,722,696,377,435,817,319,621,812,484,430,838,667,488,239,378,459,622,627,437,380,818,461,496,669,679,724,841,629,351,467,438,737,251,462,442,441,469,247,683,842,738,899,670,783,849,820,728,928,791,367,901,630,685,844,633,711,253,691,824,902,686,740,850,375,444,470,483,415,485,905,795,473,634,744,852,960,865,693,797,906,715,807,474,636,694,254,717,575,913,798,811,379,697,431,607,489,866,723,486,908,718,813,476,856,839,725,698,914,752,868,819,814,439,929,490,623,671,739,916,463,843,381,497,930,821,726,961,872,492,631,729,700,443,741,845,920,382,822,851,730,498,880,742,445,471,635,932,687,903,825,500,846,745,826,732,446,962,936,475,853,867,637,907,487,695,746,828,753,854,857,504,799,255,964,909,719,477,915,638,748,944,869,491,699,754,858,478,968,383,910,815,976,870,917,727,493,873,701,931,756,860,499,731,823,922,874,918,502,933,743,760,881,494,702,921,501,876,847,992,447,733,827,934,882,937,963,747,505,855,924,734,829,965,938,884,506,749,945,966,755,859,940,830,911,871,639,888,479,946,750,969,508,861,757,970,919,875,862,758,948,977,923,972,761,877,952,495,703,935,978,883,762,503,925,878,735,993,885,939,994,980,926,764,941,967,886,831,947,507,889,984,751,942,996,971,890,509,949,973,1000,892,950,863,759,1008,510,979,953,763,974,954,879,981,982,927,995,765,956,887,985,997,986,943,891,998,766,511,988,1001,951,1002,893,975,894,1009,955,1004,1010,957,983,958,987,1012,999,1016,767,989,1003,990,1005,959,1011,1013,895,1006,1014,1017,1018,991,1020,1007,1015,1019,1021,1022,1023];
const Q0 = seq.filter(q => q < N);
const J = interleaving_subblock(N);
let QF_tmp = [];
if (E < N) {
if (K / E <= 7 / 16) { // puncturing
for (let n = 0; n < N - E; ++n) {
QF_tmp.push(J[n]);
}
if ( E >= 3 * N / 4) {
QF_tmp.push(...linspace(0, Math.ceil(3 * N / 4 - E / 2)));
} else {
QF_tmp.push(...linspace(0, Math.ceil(9 * N / 16 - E / 4)));
}
QF_tmp = [...new Set(QF_tmp)];
} else { // shortening
for (let n = E; n < N; ++n) {
QF_tmp.push(J[n]);
}
}
}
const QI = Array(K + n_PC);
let j = 0;
for (let i = 0; i < N; ++i) {
const t = Q0[N - i - 1];
if (QF_tmp.includes(t)) {
continue;
}
QI[j++] = t;
if (j === K + n_PC) {
break;
}
}
const QF = Q0.filter(q0 => !QI.includes(q0));
const F = Array(N);
for (let i = 0; i < QF.length; ++i) {
const tmp = Array(QF.length);
tmp.fill(1);
F[QF[i]] = [...tmp];
}
const QPC = Array(n_PC);
if (n_PC > 0) {
for (let i = 0; i < n_PC - n_PC_wm; ++i) {
QPC[i] = QI[K + n_PC_wm + i];
}
if (n_PC_wm > 0) {
const n = Math.log2(N);
const G2 = [[1, 0], [1, 1]];
const G = Array(n);
G[0] = G2;
for (let i = 1; i < n; ++i) {
G[i] = kron(G[i-1], G2);
}
const GN = G[n-1];
const wg = GN.map(row => row.reduce((a, c) => a + c));
const QI_tilde = QI.slice(0, K);
const wt = QI_tilde.map(qi => wg[qi]);
const minw = Math.min(wt);
const minIdx = wt.filter(w => w === minw);
QPC[n_PC] = QI_tilde[minIdx[0]];
}
}
return {F, QPC, GN, n_PC_wm};
};
const encode = (a, E, link = 'DL') => { // input [c0, c1, ..., cK-1], E is rate match seq length by 5.4.1
assert(E < 8192);
let g = [], itlv_input = false, itlv_subblock = false, n_max = 0;
if (link.toLowerCase() === 'dl') {
g = g_poly('24C');
itlv_input = true;
itlv_subblock = false;
n_max = 9;
} else {
g = g_poly(11);
itlv_input = false;
itlv_subblock = true;
n_max = 10;
}
const b = crc(a, g); // input bit CRC attachment
const c = cb_seg_crc(b, g); // CB segmentation and CRC attachment
const K = c[0].length;
if (link.toLowerCase() === 'dl') { assert(K >= 36 && K <= 164); } else { assert((K >= 18 && K < 26) || (K >30 && K <= 1023)); }
const c_prime = c.map(ci => interleaving_input(ci, itlv_input)); // input bit interleaving
// get frozen bit indices and parity-check bit locations
const {F, QPC, GN} = calc_frozen(K, E, n_max);
const N = F.length, n_PC = QPC.length;
const u = Array(N);
let k = 0;
if (n_PC > 0) {
let y0 = 0, y1 = 0, y2 = 0, y3 = 0, y4 = 0;
for (let n = 0; n < N; ++n) {
yt = y0; y0 = y1; y1 = y2; y2 = y3; y3 = y4; y4 = yt;
if (F[n]) {
u[n] = 0;
} else {
if (QPC.includes(n)) {
u[n] = y0;
} else {
u[n] = c_prime[k];
k++;
y0 = mod(y0 + u[n], 2);
}
}
}
} else { // n_PC <= 0
let k = 0;
for (let n = 0; n < N; ++n) {
if (F[n] === 0) {
u[n] = c_prime[k++];
} else {
u[n] = 0;
}
}
}
let d = multiply(u, GN);
d = d.map(row => row.map(c => c % 2));
};
module.exports = {
g_poly, crc, cb_seg_crc, interleaving_input, interleaving_subblock, calc_N, calc_frozen, encode
};