티스토리 뷰

심화

random 함수

Just4Fun 2016. 6. 12. 10:31

임베디드 프로젝트를 진행하다 보면 가끔 난수(random number)를 발생 시킬 필요가 생긴다.  이를 위하여 C언어에서는 rand() 함수를 사용하여 난수를 발생 시킨다.  rand() 함수를 부를때 마다 임의의 결과값을 받을 수 있는 것이다.  그러나 엄밀히 말해서 C에서 제공하는 rand()함수는 완전한 random값을 생성하지는 않는다.  이말이 무슨 뜻인지는 다음과 같은 코드를 작성하여 확인할 수 있다.


위의 코드를 실행 시키면 다음과 같은 결과를 볼 수 있다.

다섯번의 rand() 함수를 불러서 각기 다른 결과를 생성 시키는 것을 볼 수 있다.  그러나 문제는 보드를 다시 시작했을때 앞의 결과와 동일한 난수를 똑같이 발생 시킨다는 것이다.

보드를 계속 재시동 했을때 다음과 같이 동일한 패턴의 난수가 반복되는 것을 확인할 수 있다.


왜 이런 결과가 나오게 되는지는 rand() 함수의 소스를 보면 쉽게 이해할 수 있다.  AVR에서 사용되는 rand() 함수의 소스코드는 다음과 같다.

소스를 보면 알겠지만 rand() 함수 내에서 do_rand()라는 내부 함수를 호출하는데 이때, 26번줄에서 선언된 next라는 변수의 포인터값을 넘겨준다.  do_rand() 에서는 함수내 주석문에 설명된 알고리듬을 이용하여 next값을 이용하여 새로운 값을 계산하고, 그 결과를 다시 next에 업데이트 한다.(23번줄)

rand() 함수를 다시 호출하면 이전에 업데이트된 next의 값에 따라 새로운 random값을 생성하고 이 값을 다시 next에 기록해 두는 것이다.

문제는 최초로 사용되는 next값이 항상 1부터 시작되도록 소스코드가 작성되어 있으므로 늘 동일한 패턴의 random값이 만들어 질 수 밖에 없는 구조가 된다.

이러한 문제점을 해결하기 위하여 35번줄과 같은 srand()라는 함수를 제공한다.  srand()는 인자로 들어오는 seed값을 next에 넣어주도록 하는 동작을 한다.

이후에 불리워지는 rand()는 srand()로 들어온 seed값을 이용하여 새로운 난수를 발생하게 되므로, seed값을 임의의 값으로 변경하게 되면 앞에서 문제가 되었던 동일한 패턴의 난수 발생을 해결할 수 있게 되는 것이다.


그런데 새로운 문제가 또 생기게 된다.  srand()의 seed값은 또 어떻게 random하게 넣어 줄수 있을까?

일반적인 컴퓨터에서는 srand(time(NULL)); 과 같이 현재 시간값을 OS로부터 받아서 seed값으로 넘겨 주는 방법을 사용한다.  이렇게 되면 시간의 경과에 따라 항상 다른 seed값을 넣어 줄 수 있으므로 더 이상 동일한 패턴의 난수가 발생하는 문제점은 나타나지 않게 된다.


그러나 AVR과 같은 임베디드 시스템에서와 같이 RTC가 없는 경우 현재 시간을 제공 받을 수 없기 때문에 다른 방법을 찾아야 한다.

AVR에서 사용가능한 방법은 ADC를 이용하는 것이다.  광센서나 온도 센서등과 같이 환경에 따라 수시로 변하는 센서값을 받아서 그 값을 seed값으로 사용하면 된다.  그러나 이를 위해서는 어쩔수 없이 추가적인 회로를 구성하여야 한다.

추가회로 구성없이 하드웨어로부터 불규칙한 데이터를 얻어오는 방법이 없을까?


다행히도 AVR(ATmega328)의 ADC안에 온도센서가 포함되어 있으므로 이것을 이용하면 매번 다른seed값을 제공할수 있을것 같다.  따라서 AVR내부 온도센서 값을 읽어오는 방법을 설명하도록 하겠다.  내부 온도센서가 제공되지 않는 CPU는 어쩔수 없이 센서회로를 추가하거나, RTC를 추가하여야 한다.


AVR datasheet에서 ADC 설명 부분을 보면 위와 같은 내용을 볼 수 있다.  ADC mux의 ADC8이 내부 온도 센서와 연결되어 있고, 이를 이용하려면 ADC의 기준 전압 선택을 1.1V로 하여야 된다고 설명하고 있다.


입문 과정중 ADC(Analog to Digital Converter)를 참조하여 다음과 같이 코드를 수정한다.



23번줄을 보면 adc_read()의 결과를 srand()의 입력 인자로 직접 전달하는 것을 알수 있다.  adc_read()의 결과물은 AVR 내부의 온도센서로 부터 읽어온 현재 온도값이므로, AVR이 시작되는 시점의 온도가 변하면 AVR이 시작될 때마다 다른 온도값으로 srand()의 seed값을 줄 수 있게 된다.


위의 코드를 이용하여 AVR이 시작될 때마다 다른 random 값을 생성하는 것을 다음과 같은 결과로 확인할 수 있다.


동일한 프로그램이 새로 시작될때마다 각기 다른 난수가 발생되는것을 볼 수 있다.


main.c


심화 과정 목차

'심화' 카테고리의 다른 글

패킷 통신 - Serial Packet Communication  (0) 2016.07.30
포인터(Pointer) - 개념  (0) 2016.07.02
EABI(Embedded Application Binary Interface)  (0) 2016.04.23
엔디안(Endian)  (0) 2016.04.23
변수는 여기에!  (6) 2016.04.23
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함