mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-30 20:40:20 -04:00 
			
		
		
		
	Merge branch 'f4exb:master' into freq_scanner
This commit is contained in:
		
						commit
						b2778d9138
					
				| @ -1,6 +1,7 @@ | |||||||
| project(ft8) | project(ft8) | ||||||
| 
 | 
 | ||||||
| set(ft8_SOURCES | set(ft8_SOURCES | ||||||
|  |     arrays.cpp | ||||||
|     fft.cpp |     fft.cpp | ||||||
|     fftbuffers.cpp |     fftbuffers.cpp | ||||||
|     ft8.cpp |     ft8.cpp | ||||||
| @ -8,12 +9,14 @@ set(ft8_SOURCES | |||||||
|     ft8plans.cpp |     ft8plans.cpp | ||||||
|     libldpc.cpp |     libldpc.cpp | ||||||
|     osd.cpp |     osd.cpp | ||||||
|     unpack.cpp |     packing.cpp | ||||||
|  |     pack0.cpp | ||||||
|     unpack0.cpp |     unpack0.cpp | ||||||
|     util.cpp |     util.cpp | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| set(ft8_HEADERS | set(ft8_HEADERS | ||||||
|  |     arrays.h | ||||||
|     fft.h |     fft.h | ||||||
|     fftbuffers.h |     fftbuffers.h | ||||||
|     ft8.h |     ft8.h | ||||||
| @ -21,7 +24,9 @@ set(ft8_HEADERS | |||||||
|     ft8plans.h |     ft8plans.h | ||||||
|     libldpc.h |     libldpc.h | ||||||
|     osd.h |     osd.h | ||||||
|     unpack.h |     packing.h | ||||||
|  |     pack0.h | ||||||
|  |     unpack0.h | ||||||
|     util.h |     util.h | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										390
									
								
								ft8/arrays.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								ft8/arrays.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,390 @@ | |||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Copyright (C) 2023 Edouard Griffiths, F4EXB <f4exb06@gmail.com>               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This is the code from ft8mon: https://github.com/rtmrtmrtmrtm/ft8mon          //
 | ||||||
|  | // reformatted and adapted to Qt and SDRangel context                            //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is free software; you can redistribute it and/or modify          //
 | ||||||
|  | // it under the terms of the GNU General Public License as published by          //
 | ||||||
|  | // the Free Software Foundation as version 3 of the License, or                  //
 | ||||||
|  | // (at your option) any later version.                                           //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is distributed in the hope that it will be useful,               //
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||||
|  | // GNU General Public License V3 for more details.                               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // You should have received a copy of the GNU General Public License             //
 | ||||||
|  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | #include "arrays.h" | ||||||
|  | 
 | ||||||
|  | namespace FT8 { | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // this is the LDPC(174,91) parity check matrix.
 | ||||||
|  | // each row describes one parity check.
 | ||||||
|  | // 83 rows.
 | ||||||
|  | // each number is an index into the codeword (1-origin).
 | ||||||
|  | // the codeword bits mentioned in each row must xor to zero.
 | ||||||
|  | // From WSJT-X's ldpc_174_91_c_reordered_parity.f90
 | ||||||
|  | //
 | ||||||
|  | const int Arrays::Nm[][7] = { | ||||||
|  |     {  4,  31,  59,  91,  92,  96, 153 }, | ||||||
|  |     {  5,  32,  60,  93, 115, 146,   0 }, | ||||||
|  |     {  6,  24,  61,  94, 122, 151,   0 }, | ||||||
|  |     {  7,  33,  62,  95,  96, 143,   0 }, | ||||||
|  |     {  8,  25,  63,  83,  93,  96, 148 }, | ||||||
|  |     {  6,  32,  64,  97, 126, 138,   0 }, | ||||||
|  |     {  5,  34,  65,  78,  98, 107, 154 }, | ||||||
|  |     {  9,  35,  66,  99, 139, 146,   0 }, | ||||||
|  |     { 10,  36,  67, 100, 107, 126,   0 }, | ||||||
|  |     { 11,  37,  67,  87, 101, 139, 158 }, | ||||||
|  |     { 12,  38,  68, 102, 105, 155,   0 }, | ||||||
|  |     { 13,  39,  69, 103, 149, 162,   0 }, | ||||||
|  |     {  8,  40,  70,  82, 104, 114, 145 }, | ||||||
|  |     { 14,  41,  71,  88, 102, 123, 156 }, | ||||||
|  |     { 15,  42,  59, 106, 123, 159,   0 }, | ||||||
|  |     {  1,  33,  72, 106, 107, 157,   0 }, | ||||||
|  |     { 16,  43,  73, 108, 141, 160,   0 }, | ||||||
|  |     { 17,  37,  74,  81, 109, 131, 154 }, | ||||||
|  |     { 11,  44,  75, 110, 121, 166,   0 }, | ||||||
|  |     { 45,  55,  64, 111, 130, 161, 173 }, | ||||||
|  |     {  8,  46,  71, 112, 119, 166,   0 }, | ||||||
|  |     { 18,  36,  76,  89, 113, 114, 143 }, | ||||||
|  |     { 19,  38,  77, 104, 116, 163,   0 }, | ||||||
|  |     { 20,  47,  70,  92, 138, 165,   0 }, | ||||||
|  |     {  2,  48,  74, 113, 128, 160,   0 }, | ||||||
|  |     { 21,  45,  78,  83, 117, 121, 151 }, | ||||||
|  |     { 22,  47,  58, 118, 127, 164,   0 }, | ||||||
|  |     { 16,  39,  62, 112, 134, 158,   0 }, | ||||||
|  |     { 23,  43,  79, 120, 131, 145,   0 }, | ||||||
|  |     { 19,  35,  59,  73, 110, 125, 161 }, | ||||||
|  |     { 20,  36,  63,  94, 136, 161,   0 }, | ||||||
|  |     { 14,  31,  79,  98, 132, 164,   0 }, | ||||||
|  |     {  3,  44,  80, 124, 127, 169,   0 }, | ||||||
|  |     { 19,  46,  81, 117, 135, 167,   0 }, | ||||||
|  |     {  7,  49,  58,  90, 100, 105, 168 }, | ||||||
|  |     { 12,  50,  61, 118, 119, 144,   0 }, | ||||||
|  |     { 13,  51,  64, 114, 118, 157,   0 }, | ||||||
|  |     { 24,  52,  76, 129, 148, 149,   0 }, | ||||||
|  |     { 25,  53,  69,  90, 101, 130, 156 }, | ||||||
|  |     { 20,  46,  65,  80, 120, 140, 170 }, | ||||||
|  |     { 21,  54,  77, 100, 140, 171,   0 }, | ||||||
|  |     { 35,  82, 133, 142, 171, 174,   0 }, | ||||||
|  |     { 14,  30,  83, 113, 125, 170,   0 }, | ||||||
|  |     {  4,  29,  68, 120, 134, 173,   0 }, | ||||||
|  |     {  1,   4,  52,  57,  86, 136, 152 }, | ||||||
|  |     { 26,  51,  56,  91, 122, 137, 168 }, | ||||||
|  |     { 52,  84, 110, 115, 145, 168,   0 }, | ||||||
|  |     {  7,  50,  81,  99, 132, 173,   0 }, | ||||||
|  |     { 23,  55,  67,  95, 172, 174,   0 }, | ||||||
|  |     { 26,  41,  77, 109, 141, 148,   0 }, | ||||||
|  |     {  2,  27,  41,  61,  62, 115, 133 }, | ||||||
|  |     { 27,  40,  56, 124, 125, 126,   0 }, | ||||||
|  |     { 18,  49,  55, 124, 141, 167,   0 }, | ||||||
|  |     {  6,  33,  85, 108, 116, 156,   0 }, | ||||||
|  |     { 28,  48,  70,  85, 105, 129, 158 }, | ||||||
|  |     {  9,  54,  63, 131, 147, 155,   0 }, | ||||||
|  |     { 22,  53,  68, 109, 121, 174,   0 }, | ||||||
|  |     {  3,  13,  48,  78,  95, 123,   0 }, | ||||||
|  |     { 31,  69, 133, 150, 155, 169,   0 }, | ||||||
|  |     { 12,  43,  66,  89,  97, 135, 159 }, | ||||||
|  |     {  5,  39,  75, 102, 136, 167,   0 }, | ||||||
|  |     {  2,  54,  86, 101, 135, 164,   0 }, | ||||||
|  |     { 15,  56,  87, 108, 119, 171,   0 }, | ||||||
|  |     { 10,  44,  82,  91, 111, 144, 149 }, | ||||||
|  |     { 23,  34,  71,  94, 127, 153,   0 }, | ||||||
|  |     { 11,  49,  88,  92, 142, 157,   0 }, | ||||||
|  |     { 29,  34,  87,  97, 147, 162,   0 }, | ||||||
|  |     { 30,  50,  60,  86, 137, 142, 162 }, | ||||||
|  |     { 10,  53,  66,  84, 112, 128, 165 }, | ||||||
|  |     { 22,  57,  85,  93, 140, 159,   0 }, | ||||||
|  |     { 28,  32,  72, 103, 132, 166,   0 }, | ||||||
|  |     { 28,  29,  84,  88, 117, 143, 150 }, | ||||||
|  |     {  1,  26,  45,  80, 128, 147,   0 }, | ||||||
|  |     { 17,  27,  89, 103, 116, 153,   0 }, | ||||||
|  |     { 51,  57,  98, 163, 165, 172,   0 }, | ||||||
|  |     { 21,  37,  73, 138, 152, 169,   0 }, | ||||||
|  |     { 16,  47,  76, 130, 137, 154,   0 }, | ||||||
|  |     {  3,  24,  30,  72, 104, 139,   0 }, | ||||||
|  |     {  9,  40,  90, 106, 134, 151,   0 }, | ||||||
|  |     { 15,  58,  60,  74, 111, 150, 163 }, | ||||||
|  |     { 18,  42,  79, 144, 146, 152,   0 }, | ||||||
|  |     { 25,  38,  65,  99, 122, 160,   0 }, | ||||||
|  |     { 17,  42,  75, 129, 170, 172,   0 }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Mn from WSJT-X's ldpc_174_91_c_reordered_parity.f90
 | ||||||
|  | // each of the 174 rows corresponds to a codeword bit.
 | ||||||
|  | // the numbers indicate which three parity
 | ||||||
|  | // checks (rows in Nm) refer to the codeword bit.
 | ||||||
|  | // 1-origin.
 | ||||||
|  | const int Arrays::Mn[][3] = { | ||||||
|  |     {  16,  45,  73 }, | ||||||
|  |     {  25,  51,  62 }, | ||||||
|  |     {  33,  58,  78 }, | ||||||
|  |     {   1,  44,  45 }, | ||||||
|  |     {   2,   7,  61 }, | ||||||
|  |     {   3,   6,  54 }, | ||||||
|  |     {   4,  35,  48 }, | ||||||
|  |     {   5,  13,  21 }, | ||||||
|  |     {   8,  56,  79 }, | ||||||
|  |     {   9,  64,  69 }, | ||||||
|  |     {  10,  19,  66 }, | ||||||
|  |     {  11,  36,  60 }, | ||||||
|  |     {  12,  37,  58 }, | ||||||
|  |     {  14,  32,  43 }, | ||||||
|  |     {  15,  63,  80 }, | ||||||
|  |     {  17,  28,  77 }, | ||||||
|  |     {  18,  74,  83 }, | ||||||
|  |     {  22,  53,  81 }, | ||||||
|  |     {  23,  30,  34 }, | ||||||
|  |     {  24,  31,  40 }, | ||||||
|  |     {  26,  41,  76 }, | ||||||
|  |     {  27,  57,  70 }, | ||||||
|  |     {  29,  49,  65 }, | ||||||
|  |     {   3,  38,  78 }, | ||||||
|  |     {   5,  39,  82 }, | ||||||
|  |     {  46,  50,  73 }, | ||||||
|  |     {  51,  52,  74 }, | ||||||
|  |     {  55,  71,  72 }, | ||||||
|  |     {  44,  67,  72 }, | ||||||
|  |     {  43,  68,  78 }, | ||||||
|  |     {   1,  32,  59 }, | ||||||
|  |     {   2,   6,  71 }, | ||||||
|  |     {   4,  16,  54 }, | ||||||
|  |     {   7,  65,  67 }, | ||||||
|  |     {   8,  30,  42 }, | ||||||
|  |     {   9,  22,  31 }, | ||||||
|  |     {  10,  18,  76 }, | ||||||
|  |     {  11,  23,  82 }, | ||||||
|  |     {  12,  28,  61 }, | ||||||
|  |     {  13,  52,  79 }, | ||||||
|  |     {  14,  50,  51 }, | ||||||
|  |     {  15,  81,  83 }, | ||||||
|  |     {  17,  29,  60 }, | ||||||
|  |     {  19,  33,  64 }, | ||||||
|  |     {  20,  26,  73 }, | ||||||
|  |     {  21,  34,  40 }, | ||||||
|  |     {  24,  27,  77 }, | ||||||
|  |     {  25,  55,  58 }, | ||||||
|  |     {  35,  53,  66 }, | ||||||
|  |     {  36,  48,  68 }, | ||||||
|  |     {  37,  46,  75 }, | ||||||
|  |     {  38,  45,  47 }, | ||||||
|  |     {  39,  57,  69 }, | ||||||
|  |     {  41,  56,  62 }, | ||||||
|  |     {  20,  49,  53 }, | ||||||
|  |     {  46,  52,  63 }, | ||||||
|  |     {  45,  70,  75 }, | ||||||
|  |     {  27,  35,  80 }, | ||||||
|  |     {   1,  15,  30 }, | ||||||
|  |     {   2,  68,  80 }, | ||||||
|  |     {   3,  36,  51 }, | ||||||
|  |     {   4,  28,  51 }, | ||||||
|  |     {   5,  31,  56 }, | ||||||
|  |     {   6,  20,  37 }, | ||||||
|  |     {   7,  40,  82 }, | ||||||
|  |     {   8,  60,  69 }, | ||||||
|  |     {   9,  10,  49 }, | ||||||
|  |     {  11,  44,  57 }, | ||||||
|  |     {  12,  39,  59 }, | ||||||
|  |     {  13,  24,  55 }, | ||||||
|  |     {  14,  21,  65 }, | ||||||
|  |     {  16,  71,  78 }, | ||||||
|  |     {  17,  30,  76 }, | ||||||
|  |     {  18,  25,  80 }, | ||||||
|  |     {  19,  61,  83 }, | ||||||
|  |     {  22,  38,  77 }, | ||||||
|  |     {  23,  41,  50 }, | ||||||
|  |     {   7,  26,  58 }, | ||||||
|  |     {  29,  32,  81 }, | ||||||
|  |     {  33,  40,  73 }, | ||||||
|  |     {  18,  34,  48 }, | ||||||
|  |     {  13,  42,  64 }, | ||||||
|  |     {   5,  26,  43 }, | ||||||
|  |     {  47,  69,  72 }, | ||||||
|  |     {  54,  55,  70 }, | ||||||
|  |     {  45,  62,  68 }, | ||||||
|  |     {  10,  63,  67 }, | ||||||
|  |     {  14,  66,  72 }, | ||||||
|  |     {  22,  60,  74 }, | ||||||
|  |     {  35,  39,  79 }, | ||||||
|  |     {   1,  46,  64 }, | ||||||
|  |     {   1,  24,  66 }, | ||||||
|  |     {   2,   5,  70 }, | ||||||
|  |     {   3,  31,  65 }, | ||||||
|  |     {   4,  49,  58 }, | ||||||
|  |     {   1,   4,   5 }, | ||||||
|  |     {   6,  60,  67 }, | ||||||
|  |     {   7,  32,  75 }, | ||||||
|  |     {   8,  48,  82 }, | ||||||
|  |     {   9,  35,  41 }, | ||||||
|  |     {  10,  39,  62 }, | ||||||
|  |     {  11,  14,  61 }, | ||||||
|  |     {  12,  71,  74 }, | ||||||
|  |     {  13,  23,  78 }, | ||||||
|  |     {  11,  35,  55 }, | ||||||
|  |     {  15,  16,  79 }, | ||||||
|  |     {   7,   9,  16 }, | ||||||
|  |     {  17,  54,  63 }, | ||||||
|  |     {  18,  50,  57 }, | ||||||
|  |     {  19,  30,  47 }, | ||||||
|  |     {  20,  64,  80 }, | ||||||
|  |     {  21,  28,  69 }, | ||||||
|  |     {  22,  25,  43 }, | ||||||
|  |     {  13,  22,  37 }, | ||||||
|  |     {   2,  47,  51 }, | ||||||
|  |     {  23,  54,  74 }, | ||||||
|  |     {  26,  34,  72 }, | ||||||
|  |     {  27,  36,  37 }, | ||||||
|  |     {  21,  36,  63 }, | ||||||
|  |     {  29,  40,  44 }, | ||||||
|  |     {  19,  26,  57 }, | ||||||
|  |     {   3,  46,  82 }, | ||||||
|  |     {  14,  15,  58 }, | ||||||
|  |     {  33,  52,  53 }, | ||||||
|  |     {  30,  43,  52 }, | ||||||
|  |     {   6,   9,  52 }, | ||||||
|  |     {  27,  33,  65 }, | ||||||
|  |     {  25,  69,  73 }, | ||||||
|  |     {  38,  55,  83 }, | ||||||
|  |     {  20,  39,  77 }, | ||||||
|  |     {  18,  29,  56 }, | ||||||
|  |     {  32,  48,  71 }, | ||||||
|  |     {  42,  51,  59 }, | ||||||
|  |     {  28,  44,  79 }, | ||||||
|  |     {  34,  60,  62 }, | ||||||
|  |     {  31,  45,  61 }, | ||||||
|  |     {  46,  68,  77 }, | ||||||
|  |     {   6,  24,  76 }, | ||||||
|  |     {   8,  10,  78 }, | ||||||
|  |     {  40,  41,  70 }, | ||||||
|  |     {  17,  50,  53 }, | ||||||
|  |     {  42,  66,  68 }, | ||||||
|  |     {   4,  22,  72 }, | ||||||
|  |     {  36,  64,  81 }, | ||||||
|  |     {  13,  29,  47 }, | ||||||
|  |     {   2,   8,  81 }, | ||||||
|  |     {  56,  67,  73 }, | ||||||
|  |     {   5,  38,  50 }, | ||||||
|  |     {  12,  38,  64 }, | ||||||
|  |     {  59,  72,  80 }, | ||||||
|  |     {   3,  26,  79 }, | ||||||
|  |     {  45,  76,  81 }, | ||||||
|  |     {   1,  65,  74 }, | ||||||
|  |     {   7,  18,  77 }, | ||||||
|  |     {  11,  56,  59 }, | ||||||
|  |     {  14,  39,  54 }, | ||||||
|  |     {  16,  37,  66 }, | ||||||
|  |     {  10,  28,  55 }, | ||||||
|  |     {  15,  60,  70 }, | ||||||
|  |     {  17,  25,  82 }, | ||||||
|  |     {  20,  30,  31 }, | ||||||
|  |     {  12,  67,  68 }, | ||||||
|  |     {  23,  75,  80 }, | ||||||
|  |     {  27,  32,  62 }, | ||||||
|  |     {  24,  69,  75 }, | ||||||
|  |     {  19,  21,  71 }, | ||||||
|  |     {  34,  53,  61 }, | ||||||
|  |     {  35,  46,  47 }, | ||||||
|  |     {  33,  59,  76 }, | ||||||
|  |     {  40,  43,  83 }, | ||||||
|  |     {  41,  42,  63 }, | ||||||
|  |     {  49,  75,  83 }, | ||||||
|  |     {  20,  44,  48 }, | ||||||
|  |     {  42,  49,  57 }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // This is the LDPC(174, 91) generator matrix
 | ||||||
|  | // It has 83 rows and 91 columns (zero padded on the right thus 12 bytes)
 | ||||||
|  | // From WSJT-X's ldpc_174_91_c_generator.f90
 | ||||||
|  | const int Arrays::Gm[][12] = { | ||||||
|  |     { 0x83, 0x29, 0xce, 0x11, 0xbf, 0x31, 0xea, 0xf5, 0x09, 0xf2, 0x7f, 0xc0 }, | ||||||
|  |     { 0x76, 0x1c, 0x26, 0x4e, 0x25, 0xc2, 0x59, 0x33, 0x54, 0x93, 0x13, 0x20 }, | ||||||
|  |     { 0xdc, 0x26, 0x59, 0x02, 0xfb, 0x27, 0x7c, 0x64, 0x10, 0xa1, 0xbd, 0xc0 }, | ||||||
|  |     { 0x1b, 0x3f, 0x41, 0x78, 0x58, 0xcd, 0x2d, 0xd3, 0x3e, 0xc7, 0xf6, 0x20 }, | ||||||
|  |     { 0x09, 0xfd, 0xa4, 0xfe, 0xe0, 0x41, 0x95, 0xfd, 0x03, 0x47, 0x83, 0xa0 }, | ||||||
|  |     { 0x07, 0x7c, 0xcc, 0xc1, 0x1b, 0x88, 0x73, 0xed, 0x5c, 0x3d, 0x48, 0xa0 }, | ||||||
|  |     { 0x29, 0xb6, 0x2a, 0xfe, 0x3c, 0xa0, 0x36, 0xf4, 0xfe, 0x1a, 0x9d, 0xa0 }, | ||||||
|  |     { 0x60, 0x54, 0xfa, 0xf5, 0xf3, 0x5d, 0x96, 0xd3, 0xb0, 0xc8, 0xc3, 0xe0 }, | ||||||
|  |     { 0xe2, 0x07, 0x98, 0xe4, 0x31, 0x0e, 0xed, 0x27, 0x88, 0x4a, 0xe9, 0x00 }, | ||||||
|  |     { 0x77, 0x5c, 0x9c, 0x08, 0xe8, 0x0e, 0x26, 0xdd, 0xae, 0x56, 0x31, 0x80 }, | ||||||
|  |     { 0xb0, 0xb8, 0x11, 0x02, 0x8c, 0x2b, 0xf9, 0x97, 0x21, 0x34, 0x87, 0xc0 }, | ||||||
|  |     { 0x18, 0xa0, 0xc9, 0x23, 0x1f, 0xc6, 0x0a, 0xdf, 0x5c, 0x5e, 0xa3, 0x20 }, | ||||||
|  |     { 0x76, 0x47, 0x1e, 0x83, 0x02, 0xa0, 0x72, 0x1e, 0x01, 0xb1, 0x2b, 0x80 }, | ||||||
|  |     { 0xff, 0xbc, 0xcb, 0x80, 0xca, 0x83, 0x41, 0xfa, 0xfb, 0x47, 0xb2, 0xe0 }, | ||||||
|  |     { 0x66, 0xa7, 0x2a, 0x15, 0x8f, 0x93, 0x25, 0xa2, 0xbf, 0x67, 0x17, 0x00 }, | ||||||
|  |     { 0xc4, 0x24, 0x36, 0x89, 0xfe, 0x85, 0xb1, 0xc5, 0x13, 0x63, 0xa1, 0x80 }, | ||||||
|  |     { 0x0d, 0xff, 0x73, 0x94, 0x14, 0xd1, 0xa1, 0xb3, 0x4b, 0x1c, 0x27, 0x00 }, | ||||||
|  |     { 0x15, 0xb4, 0x88, 0x30, 0x63, 0x6c, 0x8b, 0x99, 0x89, 0x49, 0x72, 0xe0 }, | ||||||
|  |     { 0x29, 0xa8, 0x9c, 0x0d, 0x3d, 0xe8, 0x1d, 0x66, 0x54, 0x89, 0xb0, 0xe0 }, | ||||||
|  |     { 0x4f, 0x12, 0x6f, 0x37, 0xfa, 0x51, 0xcb, 0xe6, 0x1b, 0xd6, 0xb9, 0x40 }, | ||||||
|  |     { 0x99, 0xc4, 0x72, 0x39, 0xd0, 0xd9, 0x7d, 0x3c, 0x84, 0xe0, 0x94, 0x00 }, | ||||||
|  |     { 0x19, 0x19, 0xb7, 0x51, 0x19, 0x76, 0x56, 0x21, 0xbb, 0x4f, 0x1e, 0x80 }, | ||||||
|  |     { 0x09, 0xdb, 0x12, 0xd7, 0x31, 0xfa, 0xee, 0x0b, 0x86, 0xdf, 0x6b, 0x80 }, | ||||||
|  |     { 0x48, 0x8f, 0xc3, 0x3d, 0xf4, 0x3f, 0xbd, 0xee, 0xa4, 0xea, 0xfb, 0x40 }, | ||||||
|  |     { 0x82, 0x74, 0x23, 0xee, 0x40, 0xb6, 0x75, 0xf7, 0x56, 0xeb, 0x5f, 0xe0 }, | ||||||
|  |     { 0xab, 0xe1, 0x97, 0xc4, 0x84, 0xcb, 0x74, 0x75, 0x71, 0x44, 0xa9, 0xa0 }, | ||||||
|  |     { 0x2b, 0x50, 0x0e, 0x4b, 0xc0, 0xec, 0x5a, 0x6d, 0x2b, 0xdb, 0xdd, 0x00 }, | ||||||
|  |     { 0xc4, 0x74, 0xaa, 0x53, 0xd7, 0x02, 0x18, 0x76, 0x16, 0x69, 0x36, 0x00 }, | ||||||
|  |     { 0x8e, 0xba, 0x1a, 0x13, 0xdb, 0x33, 0x90, 0xbd, 0x67, 0x18, 0xce, 0xc0 }, | ||||||
|  |     { 0x75, 0x38, 0x44, 0x67, 0x3a, 0x27, 0x78, 0x2c, 0xc4, 0x20, 0x12, 0xe0 }, | ||||||
|  |     { 0x06, 0xff, 0x83, 0xa1, 0x45, 0xc3, 0x70, 0x35, 0xa5, 0xc1, 0x26, 0x80 }, | ||||||
|  |     { 0x3b, 0x37, 0x41, 0x78, 0x58, 0xcc, 0x2d, 0xd3, 0x3e, 0xc3, 0xf6, 0x20 }, | ||||||
|  |     { 0x9a, 0x4a, 0x5a, 0x28, 0xee, 0x17, 0xca, 0x9c, 0x32, 0x48, 0x42, 0xc0 }, | ||||||
|  |     { 0xbc, 0x29, 0xf4, 0x65, 0x30, 0x9c, 0x97, 0x7e, 0x89, 0x61, 0x0a, 0x40 }, | ||||||
|  |     { 0x26, 0x63, 0xae, 0x6d, 0xdf, 0x8b, 0x5c, 0xe2, 0xbb, 0x29, 0x48, 0x80 }, | ||||||
|  |     { 0x46, 0xf2, 0x31, 0xef, 0xe4, 0x57, 0x03, 0x4c, 0x18, 0x14, 0x41, 0x80 }, | ||||||
|  |     { 0x3f, 0xb2, 0xce, 0x85, 0xab, 0xe9, 0xb0, 0xc7, 0x2e, 0x06, 0xfb, 0xe0 }, | ||||||
|  |     { 0xde, 0x87, 0x48, 0x1f, 0x28, 0x2c, 0x15, 0x39, 0x71, 0xa0, 0xa2, 0xe0 }, | ||||||
|  |     { 0xfc, 0xd7, 0xcc, 0xf2, 0x3c, 0x69, 0xfa, 0x99, 0xbb, 0xa1, 0x41, 0x20 }, | ||||||
|  |     { 0xf0, 0x26, 0x14, 0x47, 0xe9, 0x49, 0x0c, 0xa8, 0xe4, 0x74, 0xce, 0xc0 }, | ||||||
|  |     { 0x44, 0x10, 0x11, 0x58, 0x18, 0x19, 0x6f, 0x95, 0xcd, 0xd7, 0x01, 0x20 }, | ||||||
|  |     { 0x08, 0x8f, 0xc3, 0x1d, 0xf4, 0xbf, 0xbd, 0xe2, 0xa4, 0xea, 0xfb, 0x40 }, | ||||||
|  |     { 0xb8, 0xfe, 0xf1, 0xb6, 0x30, 0x77, 0x29, 0xfb, 0x0a, 0x07, 0x8c, 0x00 }, | ||||||
|  |     { 0x5a, 0xfe, 0xa7, 0xac, 0xcc, 0xb7, 0x7b, 0xbc, 0x9d, 0x99, 0xa9, 0x00 }, | ||||||
|  |     { 0x49, 0xa7, 0x01, 0x6a, 0xc6, 0x53, 0xf6, 0x5e, 0xcd, 0xc9, 0x07, 0x60 }, | ||||||
|  |     { 0x19, 0x44, 0xd0, 0x85, 0xbe, 0x4e, 0x7d, 0xa8, 0xd6, 0xcc, 0x7d, 0x00 }, | ||||||
|  |     { 0x25, 0x1f, 0x62, 0xad, 0xc4, 0x03, 0x2f, 0x0e, 0xe7, 0x14, 0x00, 0x20 }, | ||||||
|  |     { 0x56, 0x47, 0x1f, 0x87, 0x02, 0xa0, 0x72, 0x1e, 0x00, 0xb1, 0x2b, 0x80 }, | ||||||
|  |     { 0x2b, 0x8e, 0x49, 0x23, 0xf2, 0xdd, 0x51, 0xe2, 0xd5, 0x37, 0xfa, 0x00 }, | ||||||
|  |     { 0x6b, 0x55, 0x0a, 0x40, 0xa6, 0x6f, 0x47, 0x55, 0xde, 0x95, 0xc2, 0x60 }, | ||||||
|  |     { 0xa1, 0x8a, 0xd2, 0x8d, 0x4e, 0x27, 0xfe, 0x92, 0xa4, 0xf6, 0xc8, 0x40 }, | ||||||
|  |     { 0x10, 0xc2, 0xe5, 0x86, 0x38, 0x8c, 0xb8, 0x2a, 0x3d, 0x80, 0x75, 0x80 }, | ||||||
|  |     { 0xef, 0x34, 0xa4, 0x18, 0x17, 0xee, 0x02, 0x13, 0x3d, 0xb2, 0xeb, 0x00 }, | ||||||
|  |     { 0x7e, 0x9c, 0x0c, 0x54, 0x32, 0x5a, 0x9c, 0x15, 0x83, 0x6e, 0x00, 0x00 }, | ||||||
|  |     { 0x36, 0x93, 0xe5, 0x72, 0xd1, 0xfd, 0xe4, 0xcd, 0xf0, 0x79, 0xe8, 0x60 }, | ||||||
|  |     { 0xbf, 0xb2, 0xce, 0xc5, 0xab, 0xe1, 0xb0, 0xc7, 0x2e, 0x07, 0xfb, 0xe0 }, | ||||||
|  |     { 0x7e, 0xe1, 0x82, 0x30, 0xc5, 0x83, 0xcc, 0xcc, 0x57, 0xd4, 0xb0, 0x80 }, | ||||||
|  |     { 0xa0, 0x66, 0xcb, 0x2f, 0xed, 0xaf, 0xc9, 0xf5, 0x26, 0x64, 0x12, 0x60 }, | ||||||
|  |     { 0xbb, 0x23, 0x72, 0x5a, 0xbc, 0x47, 0xcc, 0x5f, 0x4c, 0xc4, 0xcd, 0x20 }, | ||||||
|  |     { 0xde, 0xd9, 0xdb, 0xa3, 0xbe, 0xe4, 0x0c, 0x59, 0xb5, 0x60, 0x9b, 0x40 }, | ||||||
|  |     { 0xd9, 0xa7, 0x01, 0x6a, 0xc6, 0x53, 0xe6, 0xde, 0xcd, 0xc9, 0x03, 0x60 }, | ||||||
|  |     { 0x9a, 0xd4, 0x6a, 0xed, 0x5f, 0x70, 0x7f, 0x28, 0x0a, 0xb5, 0xfc, 0x40 }, | ||||||
|  |     { 0xe5, 0x92, 0x1c, 0x77, 0x82, 0x25, 0x87, 0x31, 0x6d, 0x7d, 0x3c, 0x20 }, | ||||||
|  |     { 0x4f, 0x14, 0xda, 0x82, 0x42, 0xa8, 0xb8, 0x6d, 0xca, 0x73, 0x35, 0x20 }, | ||||||
|  |     { 0x8b, 0x8b, 0x50, 0x7a, 0xd4, 0x67, 0xd4, 0x44, 0x1d, 0xf7, 0x70, 0xe0 }, | ||||||
|  |     { 0x22, 0x83, 0x1c, 0x9c, 0xf1, 0x16, 0x94, 0x67, 0xad, 0x04, 0xb6, 0x80 }, | ||||||
|  |     { 0x21, 0x3b, 0x83, 0x8f, 0xe2, 0xae, 0x54, 0xc3, 0x8e, 0xe7, 0x18, 0x00 }, | ||||||
|  |     { 0x5d, 0x92, 0x6b, 0x6d, 0xd7, 0x1f, 0x08, 0x51, 0x81, 0xa4, 0xe1, 0x20 }, | ||||||
|  |     { 0x66, 0xab, 0x79, 0xd4, 0xb2, 0x9e, 0xe6, 0xe6, 0x95, 0x09, 0xe5, 0x60 }, | ||||||
|  |     { 0x95, 0x81, 0x48, 0x68, 0x2d, 0x74, 0x8a, 0x38, 0xdd, 0x68, 0xba, 0xa0 }, | ||||||
|  |     { 0xb8, 0xce, 0x02, 0x0c, 0xf0, 0x69, 0xc3, 0x2a, 0x72, 0x3a, 0xb1, 0x40 }, | ||||||
|  |     { 0xf4, 0x33, 0x1d, 0x6d, 0x46, 0x16, 0x07, 0xe9, 0x57, 0x52, 0x74, 0x60 }, | ||||||
|  |     { 0x6d, 0xa2, 0x3b, 0xa4, 0x24, 0xb9, 0x59, 0x61, 0x33, 0xcf, 0x9c, 0x80 }, | ||||||
|  |     { 0xa6, 0x36, 0xbc, 0xbc, 0x7b, 0x30, 0xc5, 0xfb, 0xea, 0xe6, 0x7f, 0xe0 }, | ||||||
|  |     { 0x5c, 0xb0, 0xd8, 0x6a, 0x07, 0xdf, 0x65, 0x4a, 0x90, 0x89, 0xa2, 0x00 }, | ||||||
|  |     { 0xf1, 0x1f, 0x10, 0x68, 0x48, 0x78, 0x0f, 0xc9, 0xec, 0xdd, 0x80, 0xa0 }, | ||||||
|  |     { 0x1f, 0xbb, 0x53, 0x64, 0xfb, 0x8d, 0x2c, 0x9d, 0x73, 0x0d, 0x5b, 0xa0 }, | ||||||
|  |     { 0xfc, 0xb8, 0x6b, 0xc7, 0x0a, 0x50, 0xc9, 0xd0, 0x2a, 0x5d, 0x03, 0x40 }, | ||||||
|  |     { 0xa5, 0x34, 0x43, 0x30, 0x29, 0xea, 0xc1, 0x5f, 0x32, 0x2e, 0x34, 0xc0 }, | ||||||
|  |     { 0xc9, 0x89, 0xd9, 0xc7, 0xc3, 0xd3, 0xb8, 0xc5, 0x5d, 0x75, 0x13, 0x00 }, | ||||||
|  |     { 0x7b, 0xb3, 0x8b, 0x2f, 0x01, 0x86, 0xd4, 0x66, 0x43, 0xae, 0x96, 0x20 }, | ||||||
|  |     { 0x26, 0x44, 0xeb, 0xad, 0xeb, 0x44, 0xb9, 0x46, 0x7d, 0x1f, 0x42, 0xc0 }, | ||||||
|  |     { 0x60, 0x8c, 0xc8, 0x57, 0x59, 0x4b, 0xfb, 0xb5, 0x5d, 0x69, 0x60, 0x00 } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace FT8
 | ||||||
							
								
								
									
										277
									
								
								ft8/arrays.h
									
									
									
									
									
								
							
							
						
						
									
										277
									
								
								ft8/arrays.h
									
									
									
									
									
								
							| @ -18,8 +18,16 @@ | |||||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
|  | #ifndef FT8_ARRAYS_H_ | ||||||
|  | #define FT8_ARRAYS_H_ | ||||||
|  | 
 | ||||||
|  | #include "export.h" | ||||||
|  | 
 | ||||||
| namespace FT8 { | namespace FT8 { | ||||||
| 
 | 
 | ||||||
|  | class FT8_API Arrays | ||||||
|  | { | ||||||
|  | public: | ||||||
|     //
 |     //
 | ||||||
|     // this is the LDPC(174,91) parity check matrix.
 |     // this is the LDPC(174,91) parity check matrix.
 | ||||||
|     // each row describes one parity check.
 |     // each row describes one parity check.
 | ||||||
| @ -28,272 +36,21 @@ namespace FT8 { | |||||||
|     // the codeword bits mentioned in each row must xor to zero.
 |     // the codeword bits mentioned in each row must xor to zero.
 | ||||||
|     // From WSJT-X's ldpc_174_91_c_reordered_parity.f90
 |     // From WSJT-X's ldpc_174_91_c_reordered_parity.f90
 | ||||||
|     //
 |     //
 | ||||||
| int Nm[][7] = { |     static const int Nm[][7]; | ||||||
|  {  4,  31,  59,  91,  92,  96, 153 }, |  | ||||||
|  {  5,  32,  60,  93, 115, 146,   0 }, |  | ||||||
|  {  6,  24,  61,  94, 122, 151,   0 }, |  | ||||||
|  {  7,  33,  62,  95,  96, 143,   0 }, |  | ||||||
|  {  8,  25,  63,  83,  93,  96, 148 }, |  | ||||||
|  {  6,  32,  64,  97, 126, 138,   0 }, |  | ||||||
|  {  5,  34,  65,  78,  98, 107, 154 }, |  | ||||||
|  {  9,  35,  66,  99, 139, 146,   0 }, |  | ||||||
|  { 10,  36,  67, 100, 107, 126,   0 }, |  | ||||||
|  { 11,  37,  67,  87, 101, 139, 158 }, |  | ||||||
|  { 12,  38,  68, 102, 105, 155,   0 }, |  | ||||||
|  { 13,  39,  69, 103, 149, 162,   0 }, |  | ||||||
|  {  8,  40,  70,  82, 104, 114, 145 }, |  | ||||||
|  { 14,  41,  71,  88, 102, 123, 156 }, |  | ||||||
|  { 15,  42,  59, 106, 123, 159,   0 }, |  | ||||||
|  {  1,  33,  72, 106, 107, 157,   0 }, |  | ||||||
|  { 16,  43,  73, 108, 141, 160,   0 }, |  | ||||||
|  { 17,  37,  74,  81, 109, 131, 154 }, |  | ||||||
|  { 11,  44,  75, 110, 121, 166,   0 }, |  | ||||||
|  { 45,  55,  64, 111, 130, 161, 173 }, |  | ||||||
|  {  8,  46,  71, 112, 119, 166,   0 }, |  | ||||||
|  { 18,  36,  76,  89, 113, 114, 143 }, |  | ||||||
|  { 19,  38,  77, 104, 116, 163,   0 }, |  | ||||||
|  { 20,  47,  70,  92, 138, 165,   0 }, |  | ||||||
|  {  2,  48,  74, 113, 128, 160,   0 }, |  | ||||||
|  { 21,  45,  78,  83, 117, 121, 151 }, |  | ||||||
|  { 22,  47,  58, 118, 127, 164,   0 }, |  | ||||||
|  { 16,  39,  62, 112, 134, 158,   0 }, |  | ||||||
|  { 23,  43,  79, 120, 131, 145,   0 }, |  | ||||||
|  { 19,  35,  59,  73, 110, 125, 161 }, |  | ||||||
|  { 20,  36,  63,  94, 136, 161,   0 }, |  | ||||||
|  { 14,  31,  79,  98, 132, 164,   0 }, |  | ||||||
|  {  3,  44,  80, 124, 127, 169,   0 }, |  | ||||||
|  { 19,  46,  81, 117, 135, 167,   0 }, |  | ||||||
|  {  7,  49,  58,  90, 100, 105, 168 }, |  | ||||||
|  { 12,  50,  61, 118, 119, 144,   0 }, |  | ||||||
|  { 13,  51,  64, 114, 118, 157,   0 }, |  | ||||||
|  { 24,  52,  76, 129, 148, 149,   0 }, |  | ||||||
|  { 25,  53,  69,  90, 101, 130, 156 }, |  | ||||||
|  { 20,  46,  65,  80, 120, 140, 170 }, |  | ||||||
|  { 21,  54,  77, 100, 140, 171,   0 }, |  | ||||||
|  { 35,  82, 133, 142, 171, 174,   0 }, |  | ||||||
|  { 14,  30,  83, 113, 125, 170,   0 }, |  | ||||||
|  {  4,  29,  68, 120, 134, 173,   0 }, |  | ||||||
|  {  1,   4,  52,  57,  86, 136, 152 }, |  | ||||||
|  { 26,  51,  56,  91, 122, 137, 168 }, |  | ||||||
|  { 52,  84, 110, 115, 145, 168,   0 }, |  | ||||||
|  {  7,  50,  81,  99, 132, 173,   0 }, |  | ||||||
|  { 23,  55,  67,  95, 172, 174,   0 }, |  | ||||||
|  { 26,  41,  77, 109, 141, 148,   0 }, |  | ||||||
|  {  2,  27,  41,  61,  62, 115, 133 }, |  | ||||||
|  { 27,  40,  56, 124, 125, 126,   0 }, |  | ||||||
|  { 18,  49,  55, 124, 141, 167,   0 }, |  | ||||||
|  {  6,  33,  85, 108, 116, 156,   0 }, |  | ||||||
|  { 28,  48,  70,  85, 105, 129, 158 }, |  | ||||||
|  {  9,  54,  63, 131, 147, 155,   0 }, |  | ||||||
|  { 22,  53,  68, 109, 121, 174,   0 }, |  | ||||||
|  {  3,  13,  48,  78,  95, 123,   0 }, |  | ||||||
|  { 31,  69, 133, 150, 155, 169,   0 }, |  | ||||||
|  { 12,  43,  66,  89,  97, 135, 159 }, |  | ||||||
|  {  5,  39,  75, 102, 136, 167,   0 }, |  | ||||||
|  {  2,  54,  86, 101, 135, 164,   0 }, |  | ||||||
|  { 15,  56,  87, 108, 119, 171,   0 }, |  | ||||||
|  { 10,  44,  82,  91, 111, 144, 149 }, |  | ||||||
|  { 23,  34,  71,  94, 127, 153,   0 }, |  | ||||||
|  { 11,  49,  88,  92, 142, 157,   0 }, |  | ||||||
|  { 29,  34,  87,  97, 147, 162,   0 }, |  | ||||||
|  { 30,  50,  60,  86, 137, 142, 162 }, |  | ||||||
|  { 10,  53,  66,  84, 112, 128, 165 }, |  | ||||||
|  { 22,  57,  85,  93, 140, 159,   0 }, |  | ||||||
|  { 28,  32,  72, 103, 132, 166,   0 }, |  | ||||||
|  { 28,  29,  84,  88, 117, 143, 150 }, |  | ||||||
|  {  1,  26,  45,  80, 128, 147,   0 }, |  | ||||||
|  { 17,  27,  89, 103, 116, 153,   0 }, |  | ||||||
|  { 51,  57,  98, 163, 165, 172,   0 }, |  | ||||||
|  { 21,  37,  73, 138, 152, 169,   0 }, |  | ||||||
|  { 16,  47,  76, 130, 137, 154,   0 }, |  | ||||||
|  {  3,  24,  30,  72, 104, 139,   0 }, |  | ||||||
|  {  9,  40,  90, 106, 134, 151,   0 }, |  | ||||||
|  { 15,  58,  60,  74, 111, 150, 163 }, |  | ||||||
|  { 18,  42,  79, 144, 146, 152,   0 }, |  | ||||||
|  { 25,  38,  65,  99, 122, 160,   0 }, |  | ||||||
|  { 17,  42,  75, 129, 170, 172,   0 }, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
|     // Mn from WSJT-X's ldpc_174_91_c_reordered_parity.f90
 |     // Mn from WSJT-X's ldpc_174_91_c_reordered_parity.f90
 | ||||||
|     // each of the 174 rows corresponds to a codeword bit.
 |     // each of the 174 rows corresponds to a codeword bit.
 | ||||||
|     // the numbers indicate which three parity
 |     // the numbers indicate which three parity
 | ||||||
|     // checks (rows in Nm) refer to the codeword bit.
 |     // checks (rows in Nm) refer to the codeword bit.
 | ||||||
|     // 1-origin.
 |     // 1-origin.
 | ||||||
| int Mn[][3] = { |     static const int Mn[][3]; | ||||||
|   {  16,  45,  73 }, | 
 | ||||||
|   {  25,  51,  62 }, |     // This is the LDPC(174, 91) generator matrix
 | ||||||
|   {  33,  58,  78 }, |     // It has 83 rows and 91 columns (zero padded on the right thus 12 bytes)
 | ||||||
|   {   1,  44,  45 }, |     // From WSJT-X's ldpc_174_91_c_generator.f90
 | ||||||
|   {   2,   7,  61 }, |     static const int Gm[][12]; | ||||||
|   {   3,   6,  54 }, |  | ||||||
|   {   4,  35,  48 }, |  | ||||||
|   {   5,  13,  21 }, |  | ||||||
|   {   8,  56,  79 }, |  | ||||||
|   {   9,  64,  69 }, |  | ||||||
|   {  10,  19,  66 }, |  | ||||||
|   {  11,  36,  60 }, |  | ||||||
|   {  12,  37,  58 }, |  | ||||||
|   {  14,  32,  43 }, |  | ||||||
|   {  15,  63,  80 }, |  | ||||||
|   {  17,  28,  77 }, |  | ||||||
|   {  18,  74,  83 }, |  | ||||||
|   {  22,  53,  81 }, |  | ||||||
|   {  23,  30,  34 }, |  | ||||||
|   {  24,  31,  40 }, |  | ||||||
|   {  26,  41,  76 }, |  | ||||||
|   {  27,  57,  70 }, |  | ||||||
|   {  29,  49,  65 }, |  | ||||||
|   {   3,  38,  78 }, |  | ||||||
|   {   5,  39,  82 }, |  | ||||||
|   {  46,  50,  73 }, |  | ||||||
|   {  51,  52,  74 }, |  | ||||||
|   {  55,  71,  72 }, |  | ||||||
|   {  44,  67,  72 }, |  | ||||||
|   {  43,  68,  78 }, |  | ||||||
|   {   1,  32,  59 }, |  | ||||||
|   {   2,   6,  71 }, |  | ||||||
|   {   4,  16,  54 }, |  | ||||||
|   {   7,  65,  67 }, |  | ||||||
|   {   8,  30,  42 }, |  | ||||||
|   {   9,  22,  31 }, |  | ||||||
|   {  10,  18,  76 }, |  | ||||||
|   {  11,  23,  82 }, |  | ||||||
|   {  12,  28,  61 }, |  | ||||||
|   {  13,  52,  79 }, |  | ||||||
|   {  14,  50,  51 }, |  | ||||||
|   {  15,  81,  83 }, |  | ||||||
|   {  17,  29,  60 }, |  | ||||||
|   {  19,  33,  64 }, |  | ||||||
|   {  20,  26,  73 }, |  | ||||||
|   {  21,  34,  40 }, |  | ||||||
|   {  24,  27,  77 }, |  | ||||||
|   {  25,  55,  58 }, |  | ||||||
|   {  35,  53,  66 }, |  | ||||||
|   {  36,  48,  68 }, |  | ||||||
|   {  37,  46,  75 }, |  | ||||||
|   {  38,  45,  47 }, |  | ||||||
|   {  39,  57,  69 }, |  | ||||||
|   {  41,  56,  62 }, |  | ||||||
|   {  20,  49,  53 }, |  | ||||||
|   {  46,  52,  63 }, |  | ||||||
|   {  45,  70,  75 }, |  | ||||||
|   {  27,  35,  80 }, |  | ||||||
|   {   1,  15,  30 }, |  | ||||||
|   {   2,  68,  80 }, |  | ||||||
|   {   3,  36,  51 }, |  | ||||||
|   {   4,  28,  51 }, |  | ||||||
|   {   5,  31,  56 }, |  | ||||||
|   {   6,  20,  37 }, |  | ||||||
|   {   7,  40,  82 }, |  | ||||||
|   {   8,  60,  69 }, |  | ||||||
|   {   9,  10,  49 }, |  | ||||||
|   {  11,  44,  57 }, |  | ||||||
|   {  12,  39,  59 }, |  | ||||||
|   {  13,  24,  55 }, |  | ||||||
|   {  14,  21,  65 }, |  | ||||||
|   {  16,  71,  78 }, |  | ||||||
|   {  17,  30,  76 }, |  | ||||||
|   {  18,  25,  80 }, |  | ||||||
|   {  19,  61,  83 }, |  | ||||||
|   {  22,  38,  77 }, |  | ||||||
|   {  23,  41,  50 }, |  | ||||||
|   {   7,  26,  58 }, |  | ||||||
|   {  29,  32,  81 }, |  | ||||||
|   {  33,  40,  73 }, |  | ||||||
|   {  18,  34,  48 }, |  | ||||||
|   {  13,  42,  64 }, |  | ||||||
|   {   5,  26,  43 }, |  | ||||||
|   {  47,  69,  72 }, |  | ||||||
|   {  54,  55,  70 }, |  | ||||||
|   {  45,  62,  68 }, |  | ||||||
|   {  10,  63,  67 }, |  | ||||||
|   {  14,  66,  72 }, |  | ||||||
|   {  22,  60,  74 }, |  | ||||||
|   {  35,  39,  79 }, |  | ||||||
|   {   1,  46,  64 }, |  | ||||||
|   {   1,  24,  66 }, |  | ||||||
|   {   2,   5,  70 }, |  | ||||||
|   {   3,  31,  65 }, |  | ||||||
|   {   4,  49,  58 }, |  | ||||||
|   {   1,   4,   5 }, |  | ||||||
|   {   6,  60,  67 }, |  | ||||||
|   {   7,  32,  75 }, |  | ||||||
|   {   8,  48,  82 }, |  | ||||||
|   {   9,  35,  41 }, |  | ||||||
|   {  10,  39,  62 }, |  | ||||||
|   {  11,  14,  61 }, |  | ||||||
|   {  12,  71,  74 }, |  | ||||||
|   {  13,  23,  78 }, |  | ||||||
|   {  11,  35,  55 }, |  | ||||||
|   {  15,  16,  79 }, |  | ||||||
|   {   7,   9,  16 }, |  | ||||||
|   {  17,  54,  63 }, |  | ||||||
|   {  18,  50,  57 }, |  | ||||||
|   {  19,  30,  47 }, |  | ||||||
|   {  20,  64,  80 }, |  | ||||||
|   {  21,  28,  69 }, |  | ||||||
|   {  22,  25,  43 }, |  | ||||||
|   {  13,  22,  37 }, |  | ||||||
|   {   2,  47,  51 }, |  | ||||||
|   {  23,  54,  74 }, |  | ||||||
|   {  26,  34,  72 }, |  | ||||||
|   {  27,  36,  37 }, |  | ||||||
|   {  21,  36,  63 }, |  | ||||||
|   {  29,  40,  44 }, |  | ||||||
|   {  19,  26,  57 }, |  | ||||||
|   {   3,  46,  82 }, |  | ||||||
|   {  14,  15,  58 }, |  | ||||||
|   {  33,  52,  53 }, |  | ||||||
|   {  30,  43,  52 }, |  | ||||||
|   {   6,   9,  52 }, |  | ||||||
|   {  27,  33,  65 }, |  | ||||||
|   {  25,  69,  73 }, |  | ||||||
|   {  38,  55,  83 }, |  | ||||||
|   {  20,  39,  77 }, |  | ||||||
|   {  18,  29,  56 }, |  | ||||||
|   {  32,  48,  71 }, |  | ||||||
|   {  42,  51,  59 }, |  | ||||||
|   {  28,  44,  79 }, |  | ||||||
|   {  34,  60,  62 }, |  | ||||||
|   {  31,  45,  61 }, |  | ||||||
|   {  46,  68,  77 }, |  | ||||||
|   {   6,  24,  76 }, |  | ||||||
|   {   8,  10,  78 }, |  | ||||||
|   {  40,  41,  70 }, |  | ||||||
|   {  17,  50,  53 }, |  | ||||||
|   {  42,  66,  68 }, |  | ||||||
|   {   4,  22,  72 }, |  | ||||||
|   {  36,  64,  81 }, |  | ||||||
|   {  13,  29,  47 }, |  | ||||||
|   {   2,   8,  81 }, |  | ||||||
|   {  56,  67,  73 }, |  | ||||||
|   {   5,  38,  50 }, |  | ||||||
|   {  12,  38,  64 }, |  | ||||||
|   {  59,  72,  80 }, |  | ||||||
|   {   3,  26,  79 }, |  | ||||||
|   {  45,  76,  81 }, |  | ||||||
|   {   1,  65,  74 }, |  | ||||||
|   {   7,  18,  77 }, |  | ||||||
|   {  11,  56,  59 }, |  | ||||||
|   {  14,  39,  54 }, |  | ||||||
|   {  16,  37,  66 }, |  | ||||||
|   {  10,  28,  55 }, |  | ||||||
|   {  15,  60,  70 }, |  | ||||||
|   {  17,  25,  82 }, |  | ||||||
|   {  20,  30,  31 }, |  | ||||||
|   {  12,  67,  68 }, |  | ||||||
|   {  23,  75,  80 }, |  | ||||||
|   {  27,  32,  62 }, |  | ||||||
|   {  24,  69,  75 }, |  | ||||||
|   {  19,  21,  71 }, |  | ||||||
|   {  34,  53,  61 }, |  | ||||||
|   {  35,  46,  47 }, |  | ||||||
|   {  33,  59,  76 }, |  | ||||||
|   {  40,  43,  83 }, |  | ||||||
|   {  41,  42,  63 }, |  | ||||||
|   {  49,  75,  83 }, |  | ||||||
|   {  20,  44,  48 }, |  | ||||||
|   {  42,  49,  57 }, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace FT8
 | } // namespace FT8
 | ||||||
|  | 
 | ||||||
|  | #endif // FT8_ARRAYS_H_
 | ||||||
|  | |||||||
							
								
								
									
										44
									
								
								ft8/ft8.cpp
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								ft8/ft8.cpp
									
									
									
									
									
								
							| @ -44,6 +44,7 @@ | |||||||
| #include "ft8.h" | #include "ft8.h" | ||||||
| #include "libldpc.h" | #include "libldpc.h" | ||||||
| #include "osd.h" | #include "osd.h" | ||||||
|  | #include "arrays.h" | ||||||
| 
 | 
 | ||||||
| namespace FT8 { | namespace FT8 { | ||||||
| 
 | 
 | ||||||
| @ -2478,13 +2479,11 @@ void FT8::soft_decode_triples( | |||||||
| // given log likelyhood for each bit, try LDPC and OSD decoders.
 | // given log likelyhood for each bit, try LDPC and OSD decoders.
 | ||||||
| // on success, puts corrected 174 bits into a174[].
 | // on success, puts corrected 174 bits into a174[].
 | ||||||
| //
 | //
 | ||||||
| int FT8::decode(const float ll174[], int a174[], int use_osd, std::string &comment) | int FT8::decode(const float ll174[], int a174[], FT8Params& _params, int use_osd, std::string &comment) | ||||||
| { | { | ||||||
|     void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok); |  | ||||||
|     void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok); |  | ||||||
|     int plain[174];  // will be 0/1 bits.
 |     int plain[174];  // will be 0/1 bits.
 | ||||||
|     int ldpc_ok = 0; // 83 will mean success.
 |     int ldpc_ok = 0; // 83 will mean success.
 | ||||||
|     ldpc_decode((float *)ll174, params.ldpc_iters, plain, &ldpc_ok); |     LDPC::ldpc_decode((float *)ll174, _params.ldpc_iters, plain, &ldpc_ok); | ||||||
|     int ok_thresh = 83; // 83 is perfect
 |     int ok_thresh = 83; // 83 is perfect
 | ||||||
| 
 | 
 | ||||||
|     if (ldpc_ok >= ok_thresh) |     if (ldpc_ok >= ok_thresh) | ||||||
| @ -2500,11 +2499,11 @@ int FT8::decode(const float ll174[], int a174[], int use_osd, std::string &comme | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (use_osd && params.osd_depth >= 0 && ldpc_ok >= params.osd_ldpc_thresh) |     if (use_osd && _params.osd_depth >= 0 && ldpc_ok >= _params.osd_ldpc_thresh) | ||||||
|     { |     { | ||||||
|         int oplain[91]; |         int oplain[91]; | ||||||
|         int got_depth = -1; |         int got_depth = -1; | ||||||
|         int osd_ok = OSD::osd_decode((float *)ll174, params.osd_depth, oplain, &got_depth); |         int osd_ok = OSD::osd_decode((float *)ll174, _params.osd_depth, oplain, &got_depth); | ||||||
| 
 | 
 | ||||||
|         if (osd_ok) |         if (osd_ok) | ||||||
|         { |         { | ||||||
| @ -2518,6 +2517,37 @@ int FT8::decode(const float ll174[], int a174[], int use_osd, std::string &comme | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | //
 | ||||||
|  | // encode a 77 bit message into a 174 bit payload
 | ||||||
|  | // adds the 14 bit CRC to obtain 91 bits
 | ||||||
|  | // apply (174, 91) generator mastrix to obtain the 83 parity bits
 | ||||||
|  | // append the 83 bits to the 91 bits message + crc to obbain the 174 bit payload
 | ||||||
|  | //
 | ||||||
|  | void FT8::encode(int a174[], int s77[]) | ||||||
|  | { | ||||||
|  |     int a91[91]; // msg + CRC
 | ||||||
|  |     std::fill(a91, a91 + 91, 0); | ||||||
|  |     std::copy(s77, s77+77, a91); // copy msg
 | ||||||
|  |     LDPC::ft8_crc(a91, 82, &a91[77]); // append CRC - to match OSD::check_crc
 | ||||||
|  |     std::copy(a91, a91+91, a174); // copy msg + CRC
 | ||||||
|  |     int sum, n, ni, b; | ||||||
|  | 
 | ||||||
|  |     for (int i=0; i<83; i++) | ||||||
|  |     { | ||||||
|  |         sum = 0; | ||||||
|  | 
 | ||||||
|  |         for (int j=0; j<91; j++) | ||||||
|  |         { | ||||||
|  |             n = j/8;  // byte index in the generator matrix
 | ||||||
|  |             ni = j%8;  // bit index in the generator matrix byte LSB first
 | ||||||
|  |             b = (Arrays::Gm[i][n] >> (7-ni)) & 1; // bit in the generator matrix
 | ||||||
|  |             sum += a91[j] * b; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         a174[91+i] = sum % 2; // sum modulo 2
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| //
 | //
 | ||||||
| // bandpass filter some FFT bins.
 | // bandpass filter some FFT bins.
 | ||||||
| // smooth transition from stop-band to pass-band,
 | // smooth transition from stop-band to pass-band,
 | ||||||
| @ -3418,7 +3448,7 @@ int FT8::try_decode( | |||||||
|     int a174[174]; |     int a174[174]; | ||||||
|     std::string comment(comment1); |     std::string comment(comment1); | ||||||
| 
 | 
 | ||||||
|     if (decode(ll174, a174, use_osd, comment)) |     if (decode(ll174, a174, params, use_osd, comment)) | ||||||
|     { |     { | ||||||
|         // a174 is corrected 91 bits of plain message plus 83 bits of LDPC parity.
 |         // a174 is corrected 91 bits of plain message plus 83 bits of LDPC parity.
 | ||||||
|         // how many of the corrected 174 bits match the received signal in ll174?
 |         // how many of the corrected 174 bits match the received signal in ll174?
 | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								ft8/ft8.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								ft8/ft8.h
									
									
									
									
									
								
							| @ -309,6 +309,16 @@ public: | |||||||
|     std::vector<Strength> coarse(const FFTEngine::ffts_t &bins, int si0, int si1); |     std::vector<Strength> coarse(const FFTEngine::ffts_t &bins, int si0, int si1); | ||||||
| 
 | 
 | ||||||
|     FT8Params& getParams() { return params; } |     FT8Params& getParams() { return params; } | ||||||
|  |     //
 | ||||||
|  |     // given log likelyhood for each bit, try LDPC and OSD decoders.
 | ||||||
|  |     // on success, puts corrected 174 bits into a174[].
 | ||||||
|  |     //
 | ||||||
|  |     static int decode(const float ll174[], int a174[], FT8Params& params, int use_osd, std::string &comment); | ||||||
|  |     // encode a 77 bit message into a 174 bit payload
 | ||||||
|  |     // adds the 14 bit CRC to obtain 91 bits
 | ||||||
|  |     // apply (174, 91) generator mastrix to obtain the 83 parity bits
 | ||||||
|  |     // append the 83 bits to the 91 bits messag e+ crc to obbain the 174 bit payload
 | ||||||
|  |     static void encode(int a174[], int s77[]); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     //
 |     //
 | ||||||
| @ -505,11 +515,6 @@ private: | |||||||
|         float ll174[] |         float ll174[] | ||||||
|     ); |     ); | ||||||
|     //
 |     //
 | ||||||
|     // given log likelyhood for each bit, try LDPC and OSD decoders.
 |  | ||||||
|     // on success, puts corrected 174 bits into a174[].
 |  | ||||||
|     //
 |  | ||||||
|     int decode(const float ll174[], int a174[], int use_osd, std::string &comment); |  | ||||||
|     //
 |  | ||||||
|     // bandpass filter some FFT bins.
 |     // bandpass filter some FFT bins.
 | ||||||
|     // smooth transition from stop-band to pass-band,
 |     // smooth transition from stop-band to pass-band,
 | ||||||
|     // so that it's not a brick-wall filter, so that it
 |     // so that it's not a brick-wall filter, so that it
 | ||||||
|  | |||||||
							
								
								
									
										104
									
								
								ft8/ldpcgen.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										104
									
								
								ft8/ldpcgen.py
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | 
 | ||||||
|  | # Generates (prints out) C structure of FT8 LDPC generator matrix | ||||||
|  | # Derived from WSJT-X ldpc_174_91_c_generator.f90 | ||||||
|  | 
 | ||||||
|  | DATA_G = [ | ||||||
|  |     "8329ce11bf31eaf509f27fc", | ||||||
|  |     "761c264e25c259335493132", | ||||||
|  |     "dc265902fb277c6410a1bdc", | ||||||
|  |     "1b3f417858cd2dd33ec7f62", | ||||||
|  |     "09fda4fee04195fd034783a", | ||||||
|  |     "077cccc11b8873ed5c3d48a", | ||||||
|  |     "29b62afe3ca036f4fe1a9da", | ||||||
|  |     "6054faf5f35d96d3b0c8c3e", | ||||||
|  |     "e20798e4310eed27884ae90", | ||||||
|  |     "775c9c08e80e26ddae56318", | ||||||
|  |     "b0b811028c2bf997213487c", | ||||||
|  |     "18a0c9231fc60adf5c5ea32", | ||||||
|  |     "76471e8302a0721e01b12b8", | ||||||
|  |     "ffbccb80ca8341fafb47b2e", | ||||||
|  |     "66a72a158f9325a2bf67170", | ||||||
|  |     "c4243689fe85b1c51363a18", | ||||||
|  |     "0dff739414d1a1b34b1c270", | ||||||
|  |     "15b48830636c8b99894972e", | ||||||
|  |     "29a89c0d3de81d665489b0e", | ||||||
|  |     "4f126f37fa51cbe61bd6b94", | ||||||
|  |     "99c47239d0d97d3c84e0940", | ||||||
|  |     "1919b75119765621bb4f1e8", | ||||||
|  |     "09db12d731faee0b86df6b8", | ||||||
|  |     "488fc33df43fbdeea4eafb4", | ||||||
|  |     "827423ee40b675f756eb5fe", | ||||||
|  |     "abe197c484cb74757144a9a", | ||||||
|  |     "2b500e4bc0ec5a6d2bdbdd0", | ||||||
|  |     "c474aa53d70218761669360", | ||||||
|  |     "8eba1a13db3390bd6718cec", | ||||||
|  |     "753844673a27782cc42012e", | ||||||
|  |     "06ff83a145c37035a5c1268", | ||||||
|  |     "3b37417858cc2dd33ec3f62", | ||||||
|  |     "9a4a5a28ee17ca9c324842c", | ||||||
|  |     "bc29f465309c977e89610a4", | ||||||
|  |     "2663ae6ddf8b5ce2bb29488", | ||||||
|  |     "46f231efe457034c1814418", | ||||||
|  |     "3fb2ce85abe9b0c72e06fbe", | ||||||
|  |     "de87481f282c153971a0a2e", | ||||||
|  |     "fcd7ccf23c69fa99bba1412", | ||||||
|  |     "f0261447e9490ca8e474cec", | ||||||
|  |     "4410115818196f95cdd7012", | ||||||
|  |     "088fc31df4bfbde2a4eafb4", | ||||||
|  |     "b8fef1b6307729fb0a078c0", | ||||||
|  |     "5afea7acccb77bbc9d99a90", | ||||||
|  |     "49a7016ac653f65ecdc9076", | ||||||
|  |     "1944d085be4e7da8d6cc7d0", | ||||||
|  |     "251f62adc4032f0ee714002", | ||||||
|  |     "56471f8702a0721e00b12b8", | ||||||
|  |     "2b8e4923f2dd51e2d537fa0", | ||||||
|  |     "6b550a40a66f4755de95c26", | ||||||
|  |     "a18ad28d4e27fe92a4f6c84", | ||||||
|  |     "10c2e586388cb82a3d80758", | ||||||
|  |     "ef34a41817ee02133db2eb0", | ||||||
|  |     "7e9c0c54325a9c15836e000", | ||||||
|  |     "3693e572d1fde4cdf079e86", | ||||||
|  |     "bfb2cec5abe1b0c72e07fbe", | ||||||
|  |     "7ee18230c583cccc57d4b08", | ||||||
|  |     "a066cb2fedafc9f52664126", | ||||||
|  |     "bb23725abc47cc5f4cc4cd2", | ||||||
|  |     "ded9dba3bee40c59b5609b4", | ||||||
|  |     "d9a7016ac653e6decdc9036", | ||||||
|  |     "9ad46aed5f707f280ab5fc4", | ||||||
|  |     "e5921c77822587316d7d3c2", | ||||||
|  |     "4f14da8242a8b86dca73352", | ||||||
|  |     "8b8b507ad467d4441df770e", | ||||||
|  |     "22831c9cf1169467ad04b68", | ||||||
|  |     "213b838fe2ae54c38ee7180", | ||||||
|  |     "5d926b6dd71f085181a4e12", | ||||||
|  |     "66ab79d4b29ee6e69509e56", | ||||||
|  |     "958148682d748a38dd68baa", | ||||||
|  |     "b8ce020cf069c32a723ab14", | ||||||
|  |     "f4331d6d461607e95752746", | ||||||
|  |     "6da23ba424b9596133cf9c8", | ||||||
|  |     "a636bcbc7b30c5fbeae67fe", | ||||||
|  |     "5cb0d86a07df654a9089a20", | ||||||
|  |     "f11f106848780fc9ecdd80a", | ||||||
|  |     "1fbb5364fb8d2c9d730d5ba", | ||||||
|  |     "fcb86bc70a50c9d02a5d034", | ||||||
|  |     "a534433029eac15f322e34c", | ||||||
|  |     "c989d9c7c3d3b8c55d75130", | ||||||
|  |     "7bb38b2f0186d46643ae962", | ||||||
|  |     "2644ebadeb44b9467d1f42c", | ||||||
|  |     "608cc857594bfbb55d69600" | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | for data_g in DATA_G: | ||||||
|  |     rest = data_g | ||||||
|  |     rowstr = '{ ' | ||||||
|  |     while len(rest) > 0: | ||||||
|  |         byte_hex = rest[:2] | ||||||
|  |         if len(byte_hex) == 1: | ||||||
|  |             rowstr += f'0x{byte_hex}0, ' | ||||||
|  |         else: | ||||||
|  |             rowstr += f'0x{byte_hex}, ' | ||||||
|  |         rest = rest[2:] | ||||||
|  |     rowstr = rowstr[:-2] + ' },' | ||||||
|  |     print(rowstr) | ||||||
|  | 
 | ||||||
| @ -37,6 +37,7 @@ | |||||||
| #include <math.h> | #include <math.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include "arrays.h" | #include "arrays.h" | ||||||
|  | #include "libldpc.h" | ||||||
| 
 | 
 | ||||||
| // float, long float, __float128
 | // float, long float, __float128
 | ||||||
| #define REAL float | #define REAL float | ||||||
| @ -48,7 +49,7 @@ namespace FT8 | |||||||
| // returns the number of parity checks that passed.
 | // returns the number of parity checks that passed.
 | ||||||
| // 83 means total success.
 | // 83 means total success.
 | ||||||
| //
 | //
 | ||||||
| int ldpc_check(int codeword[]) | int LDPC::ldpc_check(int codeword[]) | ||||||
| { | { | ||||||
|     int score = 0; |     int score = 0; | ||||||
| 
 | 
 | ||||||
| @ -58,7 +59,7 @@ int ldpc_check(int codeword[]) | |||||||
|         int x = 0; |         int x = 0; | ||||||
|         for (int ii1 = 0; ii1 < 7; ii1++) |         for (int ii1 = 0; ii1 < 7; ii1++) | ||||||
|         { |         { | ||||||
|             int i1 = Nm[j][ii1] - 1; |             int i1 = Arrays::Nm[j][ii1] - 1; | ||||||
|             if (i1 >= 0) |             if (i1 >= 0) | ||||||
|             { |             { | ||||||
|                 x ^= codeword[i1]; |                 x ^= codeword[i1]; | ||||||
| @ -75,7 +76,7 @@ int ldpc_check(int codeword[]) | |||||||
| // iters is how hard to try.
 | // iters is how hard to try.
 | ||||||
| // ok is the number of parity checks that worked out,
 | // ok is the number of parity checks that worked out,
 | ||||||
| // ok == 83 means success.
 | // ok == 83 means success.
 | ||||||
| void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok) | void LDPC::ldpc_decode(float llcodeword[], int iters, int plain[], int *ok) | ||||||
| { | { | ||||||
|     REAL m[83][174]; |     REAL m[83][174]; | ||||||
|     REAL e[83][174]; |     REAL e[83][174]; | ||||||
| @ -114,13 +115,13 @@ void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok) | |||||||
|         { |         { | ||||||
|             for (int ii1 = 0; ii1 < 7; ii1++) |             for (int ii1 = 0; ii1 < 7; ii1++) | ||||||
|             { |             { | ||||||
|                 int i1 = Nm[j][ii1] - 1; |                 int i1 = Arrays::Nm[j][ii1] - 1; | ||||||
|                 if (i1 < 0) |                 if (i1 < 0) | ||||||
|                     continue; |                     continue; | ||||||
|                 REAL a = 1.0; |                 REAL a = 1.0; | ||||||
|                 for (int ii2 = 0; ii2 < 7; ii2++) |                 for (int ii2 = 0; ii2 < 7; ii2++) | ||||||
|                 { |                 { | ||||||
|                     int i2 = Nm[j][ii2] - 1; |                     int i2 = Arrays::Nm[j][ii2] - 1; | ||||||
|                     if (i2 >= 0 && i2 != i1) |                     if (i2 >= 0 && i2 != i1) | ||||||
|                     { |                     { | ||||||
|                         // tmp ranges from 1.0 to -1.0, for
 |                         // tmp ranges from 1.0 to -1.0, for
 | ||||||
| @ -145,7 +146,7 @@ void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok) | |||||||
|             REAL q1 = 1.0 - q0; |             REAL q1 = 1.0 - q0; | ||||||
|             for (int j = 0; j < 3; j++) |             for (int j = 0; j < 3; j++) | ||||||
|             { |             { | ||||||
|                 int j2 = Mn[i][j] - 1; |                 int j2 = Arrays::Mn[i][j] - 1; | ||||||
|                 q0 *= e[j2][i]; |                 q0 *= e[j2][i]; | ||||||
|                 q1 *= 1.0 - e[j2][i]; |                 q1 *= 1.0 - e[j2][i]; | ||||||
|             } |             } | ||||||
| @ -181,12 +182,12 @@ void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok) | |||||||
|         { |         { | ||||||
|             for (int ji1 = 0; ji1 < 3; ji1++) |             for (int ji1 = 0; ji1 < 3; ji1++) | ||||||
|             { |             { | ||||||
|                 int j1 = Mn[i][ji1] - 1; |                 int j1 = Arrays::Mn[i][ji1] - 1; | ||||||
|                 REAL q0 = codeword[i]; |                 REAL q0 = codeword[i]; | ||||||
|                 REAL q1 = 1.0 - q0; |                 REAL q1 = 1.0 - q0; | ||||||
|                 for (int ji2 = 0; ji2 < 3; ji2++) |                 for (int ji2 = 0; ji2 < 3; ji2++) | ||||||
|                 { |                 { | ||||||
|                     int j2 = Mn[i][ji2] - 1; |                     int j2 = Arrays::Mn[i][ji2] - 1; | ||||||
|                     if (j1 != j2) |                     if (j1 != j2) | ||||||
|                     { |                     { | ||||||
|                         q0 *= e[j2][i]; |                         q0 *= e[j2][i]; | ||||||
| @ -217,7 +218,7 @@ void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok) | |||||||
| 
 | 
 | ||||||
| // thank you Douglas Bagnall
 | // thank you Douglas Bagnall
 | ||||||
| // https://math.stackexchange.com/a/446411
 | // https://math.stackexchange.com/a/446411
 | ||||||
| float fast_tanh(float x) | float LDPC::fast_tanh(float x) | ||||||
| { | { | ||||||
|     if (x < -7.6) |     if (x < -7.6) | ||||||
|     { |     { | ||||||
| @ -256,7 +257,7 @@ return tanhtable[ind]; | |||||||
| // iters is how hard to try.
 | // iters is how hard to try.
 | ||||||
| // ok is the number of parity checks that worked out,
 | // ok is the number of parity checks that worked out,
 | ||||||
| // ok == 83 means success.
 | // ok == 83 means success.
 | ||||||
| void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok) | void LDPC::ldpc_decode_log(float codeword[], int iters, int plain[], int *ok) | ||||||
| { | { | ||||||
|     REAL m[83][174]; |     REAL m[83][174]; | ||||||
|     REAL e[83][174]; |     REAL e[83][174]; | ||||||
| @ -277,13 +278,13 @@ void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok) | |||||||
|         { |         { | ||||||
|             for (int ii1 = 0; ii1 < 7; ii1++) |             for (int ii1 = 0; ii1 < 7; ii1++) | ||||||
|             { |             { | ||||||
|                 int i1 = Nm[j][ii1] - 1; |                 int i1 = Arrays::Nm[j][ii1] - 1; | ||||||
|                 if (i1 < 0) |                 if (i1 < 0) | ||||||
|                     continue; |                     continue; | ||||||
|                 REAL a = 1.0; |                 REAL a = 1.0; | ||||||
|                 for (int ii2 = 0; ii2 < 7; ii2++) |                 for (int ii2 = 0; ii2 < 7; ii2++) | ||||||
|                 { |                 { | ||||||
|                     int i2 = Nm[j][ii2] - 1; |                     int i2 = Arrays::Nm[j][ii2] - 1; | ||||||
|                     if (i2 >= 0 && i2 != i1) |                     if (i2 >= 0 && i2 != i1) | ||||||
|                     { |                     { | ||||||
|                         // a *= table_tanh(m[j][i2] / 2.0);
 |                         // a *= table_tanh(m[j][i2] / 2.0);
 | ||||||
| @ -312,7 +313,7 @@ void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok) | |||||||
|         { |         { | ||||||
|             REAL l = codeword[i]; |             REAL l = codeword[i]; | ||||||
|             for (int j = 0; j < 3; j++) |             for (int j = 0; j < 3; j++) | ||||||
|                 l += e[Mn[i][j] - 1][i]; |                 l += e[Arrays::Mn[i][j] - 1][i]; | ||||||
|             cw[i] = (l <= 0.0); |             cw[i] = (l <= 0.0); | ||||||
|         } |         } | ||||||
|         int score = ldpc_check(cw); |         int score = ldpc_check(cw); | ||||||
| @ -335,11 +336,11 @@ void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok) | |||||||
|         { |         { | ||||||
|             for (int ji1 = 0; ji1 < 3; ji1++) |             for (int ji1 = 0; ji1 < 3; ji1++) | ||||||
|             { |             { | ||||||
|                 int j1 = Mn[i][ji1] - 1; |                 int j1 = Arrays::Mn[i][ji1] - 1; | ||||||
|                 REAL l = codeword[i]; |                 REAL l = codeword[i]; | ||||||
|                 for (int ji2 = 0; ji2 < 3; ji2++) |                 for (int ji2 = 0; ji2 < 3; ji2++) | ||||||
|                 { |                 { | ||||||
|                     int j2 = Mn[i][ji2] - 1; |                     int j2 = Arrays::Mn[i][ji2] - 1; | ||||||
|                     if (j1 != j2) |                     if (j1 != j2) | ||||||
|                     { |                     { | ||||||
|                         l += e[j2][i]; |                         l += e[j2][i]; | ||||||
| @ -361,7 +362,7 @@ void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok) | |||||||
| // check the FT8 CRC-14
 | // check the FT8 CRC-14
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| void ft8_crc(int msg1[], int msglen, int out[14]) | void LDPC::ft8_crc(int msg1[], int msglen, int out[14]) | ||||||
| { | { | ||||||
|     // the old FT8 polynomial for 12-bit CRC, 0xc06.
 |     // the old FT8 polynomial for 12-bit CRC, 0xc06.
 | ||||||
|     // int div[] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 };
 |     // int div[] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 };
 | ||||||
| @ -407,7 +408,7 @@ void ft8_crc(int msg1[], int msglen, int out[14]) | |||||||
| // m[174][2*91].
 | // m[174][2*91].
 | ||||||
| // m's right half should start out as zeros.
 | // m's right half should start out as zeros.
 | ||||||
| // m's upper-right quarter will be the desired inverse.
 | // m's upper-right quarter will be the desired inverse.
 | ||||||
| void gauss_jordan(int rows, int cols, int m[174][2 * 91], int which[91], int *ok) | void LDPC::gauss_jordan(int rows, int cols, int m[174][2 * 91], int which[91], int *ok) | ||||||
| // gauss_jordan(int rows, int cols, int m[cols][2*rows], int which[rows], int *ok)
 | // gauss_jordan(int rows, int cols, int m[cols][2*rows], int which[rows], int *ok)
 | ||||||
| { | { | ||||||
|     *ok = 0; |     *ok = 0; | ||||||
|  | |||||||
| @ -24,13 +24,17 @@ | |||||||
| 
 | 
 | ||||||
| namespace FT8 { | namespace FT8 { | ||||||
| 
 | 
 | ||||||
| int ldpc_check(int codeword[]); | class LDPC { | ||||||
| void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok); | public: | ||||||
| float fast_tanh(float x); |     static void ldpc_decode(float llcodeword[], int iters, int plain[], int *ok); | ||||||
| void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok); |     static void ldpc_decode_log(float codeword[], int iters, int plain[], int *ok); | ||||||
| void ft8_crc(int msg1[], int msglen, int out[14]); |     static void ft8_crc(int msg1[], int msglen, int out[14]); | ||||||
| void gauss_jordan(int rows, int cols, int m[174][2 * 91], int which[91], int *ok); |     static void gauss_jordan(int rows, int cols, int m[174][2 * 91], int which[91], int *ok); | ||||||
| 
 | 
 | ||||||
|  | private: | ||||||
|  |     static int ldpc_check(int codeword[]); | ||||||
|  |     static float fast_tanh(float x); | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| } // namespace FT8
 | } // namespace FT8
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -57,7 +57,7 @@ int OSD::check_crc(const int a91[91]) | |||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     // why 82? why not 77?
 |     // why 82? why not 77?
 | ||||||
|     ft8_crc(aa, 82, out1); |     LDPC::ft8_crc(aa, 82, out1); | ||||||
| 
 | 
 | ||||||
|     for (int i = 0; i < 14; i++) |     for (int i = 0; i < 14; i++) | ||||||
|     { |     { | ||||||
| @ -216,7 +216,7 @@ int OSD::osd_decode(float codeword[174], int depth, int out[91], int *out_depth) | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     int ok = 0; |     int ok = 0; | ||||||
|     gauss_jordan(91, 174, b, xwhich, &ok); |     LDPC::gauss_jordan(91, 174, b, xwhich, &ok); | ||||||
| 
 | 
 | ||||||
|     if (ok == 0) { |     if (ok == 0) { | ||||||
|         fprintf(stderr, "gauss_jordan failed\n"); |         fprintf(stderr, "gauss_jordan failed\n"); | ||||||
|  | |||||||
							
								
								
									
										51
									
								
								ft8/pack0.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								ft8/pack0.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Copyright (C) 2024 Edouard Griffiths, F4EXB <f4exb06@gmail.com>               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This is the code from ft8mon: https://github.com/rtmrtmrtmrtm/ft8mon          //
 | ||||||
|  | // reformatted and adapted to Qt and SDRangel context                            //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is free software; you can redistribute it and/or modify          //
 | ||||||
|  | // it under the terms of the GNU General Public License as published by          //
 | ||||||
|  | // the Free Software Foundation as version 3 of the License, or                  //
 | ||||||
|  | // (at your option) any later version.                                           //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is distributed in the hope that it will be useful,               //
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||||
|  | // GNU General Public License V3 for more details.                               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // You should have received a copy of the GNU General Public License             //
 | ||||||
|  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | #include "pack0.h" | ||||||
|  | 
 | ||||||
|  | namespace FT8 { | ||||||
|  | 
 | ||||||
|  | void pa128(int a77[], int start, int len, const boost::multiprecision::int128_t value) | ||||||
|  | { | ||||||
|  |     boost::multiprecision::int128_t x = value; | ||||||
|  |     int i = start + len; | ||||||
|  | 
 | ||||||
|  |     while (x != 0) | ||||||
|  |     { | ||||||
|  |         i--; | ||||||
|  |         a77[i] = (int) (x % 2); | ||||||
|  |         x /= 2; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void pa64(int a77[], int start, int len, const uint64_t value) | ||||||
|  | { | ||||||
|  |     uint64_t x = value; | ||||||
|  |     int i = start + len; | ||||||
|  | 
 | ||||||
|  |     while (x != 0) | ||||||
|  |     { | ||||||
|  |         i--; | ||||||
|  |         a77[i] = x % 2; | ||||||
|  |         x /= 2; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespae FT8
 | ||||||
							
								
								
									
										28
									
								
								ft8/pack0.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								ft8/pack0.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Copyright (C) 2024 Edouard Griffiths, F4EXB <f4exb06@gmail.com>               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This is the code from ft8mon: https://github.com/rtmrtmrtmrtm/ft8mon          //
 | ||||||
|  | // reformatted and adapted to Qt and SDRangel context                            //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is free software; you can redistribute it and/or modify          //
 | ||||||
|  | // it under the terms of the GNU General Public License as published by          //
 | ||||||
|  | // the Free Software Foundation as version 3 of the License, or                  //
 | ||||||
|  | // (at your option) any later version.                                           //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is distributed in the hope that it will be useful,               //
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||||
|  | // GNU General Public License V3 for more details.                               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // You should have received a copy of the GNU General Public License             //
 | ||||||
|  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | #include <boost/multiprecision/cpp_int.hpp> | ||||||
|  | 
 | ||||||
|  | namespace FT8 | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | void pa128(int a77[], int start, int len, const boost::multiprecision::int128_t value); | ||||||
|  | void pa64(int a77[], int start, int len, const uint64_t value); // pack into bits MSB first
 | ||||||
|  | 
 | ||||||
|  | } // namespace FT8
 | ||||||
| @ -18,9 +18,11 @@ | |||||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <regex> | ||||||
| 
 | 
 | ||||||
| #include "unpack.h" | #include "packing.h" | ||||||
| #include "unpack0.h" | #include "unpack0.h" | ||||||
|  | #include "pack0.h" | ||||||
| #include "util.h" | #include "util.h" | ||||||
| 
 | 
 | ||||||
| namespace FT8 { | namespace FT8 { | ||||||
| @ -716,4 +718,220 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s | |||||||
|     return std::string(tmp); |     return std::string(tmp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool Packing::packcall_std(int& c28, const std::string& callstr) | ||||||
|  | { | ||||||
|  |     c28 = 0; | ||||||
|  | 
 | ||||||
|  |     if (callstr.size() == 2) | ||||||
|  |     { | ||||||
|  |         if (callstr == "DE") { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (callstr == "CQ") | ||||||
|  |         { | ||||||
|  |             c28 = 2; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (callstr == "QRZ") | ||||||
|  |     { | ||||||
|  |         c28 = 1; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (callstr.rfind("CQ ", 0) == 0) // special CQ
 | ||||||
|  |     { | ||||||
|  |         std::regex cq_regex_num("CQ (\\d\\d\\d)"); | ||||||
|  |         std::regex cq_regex_alpha("CQ ([A-Z]+)"); | ||||||
|  |         std::smatch cq_match; | ||||||
|  | 
 | ||||||
|  |         if (std::regex_match(callstr, cq_match, cq_regex_num)) | ||||||
|  |         { | ||||||
|  |             std::string cq_num_arg = cq_match[1].str(); | ||||||
|  |             int cq_num = stoi(cq_num_arg); | ||||||
|  |             c28 = 3 + cq_num; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (std::regex_match(callstr, cq_match, cq_regex_alpha)) | ||||||
|  |         { | ||||||
|  |             std::string cq_alpha_arg = cq_match[1].str(); | ||||||
|  | 
 | ||||||
|  |             if (cq_alpha_arg.size() > 4) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             int arg_value = 1; | ||||||
|  | 
 | ||||||
|  |             for (auto c : cq_alpha_arg) { | ||||||
|  |                 arg_value *= int(c) - int('A') + 1; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (cq_alpha_arg.size() == 1) { | ||||||
|  |                 c28 = 1003 + arg_value; | ||||||
|  |             } else if (cq_alpha_arg.size() == 2) { | ||||||
|  |                 c28 = 1030 + arg_value; | ||||||
|  |             } else if (cq_alpha_arg.size() == 3) { | ||||||
|  |                 c28 = 1759 + arg_value; | ||||||
|  |             } else if (cq_alpha_arg.size() == 4) { | ||||||
|  |                 c28 = 21442 + arg_value; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if ((callstr.size() < 3) || (callstr.size() > 6)) { // standard callsigns are 3 to 6 characters
 | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::string call_prefix; | ||||||
|  |     int call_num; | ||||||
|  |     std::string call_suffix; | ||||||
|  | 
 | ||||||
|  |     if (isdigit(callstr.at(0))) | ||||||
|  |     { | ||||||
|  |         std::regex call_regex("(\\d[A-Z])(\\d)([A-Z]{1,3})"); | ||||||
|  |         std::smatch call_match; | ||||||
|  | 
 | ||||||
|  |         if (std::regex_match(callstr, call_match, call_regex)) | ||||||
|  |         { | ||||||
|  |             call_prefix = call_match[1].str(); | ||||||
|  |             call_num = stoi(call_match[2].str()); | ||||||
|  |             call_suffix = call_match[3].str(); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         std::regex call_regex("([A-Z0-9]{1,2})(\\d)([A-Z]{1,3})"); | ||||||
|  |         std::smatch call_match; | ||||||
|  | 
 | ||||||
|  |         if (std::regex_match(callstr, call_match, call_regex)) | ||||||
|  |         { | ||||||
|  |             call_prefix = call_match[1].str(); | ||||||
|  |             call_num = stoi(call_match[2].str()); | ||||||
|  |             call_suffix = call_match[3].str(); | ||||||
|  | 
 | ||||||
|  |             if (isdigit(call_prefix.at(0))) { // In this case the first character cannot be a digit
 | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // qDebug("Packing::packcall_std: %s %d %s", call_prefix.c_str(), call_num, call_suffix.c_str());
 | ||||||
|  |     int i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0; | ||||||
|  |     std::string alnums = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||||||
|  |     std::string alphas = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||||||
|  | 
 | ||||||
|  |     if (call_prefix.size() == 2) | ||||||
|  |     { | ||||||
|  |         i1 = alnums.find(call_prefix.at(0)) + 1; | ||||||
|  |         i2 = alnums.find(call_prefix.at(1)); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         i2 = alnums.find(call_prefix.at(0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     i3 = call_num; | ||||||
|  |     i4 = alphas.find(call_suffix.at(0)) + 1; | ||||||
|  | 
 | ||||||
|  |     if (call_suffix.size() > 1) { | ||||||
|  |         i5 = alphas.find(call_suffix.at(1)) + 1; | ||||||
|  |     } | ||||||
|  |     if (call_suffix.size() > 2) { | ||||||
|  |         i6 = alphas.find(call_suffix.at(2)) + 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     c28 = 2063592 + (1<<22) + 36*10*27*27*27*i1 + 10*27*27*27*i2 + 27*27*27*i3 + 27*27*i4 + 27*i5 + i6; | ||||||
|  |     // qDebug("Packing::packcall c28: %d, i1: %d, i2: %d, i3: %d, i4: %d, i5: %d, i6: %d", c28, i1, i2, i3, i4, i5, i6);
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Packing::packgrid(int& g15, const std::string& locstr) | ||||||
|  | { | ||||||
|  |     static const int MAXGRID4 = 32400; | ||||||
|  |     std::regex loc_regex("[A-R][A-R][0-9][0-9]"); | ||||||
|  |     std::smatch loc_match; | ||||||
|  |     g15 = 0; | ||||||
|  | 
 | ||||||
|  |     if (locstr.size() == 0) | ||||||
|  |     { | ||||||
|  |         g15 = MAXGRID4 + 1; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (locstr == "RRR") | ||||||
|  |     { | ||||||
|  |         g15 = MAXGRID4 + 2; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (locstr == "RR73") | ||||||
|  |     { | ||||||
|  |         g15 = MAXGRID4 + 3; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (locstr == "73") | ||||||
|  |     { | ||||||
|  |         g15 = MAXGRID4 + 4; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (std::regex_match(locstr, loc_match, loc_regex)) // Maidenhead 4 char locator
 | ||||||
|  |     { | ||||||
|  |         int i1 = int(locstr.at(0)) - int('A'); | ||||||
|  |         int i2 = int(locstr.at(1)) - int('A'); | ||||||
|  |         int i3 = int(locstr.at(2)) - int('0'); | ||||||
|  |         int i4 = int(locstr.at(3)) - int('0'); | ||||||
|  |         g15 = i1*18*10*10 + i2*10*10 + i3*10 + i4; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::regex rpt_regex("([+-])(\\d)(\\d)"); | ||||||
|  | 
 | ||||||
|  |     if (std::regex_match(locstr, loc_match, rpt_regex)) // Report -30 to +99
 | ||||||
|  |     { | ||||||
|  |         int i1 = int(locstr.at(1)) - int('0'); | ||||||
|  |         int i2 = int(locstr.at(2)) - int('0'); | ||||||
|  |         int s = (locstr.at(0) == '-') ? -1 : 1; | ||||||
|  |         g15 = MAXGRID4 + 35 + s*(i1*10 + i2); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Packing::packfree(int a77[], const std::string& msg) | ||||||
|  | { | ||||||
|  |     std::string s = msg; | ||||||
|  |     s.append(13, ' '); | ||||||
|  |     s = s.substr(0, 13); | ||||||
|  | 
 | ||||||
|  |     std::string a = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"; | ||||||
|  |     boost::multiprecision::int128_t b = 1, x = 0; | ||||||
|  | 
 | ||||||
|  |     for (int i=12; i>=0; i--) | ||||||
|  |     { | ||||||
|  |         int ai = a.find(s.at(i)); | ||||||
|  |         ai = (ai < 0) ? 0 : ai; // map unknown characters to blanks
 | ||||||
|  |         x += ai * b; | ||||||
|  |         b *= 42; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pa128(a77, 0, 71, x); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace FT8
 | } // namespace FT8
 | ||||||
| @ -35,6 +35,11 @@ class FT8_API Packing | |||||||
| { | { | ||||||
| public: | public: | ||||||
|     std::string unpack(int a91[], std::string& call1str, std::string& call2str, std::string& locstr, std::string& type); |     std::string unpack(int a91[], std::string& call1str, std::string& call2str, std::string& locstr, std::string& type); | ||||||
|  |     static std::string unpack_0_0(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
|  |     std::string unpack_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
|  |     static bool packcall_std(int& c28, const std::string& callstr); | ||||||
|  |     static bool packgrid(int& g15, const std::string& locstr); | ||||||
|  |     static bool packfree(int a77[], const std::string& msg); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     static int ihashcall(std::string call, int m); |     static int ihashcall(std::string call, int m); | ||||||
| @ -42,17 +47,16 @@ private: | |||||||
|     std::string unpackgrid15(int ng, int ir); |     std::string unpackgrid15(int ng, int ir); | ||||||
|     std::string unpackgrid25(int ng); |     std::string unpackgrid25(int ng); | ||||||
|     void remember_call(std::string call); |     void remember_call(std::string call); | ||||||
|     std::string unpack_0_0(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); |  | ||||||
|     std::string unpack_0_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); |     std::string unpack_0_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
|     // 0.3 and 0.4
 |     // 0.3 and 0.4
 | ||||||
|     std::string unpack_0_3(int a77[], int n3, std::string& call1str, std::string& call2str, std::string& locstr); |     std::string unpack_0_3(int a77[], int n3, std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
|     std::string unpack_0_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); |     std::string unpack_0_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
|     // 1 and 2
 |     // 1 and 2
 | ||||||
|     std::string unpack_1(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); |  | ||||||
|     std::string unpack_3(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); |     std::string unpack_3(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
|     std::string unpack_4(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); |     std::string unpack_4(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
|     std::string unpack_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); |     std::string unpack_5(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     QMutex hashes_mu; |     QMutex hashes_mu; | ||||||
|     std::map<int, std::string> hashes10; |     std::map<int, std::string> hashes10; | ||||||
|     std::map<int, std::string> hashes12; |     std::map<int, std::string> hashes12; | ||||||
| @ -24,7 +24,7 @@ | |||||||
| #include <QSet> | #include <QSet> | ||||||
| 
 | 
 | ||||||
| #include "ft8.h" | #include "ft8.h" | ||||||
| #include "unpack.h" | #include "packing.h" | ||||||
| 
 | 
 | ||||||
| class QDateTime; | class QDateTime; | ||||||
| class MessageQueue; | class MessageQueue; | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ set(sdrbench_SOURCES | |||||||
|     test_golay2312.cpp |     test_golay2312.cpp | ||||||
|     test_ft8.cpp |     test_ft8.cpp | ||||||
|     test_callsign.cpp |     test_callsign.cpp | ||||||
|  |     test_ft8protocols.cpp | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| set(sdrbench_HEADERS | set(sdrbench_HEADERS | ||||||
|  | |||||||
| @ -71,6 +71,8 @@ void MainBench::run() | |||||||
|         testFT8(m_parser.getFileName(), m_parser.getArgsStr()); |         testFT8(m_parser.getFileName(), m_parser.getArgsStr()); | ||||||
|     } else if (m_parser.getTestType() == ParserBench::TestCallsign) { |     } else if (m_parser.getTestType() == ParserBench::TestCallsign) { | ||||||
|         testCallsign(m_parser.getArgsStr()); |         testCallsign(m_parser.getArgsStr()); | ||||||
|  |     } else if (m_parser.getTestType() == ParserBench::TestFT8Protocols) { | ||||||
|  |         testFT8Protocols(m_parser.getArgsStr()); | ||||||
|     } else { |     } else { | ||||||
|         qDebug() << "MainBench::run: unknown test type: " << m_parser.getTestType(); |         qDebug() << "MainBench::run: unknown test type: " << m_parser.getTestType(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -58,6 +58,7 @@ private: | |||||||
|     void testDecimateFF(); |     void testDecimateFF(); | ||||||
|     void testGolay2312(); |     void testGolay2312(); | ||||||
|     void testFT8(const QString& wavFile, const QString& argsStr); //!< use with sdrbench/samples/ft8/230105_091630.wav in -f option
 |     void testFT8(const QString& wavFile, const QString& argsStr); //!< use with sdrbench/samples/ft8/230105_091630.wav in -f option
 | ||||||
|  |     void testFT8Protocols(const QString& argsStr); | ||||||
|     void testCallsign(const QString& argsStr); |     void testCallsign(const QString& argsStr); | ||||||
|     void decimateII(const qint16 *buf, int len); |     void decimateII(const qint16 *buf, int len); | ||||||
|     void decimateInfII(const qint16 *buf, int len); |     void decimateInfII(const qint16 *buf, int len); | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ | |||||||
| 
 | 
 | ||||||
| ParserBench::ParserBench() : | ParserBench::ParserBench() : | ||||||
|     m_testOption(QStringList() << "t" << "test", |     m_testOption(QStringList() << "t" << "test", | ||||||
|         "Test type: decimateii, decimatefi, decimateff, decimateif, decimateinfii, decimatesupii, ambe, golay2312, ft8, callsign" |         "Test type: decimateii, decimatefi, decimateff, decimateif, decimateinfii, decimatesupii, ambe, golay2312, ft8, ft8protocols, callsign" | ||||||
|         "test", |         "test", | ||||||
|         "decimateii"), |         "decimateii"), | ||||||
|     m_nbSamplesOption(QStringList() << "n" << "nb-samples", |     m_nbSamplesOption(QStringList() << "n" << "nb-samples", | ||||||
| @ -149,6 +149,8 @@ ParserBench::TestType ParserBench::getTestType() const | |||||||
|         return TestFT8; |         return TestFT8; | ||||||
|     } else if (m_testStr == "callsign") { |     } else if (m_testStr == "callsign") { | ||||||
|         return TestCallsign; |         return TestCallsign; | ||||||
|  |     } else if (m_testStr == "ft8protocols") { | ||||||
|  |         return TestFT8Protocols; | ||||||
|     } else { |     } else { | ||||||
|         return TestDecimatorsII; |         return TestDecimatorsII; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -39,7 +39,8 @@ public: | |||||||
|         TestDecimatorsSupII, |         TestDecimatorsSupII, | ||||||
|         TestGolay2312, |         TestGolay2312, | ||||||
|         TestFT8, |         TestFT8, | ||||||
|         TestCallsign |         TestCallsign, | ||||||
|  |         TestFT8Protocols | ||||||
|     } TestType; |     } TestType; | ||||||
| 
 | 
 | ||||||
|     ParserBench(); |     ParserBench(); | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ void MainBench::testFT8(const QString& wavFile, const QString& argsStr) | |||||||
| #else | #else | ||||||
| 
 | 
 | ||||||
| #include "ft8/ft8.h" | #include "ft8/ft8.h" | ||||||
| #include "ft8/unpack.h" | #include "ft8/packing.h" | ||||||
| 
 | 
 | ||||||
| class TestFT8Callback : public FT8::CallbackInterface | class TestFT8Callback : public FT8::CallbackInterface | ||||||
| { | { | ||||||
|  | |||||||
							
								
								
									
										233
									
								
								sdrbench/test_ft8protocols.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								sdrbench/test_ft8protocols.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | |||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | // Copyright (C) 2024 Edouard Griffiths, F4EXB <f4exb06@gmail.com>               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is free software; you can redistribute it and/or modify          //
 | ||||||
|  | // it under the terms of the GNU General Public License as published by          //
 | ||||||
|  | // the Free Software Foundation as version 3 of the License, or                  //
 | ||||||
|  | // (at your option) any later version.                                           //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // This program is distributed in the hope that it will be useful,               //
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||||
|  | // GNU General Public License V3 for more details.                               //
 | ||||||
|  | //                                                                               //
 | ||||||
|  | // You should have received a copy of the GNU General Public License             //
 | ||||||
|  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | #include <iostream> | ||||||
|  | #include <fstream> | ||||||
|  | #include <regex> | ||||||
|  | 
 | ||||||
|  | #include <QTextStream> | ||||||
|  | 
 | ||||||
|  | #include "mainbench.h" | ||||||
|  | 
 | ||||||
|  | #ifndef HAS_FT8 | ||||||
|  | void MainBench::testFT8(const QString& wavFile, const QString& argsStr) | ||||||
|  | { | ||||||
|  |     (void) wavFile; | ||||||
|  |     (void) argsStr; | ||||||
|  |     qWarning("MainBench::testFT8: this version has no FT8 support"); | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | 
 | ||||||
|  | #include "ft8/ft8.h" | ||||||
|  | #include "ft8/packing.h" | ||||||
|  | #include "ft8/pack0.h" | ||||||
|  | 
 | ||||||
|  | class TestFT8Protocols | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         static void testMsg1(const QStringList& argElements, bool runLDPC = false); | ||||||
|  |         static void testMsg00(const QStringList& argElements, bool runLDPC = false); | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         static bool testLDPC(int a77[]); | ||||||
|  |         static bool compare174(int a174[], int r174[]); | ||||||
|  |         static void debugIntArray(int a[], int length); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void MainBench::testFT8Protocols(const QString& argsStr) | ||||||
|  | { | ||||||
|  |     QStringList argElements = argsStr.split(','); // comma separated list of arguments
 | ||||||
|  | 
 | ||||||
|  |     if (argElements.size() == 0) | ||||||
|  |     { | ||||||
|  |         qWarning("MainBench::testFT8Protocols: no arguments"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     QString& testType = argElements[0]; | ||||||
|  | 
 | ||||||
|  |     if (testType == "msg1") { | ||||||
|  |         TestFT8Protocols::testMsg1(argElements); // type 1 message test
 | ||||||
|  |     } else if (testType == "msg00") { | ||||||
|  |         TestFT8Protocols::testMsg00(argElements); // type 0.0 message test
 | ||||||
|  |     } else if (testType == "msg1L") { | ||||||
|  |         TestFT8Protocols::testMsg1(argElements, true); // type 1 message test with LDPC encoding/decoding test
 | ||||||
|  |     } else if (testType == "msg00L") { | ||||||
|  |         TestFT8Protocols::testMsg00(argElements, true); // type 0.0 message test with LDPC encoding/decoding test
 | ||||||
|  |     } else { | ||||||
|  |         qWarning("MainBench::testFT8Protocols: unrecognized test type"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void TestFT8Protocols::testMsg1(const QStringList& argElements, bool runLDPC) | ||||||
|  | { | ||||||
|  |     if (argElements.size() < 4) | ||||||
|  |     { | ||||||
|  |         qWarning("TestFT8Protocols::testMsg1: missing callsigns and locator/report in argument"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int c28_1, c28_2, g15; | ||||||
|  | 
 | ||||||
|  |     if (!FT8::Packing::packcall_std(c28_1, argElements[1].toStdString())) | ||||||
|  |     { | ||||||
|  |         qWarning("TestFT8Protocols::testMsg1: callsign %s is not a standard callsign", qPrintable(argElements[1])); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!FT8::Packing::packcall_std(c28_2, argElements[2].toStdString())) | ||||||
|  |     { | ||||||
|  |         qWarning("TestFT8Protocols::testMsg1: callsign %s is not a standard callsign", qPrintable(argElements[2])); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     std::string locstr; | ||||||
|  |     int report; | ||||||
|  | 
 | ||||||
|  |     if (argElements[3].startsWith("R+") || argElements[3].startsWith("R-")) | ||||||
|  |     { | ||||||
|  |         report = 1; | ||||||
|  |         locstr = argElements[3].mid(1).toStdString(); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         report = 0; | ||||||
|  |         locstr = argElements[3].toStdString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!FT8::Packing::packgrid(g15, locstr)) | ||||||
|  |     { | ||||||
|  |         qWarning("TestFT8Protocols::testMsg1: locator or report %s is not valid", locstr.c_str()); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     qDebug("TestFT8Protocols::testMsg1: c28_1: %d c28_2: %d g15: %d", c28_1, c28_2, g15); | ||||||
|  | 
 | ||||||
|  |     int a77[77]; | ||||||
|  |     std::fill(a77, a77 + 77, 0); | ||||||
|  | 
 | ||||||
|  |     FT8::pa64(a77, 0, 28, c28_1); | ||||||
|  |     FT8::pa64(a77, 28+1, 28, c28_2); | ||||||
|  |     a77[28+1+28+1] = report; | ||||||
|  |     FT8::pa64(a77, 28+1+28+2, 15, g15); | ||||||
|  |     FT8::pa64(a77, 28+1+28+2+15, 3, 1); | ||||||
|  | 
 | ||||||
|  |     FT8::Packing packing; | ||||||
|  | 
 | ||||||
|  |     std::string call1, call2, loc; | ||||||
|  |     std::string msg = packing.unpack_1(a77, call1, call2, loc); | ||||||
|  |     qInfo("TestFT8Protocols::testMsg1: msg: %s, call1: %s, call2: %s, loc: %s", msg.c_str(), call1.c_str(), call2.c_str(), loc.c_str()); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     if (runLDPC) | ||||||
|  |     { | ||||||
|  |         if (testLDPC(a77)) { | ||||||
|  |             qInfo("TestFT8Protocols::testMsg1: LDPC test suceeded"); | ||||||
|  |         } else { | ||||||
|  |             qWarning("TestFT8Protocols::testMsg1: LDPC test failed"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TestFT8Protocols::testMsg00(const QStringList& argElements, bool runLDPC) | ||||||
|  | { | ||||||
|  |     if (argElements.size() < 2) | ||||||
|  |     { | ||||||
|  |         qWarning("TestFT8Protocols::testMsg00: missing free text in argument"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int a77[77]; | ||||||
|  |     std::fill(a77, a77 + 77, 0); | ||||||
|  | 
 | ||||||
|  |     if (!FT8::Packing::packfree(a77, argElements[1].toStdString())) | ||||||
|  |     { | ||||||
|  |         qWarning("TestFT8Protocols::testMsg00: message %s is not valid", qPrintable(argElements[1])); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::string call1, call2, loc; | ||||||
|  |     std::string msg = FT8::Packing::unpack_0_0(a77, call1, call2, loc); | ||||||
|  |     qInfo("TestFT8Protocols::testMsg00: msg: %s, call1: %s", msg.c_str(), call1.c_str()); | ||||||
|  | 
 | ||||||
|  |     if (runLDPC) | ||||||
|  |     { | ||||||
|  |         if (testLDPC(a77)) { | ||||||
|  |             qInfo("TestFT8Protocols::testMsg00: LDPC test suceeded"); | ||||||
|  |         } else { | ||||||
|  |             qWarning("TestFT8Protocols::testMsg00: LDPC test failed"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool TestFT8Protocols::testLDPC(int a77[]) | ||||||
|  | { | ||||||
|  |     int a174[174], r174[174]; | ||||||
|  |     FT8::FT8::encode(a174, a77); | ||||||
|  |     FT8::FT8Params ft8Params; | ||||||
|  |     float ll174[174]; | ||||||
|  |     FT8::FT8Params params; | ||||||
|  |     std::string comments; | ||||||
|  | 
 | ||||||
|  |     std::transform( | ||||||
|  |         a174, | ||||||
|  |         a174+174, | ||||||
|  |         ll174, | ||||||
|  |         [](const int& s) -> float { return s == 1 ? -1.0 : 1.0; } | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if (FT8::FT8::decode(ll174, r174, params, 0, comments) == 0) | ||||||
|  |     { | ||||||
|  |         qInfo("TestFT8Protocols::testLDPC(: LDPC or CRC check failed"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         return compare174(a174, r174); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool TestFT8Protocols::compare174(int a174[], int r174[]) | ||||||
|  | { | ||||||
|  |     for (int i=0; i < 174; i++) | ||||||
|  |     { | ||||||
|  |         if (a174[i] != r174[i]) | ||||||
|  |         { | ||||||
|  |             qDebug("TestFT8Protocols::compare174: failed at index %d: %d != %d", i, a174[i], r174[i]); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TestFT8Protocols::debugIntArray(int a[], int length) | ||||||
|  | { | ||||||
|  |     QString s; | ||||||
|  |     QTextStream os(&s); | ||||||
|  | 
 | ||||||
|  |     for (int i=0; i < length; i++) { | ||||||
|  |         os << a[i] << " "; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     qDebug("TestFT8Protocols::debugIntArray: %s", qPrintable(s)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user