package rtty; public class Turbo_encoder { private static int[][] interleaver_parameters = new int[][]{{40,3,10}, {48,7,12}, {56,19,42}, {64,7,16}, {72,7,18}, {80,11,20}, {88,5,22}, {96,11,24}, {104,7,26}, {112,41,84}, {120,103,90}, {128,15,32}, {136,9,34}, {144,17,108}, {152,9,38}, {160,21,120}, {168,101,84}, {176,21,44}, {184,57,46}, {192,23,48}, {200,13,50}, {208,27,52}, {216,11,36}, {224,27,56}, {232,85,58}, {240,29,60}, {248,33,62}, {256,15,32}, {264,17,198}, {272,33,68}, {280,103,210}, {288,19,36}, {296,19,74}, {304,37,76}, {312,19,78}, {320,21,120}, {328,21,82}, {336,115,84}, {344,193,86}, {352,21,44}, {360,133,90}, {368,81,46}, {376,45,94}, {384,23,48}, {392,243,98}, {400,151,40}, {408,155,102}, {416,25,52}, {424,51,106}, {432,47,72}, {440,91,110}, {448,29,168}, {456,29,114}, {464,247,58}, {472,29,118}, {480,89,180}, {488,91,122}, {496,157,62}, {504,55,84}, {512,31,64}, {528,17,66}, {544,35,68}, {560,227,420}, {576,65,96}, {592,19,74}, {608,37,76}, {624,41,234}, {640,39,80}, {656,185,82}, {672,43,252}, {688,21,86}, {704,155,44}, {720,79,120}, {736,139,92}, {752,23,94}, {768,217,48}, {784,25,98}, {800,17,80}, {816,127,102}, {832,25,52}, {848,239,106}, {864,17,48}, {880,137,110}, {896,215,112}, {912,29,114}, {928,15,58}, {944,147,118}, {960,29,60}, {976,59,122}, {992,65,124}, {1008,55,84}, {1024,31,64}, {1056,17,66}, {1088,171,204}, {1120,67,140}, {1152,35,72}, {1184,19,74}, {1216,39,76}, {1248,19,78}, {1280,199,240}, {1312,21,82}, {1344,211,252}, {1376,21,86}, {1408,43,88}, {1440,149,60}, {1472,45,92}, {1504,49,846}, {1536,71,48}, {1568,13,28}, {1600,17,80}, {1632,25,102}, {1664,183,104}, {1696,55,954}, {1728,127,96}, {1760,27,110}, {1792,29,112}, {1824,29,114}, {1856,57,116}, {1888,45,354}, {1920,31,120}, {1952,59,610}, {1984,185,124}, {2016,113,420}, {2048,31,64}, {2112,17,66}, {2176,171,136}, {2240,209,420}, {2304,253,216}, {2368,367,444}, {2432,265,456}, {2496,181,468}, {2560,39,80}, {2624,27,164}, {2688,127,504}, {2752,143,172}, {2816,43,88}, {2880,29,300}, {2944,45,62}, {3008,157,188}, {3072,47,96}, {3136,13,28}, {3200,111,240}, {3264,443,204}, {3328,51,104}, {3392,51,212}, {3456,451,192}, {3520,257,220}, {3584,57,336}, {3648,313,228}, {3712,271,232}, {3776,179,236}, {3840,331,120}, {3904,363,244}, {3968,375,248}, {4032,127,168}, {4096,31,64}, {4160,33,130}, {4224,43,264}, {4288,33,134}, {4352,477,408}, {4416,35,138}, {4480,233,280}, {4544,357,142}, {4608,337,480}, {4672,37,146}, {4736,71,444}, {4800,71,120}, {4864,37,152}, {4928,39,462}, {4992,127,234}, {5056,39,158}, {5120,39,80}, {5184,31,96}, {5248,113,902}, {5312,41,166}, {5376,251,336}, {5440,43,170}, {5504,21,86}, {5568,43,174}, {5632,45,176}, {5696,45,178}, {5760,161,120}, {5824,89,182}, {5888,323,184}, {5952,47,186}, {6016,23,94}, {6080,47,190}, {6144,263,480}}; public static boolean[] encode(boolean[] input, int num_out, boolean termination) { boolean[] a = input; //original input sequence boolean[] b = new boolean[input.length]; //interleaved input sequence boolean[] c = null, d = null; //urc outputs //termination bits, see Fig5.1.3-2 boolean[] xk = new boolean[3]; //uncoded termination boolean[] zk = new boolean[3]; //coded termination boolean[] zpk = new boolean[3]; //uncoded termination interleaved boolean[] xpk = new boolean[3]; //coded termination interleaved int inter_len = input.length; //interleaver length, number of bits before termination added int bits_per_stream = inter_len; //number of bits in each of d0,d1,d2 if (termination) bits_per_stream += 4; int[] interleaver = get_interleaver(inter_len); //interleave for (int i = 0; i < inter_len; i++) b[i] = a[interleaver[i]]; //encode if (termination) { c = urc_encoder_lte(a,xk,zk); d = urc_encoder_lte(b,xpk,zpk); } else { c = urc_encoder_lte(a); d = urc_encoder_lte(b); } boolean[] d0 = new boolean[bits_per_stream]; boolean[] d1 = new boolean[bits_per_stream]; boolean[] d2 = new boolean[bits_per_stream]; //copy into output streams for (int i = 0; i < inter_len; i++) { d0[i] = a[i]; d1[i] = c[i]; d2[i] = d[i]; } //termination multiplexing if (termination) { //5.1.3.2.2 int k = inter_len; d0[k] = xk[0]; d0[k+1] = zk[1]; d0[k+2] = xpk[0]; d0[k+3] = zpk[1]; d1[k] = zk[0]; d1[k+1] = xk[2]; d1[k+2] = zpk[0]; d1[k+3] = xpk[2]; d2[k] = xk[1]; d2[k+1] = zk[2]; d2[k+2] = xpk[1]; d2[k+3] = zpk[2]; } //rate matching return output_rate_matching(d0,d1,d2,num_out); } private static boolean[] urc_encoder_lte(boolean[] in) { boolean s1,s2,s3,s1_plus,s2_plus,s3_plus; s1 = false; s2 = false; s3 = false; boolean[] out = new boolean[in.length]; for (int i = 0; i < in.length; i++) { s1_plus = in[i]^s2^s3; s2_plus = s1; s3_plus = s2; out[i] = s1_plus^s1^s3; s1 = s1_plus; s2 = s2_plus; s3 = s3_plus; } return out; } private static boolean[] urc_encoder_lte(boolean[] in, boolean[] termination_un, boolean[] termination_en) { boolean s1,s2,s3,s1_plus,s2_plus,s3_plus; s1 = false; s2 = false; s3 = false; boolean[] out = new boolean[in.length]; //termination_en = new boolean[3]; //termination_un = new boolean[3]; for (int i = 0; i < in.length; i++) { s1_plus = in[i]^s2^s3; s2_plus = s1; s3_plus = s2; out[i] = s1_plus^s1^s3; s1 = s1_plus; s2 = s2_plus; s3 = s3_plus; } for (int i = 0; i < 3; i++) { s1_plus = false; s2_plus = s1; s3_plus = s2; termination_un[i] = s2^s3; termination_en[i] = s1_plus^s1^s3; s1 = s1_plus; s2 = s2_plus; s3 = s3_plus; } return out; } private static boolean[] output_rate_matching(boolean[] r0, boolean[] r1, boolean[] r2, int totalOut) { if (r0.length != r1.length) throw new IllegalArgumentException("Check Input Array Lengths"); if (r0.length != r2.length) throw new IllegalArgumentException("Check Input Array Lengths"); int D = r0.length; int colTcSb = 32; int rowTcSb = (int) Math.ceil((double)D/colTcSb); int Nd = colTcSb*rowTcSb - D; int[] v0 = subBlockInterleaver1(r0,colTcSb,rowTcSb,Nd); int[] v1 = subBlockInterleaver1(r1,colTcSb,rowTcSb,Nd); int[] v2 = subBlockInterleaver2(r2,colTcSb,rowTcSb,Nd); //output all systematic, then alternate v1/v2 until enough bits outputted boolean[] out = new boolean[totalOut]; int k = 0; //total outputted int i = 0; //array index //output systematic first while (k < totalOut && i < v0.length) { if (v0[i] >= 0) { if (v0[i] == 0) out[k] = false; else out[k] = true; k++; } i++; } //now parity i = 0; while (k < totalOut && i < v1.length) { if (v1[i] >= 0) { if (v1[i] == 0) out[k] = false; else out[k] = true; k++; } if (v2[i] >= 0 && k < totalOut) { if (v2[i] == 0) out[k] = false; else out[k] = true; k++; } i++; } return out; } //As per TS 36.212 v10.0.0, Section 5.1.4.1. public static int[] subBlockInterleaver1(boolean[] in, int colTcSb, int rowTcSb, int Nd) { if (colTcSb*rowTcSb != in.length + Nd) throw new IllegalArgumentException("Check Input Array Lengths"); int[] colPermPat = new int[] {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; int[][] y = new int[rowTcSb][colTcSb]; int[] out = new int[rowTcSb*colTcSb]; //fill matrix int k = 0; for (int i = 0; i < rowTcSb; i++){ for (int j = 0; j < colTcSb; j++){ if (Nd > 0) { y[i][j] = -2; //null Nd--; } else { y[i][j] = in[k]?1:0; k++; } } } k=0; for (int j = 0; j < colTcSb; j++){ for (int i = 0; i < rowTcSb; i++){ out[k] = y[i][colPermPat[j]]; k++; } } return out; } //As per TS 36.212 v10.0.0, Section 5.1.4.1. private static int[] subBlockInterleaver2(boolean[] in, int colTcSb, int rowTcSb, int Nd) { if (colTcSb*rowTcSb != in.length + Nd) throw new IllegalArgumentException("Check Input Array Lengths"); int[] colPermPat = new int[] {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; int[] pi = new int[colTcSb*rowTcSb]; int[] out = new int[rowTcSb*colTcSb]; for (int i = 0; i < colTcSb*rowTcSb; i++) pi[i] = (colPermPat[(int)Math.floor(i/rowTcSb)] + colTcSb*(i%rowTcSb)+1) % (colTcSb*rowTcSb); for (int i = 0; i < colTcSb*rowTcSb; i++) { if (pi[i] < Nd) out[i] = -2; //null else out[i] = in[pi[i]-Nd]?1:0; } return out; } public static int[] get_interleaver(int len) { int[] interleaver_o = new int[len]; int f1,f2; int index = find_interleaver_param_index(len); if (index < 0) throw new IllegalArgumentException("Interleaver Length not Supported"); f1 = interleaver_parameters[index][1]; f2 = interleaver_parameters[index][2]; for (int i = 0; i < len; i++) interleaver_o[i] = (f1*i+f2*i*i)%len; return interleaver_o; } public static int[] get_interleaver(int len, boolean termination) { int[] interleaver_o; if (termination) interleaver_o = new int[len+3]; else interleaver_o = new int[len]; int f1,f2; int index = find_interleaver_param_index(len); if (index < 0) throw new IllegalArgumentException("Interleaver Length not Supported"); f1 = interleaver_parameters[index][1]; f2 = interleaver_parameters[index][2]; for (int i = 0; i < len; i++) interleaver_o[i] = (f1*i+f2*i*i)%len; if (termination){ interleaver_o[len] = len; interleaver_o[len+1] = len+1; interleaver_o[len+2] = len+2; } return interleaver_o; } private static int find_interleaver_param_index(int len) { for (int i = 0; i < interleaver_parameters.length; i++) { if (interleaver_parameters[i][0] == len) return i; } return -1; } }