본문 바로가기

C언어

컨볼루션 인코더 & 비터비 디코더 ver 0.5

정확하지 않은 코드일 수 있으니 참고용으로 보시기 바랍니다~

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define SIGNAL_COUNT 100000

double gaussian();
double uniform();

// main 함수 ----------------------------------------

int main(void)
{
	// 반복문용 변수들
	int i, i1, diff;
	int j;
	int k, m;

	int l;
	int posi;

	int check1 = 1;
	int check2;

	int error_count; // 에러체크
	double ber[11]; // BER

	int con_length;
	int decision;

	double EbN0, noise_pow;

	int* s_d_signal;
	int* con_out;
	double* s_a_signal;

	double* r_a_signal;
	int* pre_recon;

	int* check_code;
	int* check_result;

	int* route;
	int* route_sum_main;
	int* route_sum_sub;
	int route_sum_small;

	int last;
	int pos;
	int* r_d_signal;

	int state; // 에러확인 변수

	FILE * file = fopen("output.txt", "wt");
	if (file == NULL){
		printf("파일 열기가 실패하였습니다.\n");
		return 1;
	}

	printf("Constraint Length를 입력하세요.(3,5,7,9 중에서) : ");
	scanf("%d", &con_length);

	printf("신호결정 방식을 입력하세요.(1.hard/2.soft) : ");
	scanf("%d", &decision);

	// 부호처리용 수치 얻기
	for (i = 0; i< con_length; i++){
		check1 = check1 * 2;
	}

	// sender의 digital 신호 메모리 공간 할당
	s_d_signal = (int *)calloc(SIGNAL_COUNT + ((con_length - 1) * 2), sizeof(int));

	// 부호화한 값을 담을 공간 할당
	con_out = (int *)calloc((SIGNAL_COUNT + (con_length - 1)) * 2, sizeof(int));

	// sender의 analog 신호 메모리 공간 할당
	s_a_signal = (double *)calloc((SIGNAL_COUNT + (con_length - 1)) * 2, sizeof(double));

	// sender의 analog 신호 메모리 공간 할당
	s_a_signal = (double *)calloc((SIGNAL_COUNT + (con_length - 1)) * 2, sizeof(double));

	// receiver의 analog 신호 메모리 공간 할당
	r_a_signal = (double *)calloc((SIGNAL_COUNT + (con_length - 1)) * 2, sizeof(double));

	// receiver의 digital 신호 메모리 공간 할당
	pre_recon = (int *)calloc((SIGNAL_COUNT + (con_length - 1)) * 2, sizeof(int));

	// 부호확인용 비트열 메모리 공간 할당
	check_code = (int *)calloc(con_length, sizeof(int));

	// 얻어낸 부호값 저장 메모리 공간 할당
	check_result = (int *)calloc(check1 * 2, sizeof(int));

	// 경로 저장공간할당
	route = (int *)calloc(((SIGNAL_COUNT + (con_length - 1))*(check1 / 2)), sizeof(int));

	// 거리합 저장공간할당
	route_sum_main = (int *)calloc((check1 / 2), sizeof(int));
	route_sum_sub = (int *)calloc((check1 / 2), sizeof(int));

	// 최종수신비트 저장공간 할당
	r_d_signal = (int *)calloc(SIGNAL_COUNT + ((con_length - 1) * 2), sizeof(int));

	for (j = 0; j< 11; j++){
		EbN0 = pow(10.0, (double)j / 10.0);
		noise_pow = sqrt(1.0 / (2.0*EbN0));

		// seed 값을 시간 함수로 처리
		srand((int)time(NULL));

		// 0과 1의 디지털 신호를 랜덤으로 생성
		for (i = (con_length - 1); i< SIGNAL_COUNT + (con_length - 1); i++){
			s_d_signal[i] = rand() % 2;
		}

		for (k = 0; k< SIGNAL_COUNT + (con_length - 1); k++){

			switch (con_length)
			{
			case 3:
				con_out[(k * 2)] = (s_d_signal[k] + s_d_signal[k + 1] + s_d_signal[k + 2]) % 2;
				con_out[(k * 2) + 1] = (s_d_signal[k] + s_d_signal[k + 2]) % 2;
				break;
			case 5:
				con_out[(k * 2)] = (s_d_signal[k] + s_d_signal[k + 2] + s_d_signal[k + 3] + s_d_signal[k + 4]) % 2;
				con_out[(k * 2) + 1] = (s_d_signal[k] + s_d_signal[k + 1] + s_d_signal[k + 4]) % 2;
				break;
			case 7:
				con_out[(k * 2)] = (s_d_signal[k] + s_d_signal[k + 3] + s_d_signal[k + 4] + s_d_signal[k + 5] + s_d_signal[k + 6]) % 2;
				con_out[(k * 2) + 1] = (s_d_signal[k] + s_d_signal[k + 1] + s_d_signal[k + 3] + s_d_signal[k + 4] + s_d_signal[k + 6]) % 2;
				break;
			case 9:
				con_out[(k * 2)] = (s_d_signal[k] + s_d_signal[k + 1] + s_d_signal[k + 3] + s_d_signal[k + 5] + s_d_signal[k + 6] + s_d_signal[k + 7] + s_d_signal[k + 8]) % 2;
				con_out[(k * 2) + 1] = (s_d_signal[k] + s_d_signal[k + 4] + s_d_signal[k + 5] + s_d_signal[k + 6] + s_d_signal[k + 8]) % 2;
				break;
			}
		}

		// 0은 -1로, 1은 1로 mapping
		for (i = 0; i< (SIGNAL_COUNT + (con_length - 1)) * 2; i++){
			if (con_out[i] == 0){
				s_a_signal[i] = -1.0;
			}
			else{
				s_a_signal[i] = 1.0;
			}
		}

		// 가우시안 통과
		for (i = 0; i< (SIGNAL_COUNT + (con_length - 1)) * 2; i++){
			r_a_signal[i] = s_a_signal[i] + (gaussian()*noise_pow);
		}

		switch (decision)
		{
		case 1:
			// digital 신호 결정 (hard)
			for (i = 0; i< (SIGNAL_COUNT + (con_length - 1)) * 2; i++){
				if (r_a_signal[i] & gt; 0){ // s : 가우시간 무시, r : 가우시안 통과
					pre_recon[i] = 1;
				}
				else{
					pre_recon[i] = 0;
				}
			}
			break;
		case 2:
			// digital 신호 결정 (soft)
			for (i = 0; i< (SIGNAL_COUNT + (con_length - 1)) * 2; i++){
				if (r_a_signal[i] & gt; = 0.8571){ // s : 가우시간 무시, r : 가우시안 통과
					pre_recon[i] = 7;
				}
				else if ((r_a_signal[i] & lt; 0.8571) && (r_a_signal[i] & gt; = 0.5714)){
					pre_recon[i] = 6;
				}
				else if ((r_a_signal[i] & lt; 0.5714) && (r_a_signal[i] & gt; = 0.2857)){
					pre_recon[i] = 5;
				}
				else if ((r_a_signal[i] & lt; 0.2857) && (r_a_signal[i] & gt; = 0)){
					pre_recon[i] = 4;
				}
				else if ((r_a_signal[i] & lt; 0) && (r_a_signal[i] & gt; = -0.2857)){
					pre_recon[i] = 3;
				}
				else if ((r_a_signal[i] & lt; -0.2857) && (r_a_signal[i] & gt; = -0.5714)){
					pre_recon[i] = 2;
				}
				else if ((r_a_signal[i] & lt; -0.5714) && (r_a_signal[i] & gt; = -0.8571)){
					pre_recon[i] = 1;
				}
				else if (r_a_signal[i] & lt; -0.8571){
					pre_recon[i] = 0;
				}
			}
			break;
		}
		// 복호처리시작=================================================================

		// 비트열당 부호변환값 얻기
		switch (decision)
		{
		case 1:
			k = 0;

			for (i = 0; i< check1; i++){

				// 십진수 나열을 이진수형태로 변환
				check2 = i;
				posi = con_length - 1;
				for (l = 0; l< con_length; l++)
				{
					if (check2 > = 1){
						check_code[posi] = check2 % 2;
						check2 = check2 / 2;
					}
					else{
						check_code[posi] = 0;
					}
					posi = posi - 1;
				}

				switch (con_length)
				{
				case 3:
					check_result[(i * 2)] = (check_code[0] + check_code[1] + check_code[2]) % 2;
					check_result[(i * 2) + 1] = (check_code[0] + check_code[2]) % 2;
					break;
				case 5:
					check_result[(i * 2)] = (check_code[0] + check_code[2] + check_code[3] + check_code[4]) % 2;
					check_result[(i * 2) + 1] = (check_code[0] + check_code[1] + check_code[4]) % 2;
					break;
				case 7:
					check_result[(i * 2)] = (check_code[0] + check_code[3] + check_code[4] + check_code[5] + check_code[6]) % 2;
					check_result[(i * 2) + 1] = (check_code[0] + check_code[1] + check_code[3] + check_code[4] + check_code[6]) % 2;
					break;
				case 9:
					check_result[(i * 2)] = (check_code[0] + check_code[1] + check_code[3] + check_code[5] + check_code[6] + check_code[7] + check_code[8]) % 2;
					check_result[(i * 2) + 1] = (check_code[0] + check_code[4] + check_code[5] + check_code[6] + check_code[8]) % 2;
					break;
				}
			}
			break;
		case 2:
			k = 0;

			for (i = 0; i< check1; i++){

				// 십진수 나열을 이진수형태로 변환
				check2 = i;
				posi = con_length - 1;
				for (l = 0; l< con_length; l++)
				{
					if (check2 > = 1){
						check_code[posi] = check2 % 2;
						check2 = check2 / 2;
					}
					else{
						check_code[posi] = 0;
					}
					posi = posi - 1;
				}

				switch (con_length)
				{
				case 3:
					check_result[(i * 2)] = 7 * ((check_code[0] + check_code[1] + check_code[2]) % 2);
					check_result[(i * 2) + 1] = 7 * ((check_code[0] + check_code[2]) % 2);
					break;
				case 5:
					check_result[(i * 2)] = 7 * ((check_code[0] + check_code[2] + check_code[3] + check_code[4]) % 2);
					check_result[(i * 2) + 1] = 7 * ((check_code[0] + check_code[1] + check_code[4]) % 2);
					break;
				case 7:
					check_result[(i * 2)] = 7 * ((check_code[0] + check_code[3] + check_code[4] + check_code[5] + check_code[6]) % 2);
					check_result[(i * 2) + 1] = 7 * ((check_code[0] + check_code[1] + check_code[3] + check_code[4] + check_code[6]) % 2);
					break;
				case 9:
					check_result[(i * 2)] = 7 * ((check_code[0] + check_code[1] + check_code[3] + check_code[5] + check_code[6] + check_code[7] + check_code[8]) % 2);
					check_result[(i * 2) + 1] = 7 * ((check_code[0] + check_code[4] + check_code[5] + check_code[6] + check_code[8]) % 2);
					break;
				}
			}
			break;
		}
		//핵심부분 시작========================================================================

		//거리합 초기화
		for (m = 1; m< check1 / 2; m++){
			route_sum_main[m] = 255;
		}

		// 비교시작
		switch (decision)
		{
		case 1:
			for (i = 0; i< SIGNAL_COUNT + (con_length - 1); i++){

				// 거리차 처리하기 위해 옮겨놓음
				for (i1 = 0; i1< check1 / 2; i1++)
				{
					route_sum_sub[i1] = route_sum_main[i1];
				}

				for (i1 = 0; i1< check1 / 2; i1++){

					//차이처리
					diff = 0;
					if (pre_recon[i * 2] != check_result[i1 * 2]){
						diff++;
					}
					if (pre_recon[i * 2 + 1] != check_result[i1 * 2 + 1]){
						diff++;
					}

					//차이가 0일때
					if (diff == 0){
						route_sum_main[i1] = route_sum_sub[i1 / 2];
						route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = i1;
					}

					//차이가 1일때
					if (diff == 1){
						if (route_sum_sub[i1 / 2] & lt; = route_sum_sub[(i1 + check1 / 2) / 2]){
							route_sum_main[i1] = route_sum_sub[i1 / 2] + diff;
							route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = i1;
						}
						else{
							route_sum_main[i1] = route_sum_sub[(i1 + check1 / 2) / 2] + diff;
							route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = i1 + check1 / 2;
						}
					}

					//차이가 2일때
					if (diff == 2){
						route_sum_main[i1] = route_sum_sub[(i1 + check1 / 2) / 2];
						route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = i1 + check1 / 2;
					}
				}
			}
			break;
		case 2:
			for (i = 0; i< SIGNAL_COUNT + (con_length - 1); i++){

				// 거리차 처리하기 위해 옮겨놓음
				for (i1 = 0; i1< check1 / 2; i1++)
				{
					route_sum_sub[i1] = route_sum_main[i1];
				}

				for (i1 = 0; i1< check1 / 2; i1++){

					//차이처리
					if ((pre_recon[i * 2] - check_result[i1 * 2])*(pre_recon[i * 2] - check_result[i1 * 2])
						+ (pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1])
						< (pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])*(pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])
						+ (pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1]))
					{
						route_sum_main[i1] = route_sum_sub[i1 / 2]
							+ (pre_recon[i * 2] - check_result[i1 * 2])*(pre_recon[i * 2] - check_result[i1 * 2])
							+ (pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1]);
						route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = i1;
					}
					else if ((pre_recon[i * 2] - check_result[i1 * 2])*(pre_recon[i * 2] - check_result[i1 * 2])
						+ (pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1])
						> (pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])*(pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])
						+ (pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1]))
					{
						route_sum_main[i1] = route_sum_sub[(i1 + check1 / 2) / 2]
							+ (pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])*(pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])
							+ (pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1]);
						route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = (i1 + check1 / 2);
					}
					else
					{
						if (route_sum_sub[i1 / 2] & lt; = route_sum_sub[(i1 + check1 / 2) / 2])
						{
							route_sum_main[i1] = route_sum_sub[i1 / 2]
								+ (pre_recon[i * 2] - check_result[i1 * 2])*(pre_recon[i * 2] - check_result[i1 * 2])
								+ (pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[i1 * 2 + 1]);
							route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = i1;
						}
						else{
							route_sum_main[i1] = route_sum_sub[(i1 + check1 / 2) / 2]
								+ (pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])*(pre_recon[i * 2] - check_result[(i1 + check1 / 2) * 2])
								+ (pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1])*(pre_recon[i * 2 + 1] - check_result[(i1 + check1 / 2) * 2 + 1]);
							route[i1*(SIGNAL_COUNT + (con_length - 1)) + i] = i1 + check1 / 2;
						}
					}
				}
			}
			break;
		}
		//역 경로추적 및 비트결정

		last = SIGNAL_COUNT + 2 * (con_length - 1) - 1;

		route_sum_small = route_sum_main[0];

		pos = 0;

		for (i = 0; i< check1 / 2 - 1; i++){
			if (route_sum_main[i + 1] & lt; route_sum_small){
				route_sum_small = route_sum_main[i + 1];
				pos = i + 1;
			}
		}

		for (i = SIGNAL_COUNT + (con_length - 2); i > = 0; i--)
		{
			r_d_signal[last] = route[pos*(SIGNAL_COUNT + (con_length - 1)) + i] % 2;
			pos = route[pos*(SIGNAL_COUNT + (con_length - 1)) + i] / 2;
			last--;
		}

		//핵심부분 끝=======================================================================

		// BER 측정
		error_count = 0;

		for (i = (con_length - 1); i< SIGNAL_COUNT + (con_length - 1); i++){
			if (s_d_signal[i] != r_d_signal[i]){
				error_count++;
			}
		}

		ber[j] = (double)error_count / SIGNAL_COUNT;

		printf("BER : %f \n", ber[j]);
	}

	for (i = 0; i< 11; i++){
		if (i != 10){
			fprintf(file, "%f ", ber[i]);
		}
		else{
			fprintf(file, "%f", ber[i]);
		}
	}

	state = fclose(file);
	if (state != 0){
		printf("파일 닫기가 실패하였습니다.\n");
		return 1;
	}

	free(s_d_signal);
	free(s_a_signal);
	free(r_a_signal);
	free(pre_recon);
	free(check_code);
	free(check_result);
	free(route);
	free(route_sum_main);
	free(route_sum_sub);
	free(r_d_signal);
	free(con_out);

	return 0;
}

// gaussian 함수 ----------------------------------------

double gaussian()
{
	static int ready = 0;
	static double gstore;
	double v1, v2, r, fac, gaus;
	double uniform();
	if (ready == 0)
	{
		do {
			v1 = 2.*uniform();
			v2 = 2.*uniform();
			r = v1*v1 + v2*v2;
		} while (r > 1.0);
		fac = sqrt(-2.*log(r) / r);
		gstore = v1*fac;
		gaus = v2*fac;
		ready = 1;
	}
	else
	{
		ready = 0;
		gaus = gstore;
	}
	return(gaus);
}

// uniform 함수 ----------------------------------------

double uniform()
{
	return((double)(rand() & RAND_MAX) / RAND_MAX - 0.5);
}

'C언어' 카테고리의 다른 글

이중 포인터 간단정리  (0) 2014.10.23
2의 보수를 이용한 부호 바꾸기  (0) 2014.09.26
QPSK  (0) 2014.09.04
BPSK  (0) 2014.09.03
매크로(macro) #define  (0) 2014.08.21