UNPKG

5g-polar

Version:
235 lines (220 loc) 11.5 kB
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 };