이동 평균 필터란?

->지정된 n개의 데이터만 가지고 평균을 구하는 방식

->새로운 데이터가 들어오면 가장 오래된 데이터는 버리고 n개로 평균을 구하는 방식

 

이번에도 굳이 구조체를 만들 필요는 없지만 구조체로 만들어보았다. 

만약 평균을 구할 데이터의 갯수 n이 정해져 있지 않고 사용자가 마음대로 초기화 할 수 있다고 가정하여, 

n이 정해지면 해당 갯수만큼 데이터를 담을 배열은 malloc을 사용하였다. 

#include <stdio.h>
#include <stdlib.h>
typedef struct 
{
    int cnt;
    int num;
    int *data;
    float preAvg;
    float nowAvg;
    int idx;
}mvAvg;

int init_mvAvgFilter(mvAvg *mvAvg, int num){
    mvAvg->cnt=0;
    mvAvg->num=num;
    mvAvg->data =(int*)malloc(sizeof(int)*num);
    mvAvg->preAvg=0;
    mvAvg->idx=0;
}

float mvAvgFilter(mvAvg *mvAvg,int data){
    if (mvAvg->cnt < mvAvg->num){
        mvAvg->data[mvAvg->cnt]=data;
        mvAvg->cnt++;
        
        int i=0;
        int sum=0;
        for (i=0;i<mvAvg->cnt;i++){
            sum+=mvAvg->data[i];
        }
        mvAvg->nowAvg=(float)sum/mvAvg->cnt;
        mvAvg->preAvg=mvAvg->nowAvg;
        return mvAvg->nowAvg;
    }

    mvAvg->nowAvg=(data-mvAvg->data[mvAvg->idx])/mvAvg->num+mvAvg->preAvg;
    mvAvg->data[mvAvg->idx]=data;
    mvAvg->idx++;
    if(mvAvg->idx == mvAvg->num){
        mvAvg->idx=0;
    }
    mvAvg->preAvg=mvAvg->nowAvg;
    return mvAvg->nowAvg;
}

int main(){
    mvAvg mvAvg;
    init_mvAvgFilter(&mvAvg,4);
    int i=0;
    for (i=1;i<=10;i++){
        printf("%d : %f\r\n",i,mvAvgFilter(&mvAvg,i));
    }
}

잘 되는 것 같은데.. 테스트가 부족하다.. 

 

반응형

'지식저장소 > C' 카테고리의 다른 글

[C] AverageFilter (평균 필터)  (0) 2022.04.28
[C] Ring Buffer / 링버퍼 구현  (0) 2022.03.29
[C/BOJ] 9012 괄호 - Stack이용  (0) 2022.02.16
[C]구조체를 이용한 Stack 구현  (0) 2022.02.16
[C/STM32] Uart로 printf 대신하기  (0) 2022.01.14

데이터들이 계속 들어올 때마다 평균을 갱신하는 AverageFilter 소스 

 

데이터의 수와 이전 평균만 전역 변수나 static 변수로 저장해도 되지만

구조체로 만들어보았다.

#include <stdio.h>

typedef struct 
{
    int dataCnt;
    float preAvg;
    float nowAvg;
}Avg;

float avgFilter(Avg *Avg,int data){
    if(Avg->dataCnt==0){
        Avg->dataCnt++;
        Avg->nowAvg=data;
        Avg->preAvg=data;
        return Avg->nowAvg;
    }
    Avg->preAvg=Avg->nowAvg;
    Avg->dataCnt++;
    Avg->nowAvg=(1 - (float)1/(Avg->dataCnt))*(Avg->preAvg)+((float)1/Avg->dataCnt)*data;
    return Avg->nowAvg;
}

int main(){
    Avg avg;
    avg.dataCnt = 0;
    avg.nowAvg = 0;
    avg.preAvg = 0;

    printf("%f\r\n", avgFilter(&avg,10));
    printf("%f\r\n", avgFilter(&avg,20));
    printf("%f\r\n", avgFilter(&avg,30));
    printf("%f\r\n", avgFilter(&avg,40));
    printf("%f\r\n", avgFilter(&avg,50));
    printf("%f\r\n", avgFilter(&avg,60));
    printf("%f %f\r\n",avg.preAvg,avg.nowAvg);
}

반응형

링 버퍼란? 

고정된 크기의 큐의 양 끝을 이어 원형 모양처럼 사용하는 버퍼

데이터를 넣었다가 빼는 역할을 할 수 있다 

 

구현은 다음과 같이 하였다.

 

ring_buffer.h

#include <stdint.h>
#include <string.h>

typedef struct{
	uint8_t *buffer;
	int front;
	int rear;
	int maxlen;
}ring_buffer_t;

void ring_buf_init(ring_buffer_t *rbuf, uint8_t *buffer, int size);
uint8_t ring_buf_push(ring_buffer_t *rbuf, uint8_t data);
uint8_t ring_buf_pop(ring_buffer_t *rubf, uint8_t *data);
uint8_t ring_buf_is_full(ring_buffer_t *rbuf);
uint8_t ring_buf_is_empty(ring_buffer_t *rbuf);
void ring_buf_clear(ring_buffer_t *rbuf);

ring_buffer_t는

사용할 버퍼를 담을 uint_t *buffer 와 큐를 사용하기 위한 fornt, rear와 사용할 버퍼의 크기를 maxlen으로 한다.  

 

ring_buffer.c

#include <stdint.h>
#include <string.h>

void ring_buf_init(ring_buffer_t *rbuf, uint8_t *buffer, int size){
	memset(rbuf, 0x00, sizeof(ring_buffer_t));
	rbuf->buffer=buffer;
	rbuf->maxlen=size;
}

uint8_t ring_buf_is_full(ring_buffer_t *rbuf){
	if(rbuf->rear == ( rbuf->front+1 ) % rbuf->maxlen) return 1;
	else return 0;
}
uint8_t ring_buf_is_empty(ring_buffer_t *rbuf){
	if( rbuf->rear == rbuf->front) return 1;
	else return 0;
}

uint8_t ring_buf_push(ring_buffer_t *rbuf, uint8_t data){
	if( ring_buf_is_full(rbuf) ) return 0;
	rbuf->buffer[rbuf->front] = data;
	rbuf->front = ( rbuf->front + 1) % rbuf->maxlen;
	return 1;

}
uint8_t ring_buf_pop(ring_buffer_t *rbuf, uint8_t *data){
	if( ring_buf_is_empty(rbuf) ) return 0;
	*data=rbuf->buffer[rbuf->rear];
	rbuf->rear = (rbuf->rear + 1) % rbuf->maxlen;
	return 1;
}

void ring_buf_clear(ring_buffer_t *rbuf){
	rbuf->front=0;
	rbuf->rear=0;
}

 

사용 예시

#include <stdio.h>
#include <stdint.h>
#include "ring_buffer.h"

int main(){
    uint8_t  i=0;
    uint8_t pop_data=0;
    ring_buffer_t ring_buffer;
    uint8_t rbuf[3];

    ring_buf_init(&ring_buffer, rbuf, 3);

    for(i=0;i<5;i++){
        if (ring_buf_push(&ring_buffer, i)){
             printf("push data : %d\r\n",i );
        }
    }

    for(i=0;i<5;i++){
        if (ring_buf_pop(&ring_buffer,&pop_data)){
            printf("pop %d \r\n", pop_data);
        }
    }
    return 0;
}

1. ring_buf_init(&ring_buffer, rbuf, 3);

    -> ring_buffer 구조체에 rbuf로 초기화 한다. 

2. 0~5를 ring buffer에 순차적으로 push 한다.

3.  ring_buffer의 데이터를 pop_data에 5번 pop한다. 

 

결과 

 

rbuf의 크기는 3인데 데이터는 2개를 넣은 후, 3개째에서 링 버퍼가 가득 찼다고 나온다. 

이는 링 버퍼의 경우,  empty와 full을 구분하기 위해 full의 경우 한 칸을 비워두기 때문이다.

 

나는 3개를 만들었으면 3개를 다 쓰고 싶다고 한다면 ring_buffer.h에서 ring_buffer_init 할 때 maxlen을 버퍼의 크기보다 1개 더 크게 해주면 된다. 

void ring_buf_init(ring_buffer_t* rbuf, uint8_t* buffer, uint16_t size){
    memset(rbuf,0x00,sizeof(ring_buffer_t));
    rbuf->buffer = buffer;
    rbuf->maxlen = size+1;
}

이렇게 고치고 똑같이 테스트를 하면

버퍼의 크기만큼 모두 이용할 수 있다. 

물론 테스트를 많이 안해봐서 오류가 있을 수도.....

 

반응형

만들었던 Stack 함수들을 이용하여 괄호 문제를 풀어보았다. 

Stack 함수 : https://pilimage.tistory.com/12

 

[C]구조체를 이용한 Stack 구현

Stack이란? : 데이터를 일시적으로 저장하는 방법 LIFO (Last In First Out, 후입선출)의 구조로나중에 들어온 데이터가 먼저 나가는 방식 배열을 크게 잡고 사용하여도 되지만 학습을 위하여 malloc을 사

pilimage.tistory.com

int main(){
    int num;
    int i,j;
    int err=0;

    scanf("%d",&num);
    char input[50];

    int *errList;
    errList=(int*)malloc(sizeof(int)*num);
    Stack s;
    
    for(i=0;i<num;i++){
        memset(input,0x00,sizeof(input));
        scanf("%s",input);
        initStack(&s,strlen(input));
        for(j=0;j<strlen(input);j++){
            if(input[j]=='('){
                pushStack(&s,input[j]);
            }else{
                if(popStack(&s)==0){
                    errList[i]=1;
                }
            }
        }
        if (!isEmptyStack(&s)){
            errList[i]=1;
        }
        DelStack(&s);
    }

    for(i=0;i<num;i++){
        if(errList[i]){
            printf("NO\n");
        }else{
            printf("YES\n");
        }
    }
    free(errList);
    return 0;
}

입력을 받아서 ' ( '를 만나면 스택에 push하고 ' ) '를 만나면 pop을 하도록하였다. 

' ) '을 만나서 pop을 할때, ' ( '와 ' ) '는 한 쌍이므로 ' ) '를 만났는데 스택에 ' ( '가 없어서 pop을 하지 못한다면 에러로 처리하였다. 

입력을 다 서치하고, 스택에 데이터인 ' ( '가 남아 있다면 에러로 처리하였다.

err flag과 errList를 이용하여 마지막에 결과를 출력하도록 하였다.

테스트 결과

 

반응형

Stack이란?

: 데이터를 일시적으로 저장하는 방법

LIFO (Last In First Out, 후입선출)의 구조로나중에 들어온 데이터가 먼저 나가는 방식

 

배열을 크게 잡고 사용하여도 되지만 학습을 위하여 malloc을 사용하였다. 

 

typedef struct 
{
    int size;
    int idx;
    int *data;
}Stack;

void DelStack(Stack *s){
    free(s->data);
}


int initStack(Stack *s, int size){
    s->size=size;
    s->idx=-1;
    s->data=(int*)malloc(sizeof(int)*(s->size));
    if(s->data!=NULL){
        return 1; 
    }else{
        s->size=0;
        return 0; 
    }   
}

구조체 Stack의 멤버 변수로는 스택의 크기 : size , 데이터 index : idx , 데이터 : *data 

initStack을 통해 스택 구조체를 초기화한다. 

idx는 -1로 초기화하고 malloc이 실패했을때 initStack이 0을 리턴하도록 한다. 

int isFullStack(Stack *s){
    if(s->idx>=s->size-1){
        return 1;
    }else{
        return 0;
    }
}
int isEmptyStack(Stack *s){
    if(s->idx==-1){
        return 1;
    }else{
        return 0;
    }
}

int pushStack(Stack *s, int data){
    if(isFullStack(s)){
        // printf("Stack is Full\r\n");
        return 0;
    }else{
        s->idx++;
        s->data[s->idx]=data;
        return 1;
    }
    return 0;
}
int popStack(Stack *s){
    int val=0;
    if(isEmptyStack(s)){
        // printf("stack is Empty");
        return val;
    }else{
        val=s->data[s->idx];
        s->idx--;
        return val;
    }    
}
 

isFullStack : 스택이 가득 찼는지 확인

 

isEmptyStack: 스택이 비었는지 확인 

 

pushStack : 스택에 데이터 삽입

-> 스택이 가득 차지 않았을 경우, 데이터 인덱스를 옮기고 데이터를 넣는다.

idx를 -1로 초기화 하였기 때문에 idx를 먼저 더해서 옮기고 데이터를 넣었다. 만약 idx를 0으로 초기화하였다면 데이터를 넣고 idx를 더해주면 된다. 

 

popStack : 스택에서 데이터 출력

->스택이 비어있지 않을 경우, 데이터를 출력하고 인덱스를 옮긴다. 

 

int SearchStack(Stack *s, int data){
    int i;
    for(i=0;i<s->idx;i++){
        if(data==s->data[i]){
            return i;
        }
    }
    return -1;
}

조금의 응용으로  SearchStack은 스택에 찾으려는 데이터가 있으면 해당 인덱스를 없으면 -1을 리턴하도록 만들어보았다. 

 

만든 함수를 아래와 같이 테스트하였다.

int main(){
    int i;
    Stack stack;
    initStack(&stack,10);
    pushStack(&stack,1);
    pushStack(&stack,2);
    pushStack(&stack,3);
    pushStack(&stack,4);
    pushStack(&stack,5);
    pushStack(&stack,6);
    pushStack(&stack,7);
    pushStack(&stack,8);
    pushStack(&stack,9);
    pushStack(&stack,10);

    pushStack(&stack,11);
    printf("search %d %d\r\n",SearchStack(&stack,7),SearchStack(&stack,-1));    

    for(i=0;i<13;i++){
        printf("% d idx:%d\r\n",popStack(&stack),stack.idx);

    }
    DelStack(&stack);
    return 0;

}

테스트 결과

1. 크기가 10인 사이즈를 만들고 11개의 데이터를 넣었다. - > Stack is Full 출력

2. 데이터가 7인 인덱스와 -1인 인덱스를 서치하였다 -> serach 6 -1 출력

3. 13개의 데이터를 출력하였다 -> 10 idx : 9~~ stack is Empty 0 idx : -1 출력 

 

반응형

디버깅 혹은 출력을 보기 위해 stm에서 printf가 필요할 때가 엄~~~청 많은 것 같다.

 

Uart가 있다면 HAL_UART_Transmit을 통해 아주 쉽게 printf와 비슷한 효과를 낼 수 있다. 

 

어떻게 ?

바로 그냥 문자열을 HAL_UART_Transmit을 이용하여 전송하면 된다. 

void print_str(char *str) {
	HAL_UART_Transmit(&huart1, str, strlen(str), 500);
}

int main(){
...

print_str("START\r\n")
...
}

 

만약 문자열이 아니라 변수의 값을 출력해보고 싶다면?

itoa 함수를 이용하면 출력할 수 있다. 

void print_val(char *strtemp, int val) {
	static char temp[128];
	char *ptr;
	ptr = temp;
	memset(temp, 0x00, 128);
	strcpy(temp, strtemp);
	ptr += strlen(temp);
	itoa(val, ptr, 10);
	HAL_UART_Transmit(&huart1, temp, strlen(temp), 500);
}

int main(){
...
a=10;
print_val("state : ",a);
...
}

간단한 출력할 때 유용하게 사용하는 중.. 

반응형

Hex로 된 데이터를 HexString으로, HexString을 Hex로 변환하는 경우가 종종 있었다. 

그럴때 마다 Hex convert to Hexstring ~~ 등등 구글링을 했었는데....

이번에 만든 걸로 쓸 곳에 쓰고 정리를 해보았다.

 

Hex 를 HexString으로 변환은 말그대로 Hex형태로 된 데이터를 HexString으로 변환하는 것이다.

쉽게 말하면 아래와 같다. 

 

Hex로 된 데이터가 있다. 

uint8_t hex[16]={0xA1,0xA2,0xA3,0xA4,0xB5,0xB6,0xB7,0xB8,0xC9,0xC0,0xCA,0xCB,0xDC,0xDD,0xDE,0xDF};

 

현재는 한 바이트당 hex로 표시된 것을 말 그대로 스트링형태로 바꾸는 것이다. 

예를 들어 0xA1의 경우 1바이트 Hex로 표시되어 있다.

이 때, A와 1을 문자형태로 만들어 0xA1이란 1바이트 Hex를 A1이란 2바이트의 문자열(0x41,0x31)로 만드는 것이다. 

 

반대로 HexString 은 A1이란 스트링을 보이는 그대로 0xA1이란 Hex로 만드는 것이다. 

 

설명이 애매한가....? 난 이해가 되니깐.. ㅎ 

 

먼저 Hex를 HexString으로 바꾸는 건 아래와 같다. 

int hex_convert_hexstring(uint8_t* data, uint8_t len, uint8_t* result){
	int i=0;
	int idx=0;
	for(i=0;i<len;i++){
		result[idx++]=(*(data+i))>>4 & 0x0f;
		result[idx++]=(*(data+i))& 0x0f;
	}

	for(i=0;i<idx;i++){
		if(result[i]>=10){
			result[i]=result[i]-10+'A';
		}else{
			result[i]=result[i]+'0';
		}
	}
    return idx;
}

data에는 변환할 Hex 데이터, len에는 data의 길이, result는 결과를 저장할 배열을 넣는다. 

변환된 후, result의 데이터 길이가 retrun된다. 

간단히 설명하자면..... 

Hex 값을 4비트씩 나누어서  result에 넣고, 문자열로 표현하기에 result에 넣은 값을 문자열 형태로 변환해주면 된다.

이 때, 10이 hex로 표현되면 A로 표현되므로 문자열로 변환하기 위해서 10이상의 값은 10을 빼주고 문자 'A'만큼 더해준다. 

이렇게 되면 10일 경우는 문자 'A', 11인경우 11-10+'A' 가 되므로 'A'+1 인 'B'가 된다. 

10보다 작을 때는 문자 '0'을 더해주어 0~9를 문자 형태로 변환한다. 

아스키 코드 표를 보면서 하면 더 쉽게 이해가 될 것이다. 

 

 

다음으로는 HexString에서 Hex로 변환하는 법이다. 

int hexstring_convert_hex(uint8_t* data,uint8_t len,uint8_t* result){
	int idx=0;
	int i=0;
	for (i=0;i<len;i++){
		if(*(data+i)>='A'){
			*(data+i)=*(data+i)-'A'+10;
		}else{
			*(data+i)=*(data+i)-'0';
		}
	}
	i=0;
	for(idx=0;idx<len/2;idx++){
		result[idx]=*(data+i++)<<4  | *(data+i++) & 0x0f;
	}
    return idx;
}

data에 hexstring을 넣고, len에 hexstirng의 길이를 넣고, result에 hex결과를 저장할 배열을 넣는다. 

변환된 후, hex데이터의 길이가 return 된다.

아까와는 반대로 hexString의 문자를 hex로 만들고, 2바이트씩 합쳐준다. 

 

실행 예시는 다음과 같다. 

int main(){
    int i=0;
    int string_len=0;
    int hex_len=0;
    uint8_t hex[16]={0xA1,0xA2,0xA3,0xA4,0xB5,0xB6,0xB7,0xB8,0xC9,0xC0,0xCA,0xCB,0xDC,0xDD,0xDE,0xDF};
    uint8_t hex_string[64];
    uint8_t hex_result[64];

    string_len=hex_convert_hexstring(hex,sizeof(hex),hex_string);

    for(i=0;i<string_len;i++){
        printf("%C ",hex_string[i]);
    }
    printf("\r\n");
    printf("%s\r\n",hex_string); //A1A2A3A4B5B6B7B8C9C0CACBDCDDDEDF

    hex_len=hexstring_convert_hex(hex_string,string_len,hex_result);
    
    for(i=0;i<hex_len;i++){
        printf("%02X ",hex_result[i]); //A1 A2 A3 A4 B5 B6 B7 B8 C9 C0 CA CB DC DD DE DF
    }
    printf("\r\n");
    return 0;

}

주석처리가 실제 프린트된 내용인데 잘 변환된 것 같다.

 

끝 !

반응형

'지식저장소 > C' 카테고리의 다른 글

[C] Ring Buffer / 링버퍼 구현  (0) 2022.03.29
[C/BOJ] 9012 괄호 - Stack이용  (0) 2022.02.16
[C]구조체를 이용한 Stack 구현  (0) 2022.02.16
[C/STM32] Uart로 printf 대신하기  (0) 2022.01.14
[C] ARIA 128 암호화  (2) 2021.09.03

KISA에서 제공하는 ARIA 암호화 예제를 이용한 간단한 암호화를 해보았다. 

 

16바이트로 딱 떨어지지 않는 데이터라도 제로 패딩을 하고 암호화를 하도록 기존의 함수를 조합한 정도뿐이지만...

개인적으로 함수 하나만 넣으면 결과를 얻을 수 있어 사용하기 편하게 만들었다.

 

기존 EncKeySetup 함수와 DeckeySetup 함수를 그대로 이용하였고 단순히 128비트 암호화를 사용하기 쉽게 함수만 2개 추가하였다 

 

사용한 master_key는 단순히 16 바이트로 단순히 1~16까지 넣었다. 

추가한 함수는 EnCrypt와 DeCrypt 이다. 

EnCrypt는 다음과 같다. 

암호화할 데이터와 결과를 얻을 버퍼, 평문의 길이를 넣으면 암호화된 결과의 길이가 리턴된다. 

 

DeCrypt는 다음과 같다. 

복호화 할 데이터와 결과를 얻을 버퍼, 복호화할 데이터의 길이를 넣으면 복호화 된 길이가 리턴된다.

 

해당 두 함수를 이용하여 ARIA128_test 함수를 만들었다

실행결과는 다음과 같다.

암호화를 하고 복호화를 해도 원래 데이터가 잘 나오는 것을 확인하였지만... 

검색을 통해 알아낸 ARIA 암. 복호화 모듈로 검증을 해보았다. 

 

EnCrypt
Decrypt

암.복호화 모두 일치하는 것을 확인을 했다.

 

더 많은 테스트가 필요하겠지만.. 일단은 성공...?

반응형

+ Recent posts