mirror of
				https://github.com/brmlab/osmo-tetra.git
				synced 2025-10-30 23:14:00 +01:00 
			
		
		
		
	lower_mac/viterbi: Use the viterbi code provided in libosmocore
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
		
							parent
							
								
									24177bce48
								
							
						
					
					
						commit
						2d9b3e2560
					
				
					 2 changed files with 47 additions and 225 deletions
				
			
		|  | @ -20,24 +20,26 @@ | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| 
 | 
 | ||||||
|  | #include <osmocom/core/conv.h> | ||||||
|  | 
 | ||||||
| #include <lower_mac/viterbi_cch.h> | #include <lower_mac/viterbi_cch.h> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define CONV_CCH_N		4 | /*
 | ||||||
| #define CONV_CCH_K		5 |  * G1 = 1 + D           + D4 | ||||||
| #define CONV_CCH_N_STATES	(1<<(CONV_CCH_K-1)) |  * G2 = 1     + D2 + D3 + D4 | ||||||
|  |  * G3 = 1 + D + D2      + D4 | ||||||
|  |  * G4 = 1 + D      + D3 + D4 | ||||||
|  |  */ | ||||||
| 
 | 
 | ||||||
| #define MAX_AE			0x00ffffff | static const uint8_t conv_cch_next_output[][2] = { | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static const uint8_t conv_cch_next_output[CONV_CCH_N_STATES][2] = { |  | ||||||
| 	{  0, 15 }, { 11,  4 }, {  6,  9 }, { 13,  2 }, | 	{  0, 15 }, { 11,  4 }, {  6,  9 }, { 13,  2 }, | ||||||
| 	{  5, 10 }, { 14,  1 }, {  3, 12 }, {  8,  7 }, | 	{  5, 10 }, { 14,  1 }, {  3, 12 }, {  8,  7 }, | ||||||
| 	{ 15,  0 }, {  4, 11 }, {  9,  6 }, {  2, 13 }, | 	{ 15,  0 }, {  4, 11 }, {  9,  6 }, {  2, 13 }, | ||||||
| 	{ 10,  5 }, {  1, 14 }, { 12,  3 }, {  7,  8 }, | 	{ 10,  5 }, {  1, 14 }, { 12,  3 }, {  7,  8 }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const uint8_t conv_cch_next_state[CONV_CCH_N_STATES][2] = { | static const uint8_t conv_cch_next_state[][2] = { | ||||||
| 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 }, | 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 }, | ||||||
| 	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 }, | 	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 }, | ||||||
| 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 }, | 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 }, | ||||||
|  | @ -45,119 +47,27 @@ static const uint8_t conv_cch_next_state[CONV_CCH_N_STATES][2] = { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| int conv_cch_encode(uint8_t *input, uint8_t *output, int n) | static const struct osmo_conv_code conv_cch = { | ||||||
| { | 	.N = 4, | ||||||
| 	uint8_t state; | 	.K = 5, | ||||||
| 	int i; | 	.next_output = conv_cch_next_output, | ||||||
|  | 	.next_state  = conv_cch_next_state, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| 	state = 0; |  | ||||||
| 
 |  | ||||||
| 	for (i=0; i<n; i++) { |  | ||||||
| 		int bit = input[i]; |  | ||||||
| 		uint8_t out = conv_cch_next_output[state][bit]; |  | ||||||
| 		state = conv_cch_next_state[state][bit]; |  | ||||||
| 
 |  | ||||||
| 		output[(i<<2)  ] = (out >> 3) & 1; |  | ||||||
| 		output[(i<<2)+1] = (out >> 2) & 1; |  | ||||||
| 		output[(i<<2)+2] = (out >> 1) & 1; |  | ||||||
| 		output[(i<<2)+3] =  out       & 1; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| int conv_cch_decode(int8_t *input, uint8_t *output, int n) | int conv_cch_decode(int8_t *input, uint8_t *output, int n) | ||||||
| { | { | ||||||
| 	int i, s, b; | 	struct osmo_conv_decoder decoder; | ||||||
| 	unsigned int ae[CONV_CCH_N_STATES]; | 	int rv, l; | ||||||
| 	unsigned int ae_next[CONV_CCH_N_STATES]; |  | ||||||
| 	int8_t in_sym[CONV_CCH_N]; |  | ||||||
| 	int8_t ev_sym[CONV_CCH_N]; |  | ||||||
| 	int state_history[CONV_CCH_N_STATES][n]; |  | ||||||
| 	int min_ae; |  | ||||||
| 	int min_state; |  | ||||||
| 	int cur_state; |  | ||||||
| 
 | 
 | ||||||
| 	/* Initial error (only state 0 is valid) */ | 	osmo_conv_decode_init(&decoder, &conv_cch, n); | ||||||
| 	ae[0] = 0; |  | ||||||
| 	for (i=1; i<CONV_CCH_N_STATES; i++) { |  | ||||||
| 		ae[i] = MAX_AE; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* Scan the treillis */ | 	l = osmo_conv_decode_scan(&decoder, input, n); | ||||||
| 	for (i=0; i<n; i++) { | 	l = osmo_conv_decode_finish(&decoder, &input[l]); | ||||||
| 		/* Reset next accumulated error */ |  | ||||||
| 		for (s=0; s<CONV_CCH_N_STATES; s++) { |  | ||||||
| 			ae_next[s] = MAX_AE; |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		/* Get input */ | 	rv = osmo_conv_decode_get_output(&decoder, output, 1); | ||||||
| 		in_sym[0] = input[(i<<2)  ]; |  | ||||||
| 		in_sym[1] = input[(i<<2)+1]; |  | ||||||
| 		in_sym[2] = input[(i<<2)+2]; |  | ||||||
| 		in_sym[3] = input[(i<<2)+3]; |  | ||||||
| 
 | 
 | ||||||
| 		/* Scan all states */ | 	osmo_conv_decode_deinit(&decoder); | ||||||
| 		for (s=0; s<CONV_CCH_N_STATES; s++) |  | ||||||
| 		{ |  | ||||||
| 			/* Scan possible input bits */ |  | ||||||
| 			for (b=0; b<2; b++) |  | ||||||
| 			{ |  | ||||||
| 				int nae; |  | ||||||
| 
 | 
 | ||||||
| 				/* Next output and state */ | 	return rv; | ||||||
| 				uint8_t out   = conv_cch_next_output[s][b]; |  | ||||||
| 				uint8_t state = conv_cch_next_state[s][b]; |  | ||||||
| 
 |  | ||||||
| 				/* Expand */ |  | ||||||
| 				ev_sym[0] = (out >> 3) & 1 ? -127 : 127; |  | ||||||
| 				ev_sym[1] = (out >> 2) & 1 ? -127 : 127; |  | ||||||
| 				ev_sym[2] = (out >> 1) & 1 ? -127 : 127; |  | ||||||
| 				ev_sym[3] =  out       & 1 ? -127 : 127; |  | ||||||
| 
 |  | ||||||
| 				/* New error for this path */ |  | ||||||
| 				#define DIFF(x,y) (((x-y)*(x-y)) >> 9) |  | ||||||
| 				nae = ae[s] + \ |  | ||||||
| 					DIFF(ev_sym[0], in_sym[0]) + \ |  | ||||||
| 					DIFF(ev_sym[1], in_sym[1]) + \ |  | ||||||
| 					DIFF(ev_sym[2], in_sym[2]) + \ |  | ||||||
| 					DIFF(ev_sym[3], in_sym[3]); |  | ||||||
| 
 |  | ||||||
| 				/* Is it survivor */ |  | ||||||
| 				if (ae_next[state] > nae) { |  | ||||||
| 					ae_next[state] = nae; |  | ||||||
| 					state_history[state][i+1] = s; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* Copy accumulated error */ |  | ||||||
| 		memcpy(ae, ae_next, sizeof(int) * CONV_CCH_N_STATES); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Find state with least error */ |  | ||||||
| 	min_ae = MAX_AE; |  | ||||||
| 	min_state = -1; |  | ||||||
| 
 |  | ||||||
| 	for (s=0; s<CONV_CCH_N_STATES; s++) |  | ||||||
| 	{ |  | ||||||
| 		if (ae[s] < min_ae) { |  | ||||||
| 			min_ae = ae[s]; |  | ||||||
| 			min_state = s; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Traceback */ |  | ||||||
| 	cur_state = min_state; |  | ||||||
| 	for (i=n-1; i >= 0; i--) |  | ||||||
| 	{ |  | ||||||
| 		min_state = cur_state; |  | ||||||
| 		cur_state = state_history[cur_state][i+1]; |  | ||||||
| 		if (conv_cch_next_state[cur_state][0] == min_state) |  | ||||||
| 			output[i] = 0; |  | ||||||
| 		else |  | ||||||
| 			output[i] = 1; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,140 +20,52 @@ | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| 
 | 
 | ||||||
|  | #include <osmocom/core/conv.h> | ||||||
|  | 
 | ||||||
| #include <lower_mac/viterbi_tch.h> | #include <lower_mac/viterbi_tch.h> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define CONV_TCH_N		3 | /*
 | ||||||
| #define CONV_TCH_K		5 |  * G1 = 1 + D + D2 + D3 + D4 | ||||||
| #define CONV_TCH_N_STATES	(1<<(CONV_TCH_K-1)) |  * G2 = 1 + D      + D3 + D4 | ||||||
|  |  * G3 = 1     + D2      + D4 | ||||||
|  |  */ | ||||||
| 
 | 
 | ||||||
| #define MAX_AE			0x00ffffff | static const uint8_t conv_tch_next_output[][2] = { | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static const uint8_t conv_tch_next_output[CONV_TCH_N_STATES][2] = { |  | ||||||
| 	{ 0, 7 }, { 6, 1 }, { 5, 2 }, { 3, 4 },  | 	{ 0, 7 }, { 6, 1 }, { 5, 2 }, { 3, 4 },  | ||||||
| 	{ 6, 1 }, { 0, 7 }, { 3, 4 }, { 5, 2 },  | 	{ 6, 1 }, { 0, 7 }, { 3, 4 }, { 5, 2 },  | ||||||
| 	{ 7, 0 }, { 1, 6 }, { 2, 5 }, { 4, 3 },  | 	{ 7, 0 }, { 1, 6 }, { 2, 5 }, { 4, 3 },  | ||||||
| 	{ 1, 6 }, { 7, 0 }, { 4, 3 }, { 2, 5 },  | 	{ 1, 6 }, { 7, 0 }, { 4, 3 }, { 2, 5 },  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const uint8_t conv_tch_next_state[CONV_TCH_N_STATES][2] = { | static const uint8_t conv_tch_next_state[][2] = { | ||||||
| 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },  | 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },  | ||||||
| 	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },  | 	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },  | ||||||
| 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },  | 	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },  | ||||||
| 	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },  | 	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static const struct osmo_conv_code conv_tch = { | ||||||
|  | 	.N = 4, | ||||||
|  | 	.K = 5, | ||||||
|  | 	.next_output = conv_tch_next_output, | ||||||
|  | 	.next_state  = conv_tch_next_state, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| int conv_tch_encode(uint8_t *input, uint8_t *output, int n) |  | ||||||
| { |  | ||||||
| 	uint8_t state; |  | ||||||
| 	int i; |  | ||||||
| 
 |  | ||||||
| 	state = 0; |  | ||||||
| 
 |  | ||||||
| 	for (i=0; i<n; i++) { |  | ||||||
| 		int bit = input[i]; |  | ||||||
| 		uint8_t out = conv_tch_next_output[state][bit]; |  | ||||||
| 		state = conv_tch_next_state[state][bit]; |  | ||||||
| 
 |  | ||||||
| 		output[(i<<2)  ] = (out >> 2) & 1; |  | ||||||
| 		output[(i<<2)+1] = (out >> 1) & 1; |  | ||||||
| 		output[(i<<2)+2] =  out       & 1; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| int conv_tch_decode(int8_t *input, uint8_t *output, int n) | int conv_tch_decode(int8_t *input, uint8_t *output, int n) | ||||||
| { | { | ||||||
| 	int i, s, b; | 	struct osmo_conv_decoder decoder; | ||||||
| 	unsigned int ae[CONV_TCH_N_STATES]; | 	int rv, l; | ||||||
| 	unsigned int ae_next[CONV_TCH_N_STATES]; |  | ||||||
| 	int8_t in_sym[CONV_TCH_N]; |  | ||||||
| 	int8_t ev_sym[CONV_TCH_N]; |  | ||||||
| 	int state_history[CONV_TCH_N_STATES][n]; |  | ||||||
| 	int min_ae; |  | ||||||
| 	int min_state; |  | ||||||
| 	int cur_state; |  | ||||||
| 
 | 
 | ||||||
| 	/* Initial error (only state 0 is valid) */ | 	osmo_conv_decode_init(&decoder, &conv_tch, n); | ||||||
| 	ae[0] = 0; |  | ||||||
| 	for (i=1; i<CONV_TCH_N_STATES; i++) { |  | ||||||
| 		ae[i] = MAX_AE; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* Scan the treillis */ | 	l = osmo_conv_decode_scan(&decoder, input, n); | ||||||
| 	for (i=0; i<n; i++) { | 	l = osmo_conv_decode_finish(&decoder, &input[l]); | ||||||
| 		/* Reset next accumulated error */ |  | ||||||
| 		for (s=0; s<CONV_TCH_N_STATES; s++) { |  | ||||||
| 			ae_next[s] = MAX_AE; |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		/* Get input */ | 	rv = osmo_conv_decode_get_output(&decoder, output, 1); | ||||||
| 		in_sym[0] = input[(i<<2)  ]; |  | ||||||
| 		in_sym[1] = input[(i<<2)+1]; |  | ||||||
| 		in_sym[2] = input[(i<<2)+2]; |  | ||||||
| 
 | 
 | ||||||
| 		/* Scan all states */ | 	osmo_conv_decode_deinit(&decoder); | ||||||
| 		for (s=0; s<CONV_TCH_N_STATES; s++) |  | ||||||
| 		{ |  | ||||||
| 			/* Scan possible input bits */ |  | ||||||
| 			for (b=0; b<2; b++) |  | ||||||
| 			{ |  | ||||||
| 				int nae; |  | ||||||
| 
 | 
 | ||||||
| 				/* Next output and state */ | 	return rv; | ||||||
| 				uint8_t out   = conv_tch_next_output[s][b]; |  | ||||||
| 				uint8_t state = conv_tch_next_state[s][b]; |  | ||||||
| 
 |  | ||||||
| 				/* Expand */ |  | ||||||
| 				ev_sym[0] = (out >> 2) & 1 ? -127 : 127; |  | ||||||
| 				ev_sym[1] = (out >> 1) & 1 ? -127 : 127; |  | ||||||
| 				ev_sym[2] =  out       & 1 ? -127 : 127; |  | ||||||
| 
 |  | ||||||
| 				/* New error for this path */ |  | ||||||
| 				#define DIFF(x,y) (((x-y)*(x-y)) >> 9) |  | ||||||
| 				nae = ae[s] + \ |  | ||||||
| 					DIFF(ev_sym[0], in_sym[0]) + \ |  | ||||||
| 					DIFF(ev_sym[1], in_sym[1]) + \ |  | ||||||
| 					DIFF(ev_sym[2], in_sym[2]); |  | ||||||
| 
 |  | ||||||
| 				/* Is it survivor */ |  | ||||||
| 				if (ae_next[state] > nae) { |  | ||||||
| 					ae_next[state] = nae; |  | ||||||
| 					state_history[state][i+1] = s; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* Copy accumulated error */ |  | ||||||
| 		memcpy(ae, ae_next, sizeof(int) * CONV_TCH_N_STATES); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Find state with least error */ |  | ||||||
| 	min_ae = MAX_AE; |  | ||||||
| 	min_state = -1; |  | ||||||
| 
 |  | ||||||
| 	for (s=0; s<CONV_TCH_N_STATES; s++) |  | ||||||
| 	{ |  | ||||||
| 		if (ae[s] < min_ae) { |  | ||||||
| 			min_ae = ae[s]; |  | ||||||
| 			min_state = s; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Traceback */ |  | ||||||
| 	cur_state = min_state; |  | ||||||
| 	for (i=n-1; i >= 0; i--) |  | ||||||
| 	{ |  | ||||||
| 		min_state = cur_state; |  | ||||||
| 		cur_state = state_history[cur_state][i+1]; |  | ||||||
| 		if (conv_tch_next_state[cur_state][0] == min_state) |  | ||||||
| 			output[i] = 0; |  | ||||||
| 		else |  | ||||||
| 			output[i] = 1; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sylvain Munaut
						Sylvain Munaut