반응형
fourier_transform

Fourier Transform

푸리에 변환

푸리에 변환은 연속적인 시계열 데이터를 sin, cos 함수들과 같은 파형들의 합으로 나타내는 것으로 여러 개의 주파수 성분들로 분해하는 작업이다.
주로 신호 처리나 사운드, 이미지와 같은 데이터의 주파수 변환에 많이 사용한다.
그렇다면 어떻게 분해를 할 수 있는 것일까?
여기서는 이론적인 이해가 아닌 프로그래밍 구현측면에서 접근하도록 한다.
drawingfft2
위 그림은 도형 이미지를 시간에 따른 x, y 좌표 리스트로 나누어 x, y 각각을 주파수 분해한 다음 분해된 주파수들을 하나씩 결합하여 그린 모양이다. 주파수를 하나씩 더 했을 때 점점 원본에 닮아가는 것을 확인할 수 있다.
노이즈가 섞인 원본 신호라면 주파수 분해 후 적절한 신호의 재결합을 통해 노이즈가 제거되는 효과도 나타날 수 있을 것이다.

도구

가장 쉽게 접근할 수 있는 것은 python의 numpy나 scipy 라이브러리로 쉽게 원하는 작업을 할 수 있다. cpp로 된 라이브러리도 google에서 검색하면 금방 찾을 수 있다.

해결하려는 문제

시계열 데이터를 주파수 성분으로 분해하고 분해된 수치 정보만으로 원본을 복구하는 작업을 수행하고자 한다.

알 수 없는 시그널

시간값과 신호크기만 있는 시계열 데이터가 있다고 하자.
fft02

'''  
foutier transform  
'''  
  
import numpy as np  
import matplotlib.pyplot as plt  
  
txlist = [(0.0, -0.1729957805907173), (0.0045871559633027525, -0.189873417721519), (0.009174311926605505, -0.2236286919831224), (0.013761467889908258, -0.2742616033755274), (0.01834862385321101, -0.3080168776371308), (0.022935779816513763, -0.3502109704641351), (0.027522935779816515, -0.4092827004219409), (0.03211009174311927, -0.4345991561181435), (0.03669724770642202, -0.47679324894514763), (0.04128440366972477, -0.510548523206751), (0.045871559633027525, -0.5527426160337553), (0.05045871559633028, -0.5864978902953586), (0.05504587155963303, -0.620253164556962), (0.05963302752293578, -0.6371308016877637), (0.06422018348623854, -0.6540084388185654), (0.06880733944954129, -0.6793248945147679), (0.07339449541284404, -0.6877637130801688), (0.0779816513761468, -0.6877637130801688), (0.08256880733944955, -0.6877637130801688), (0.0871559633027523, -0.6708860759493671), (0.09174311926605505, -0.6540084388185654), (0.0963302752293578, -0.6286919831223629), (0.10091743119266056, -0.5949367088607596), (0.10550458715596331, -0.5864978902953586), (0.11009174311926606, -0.5527426160337553), (0.11467889908256881, -0.5274261603375527), (0.11926605504587157, -0.5021097046413502), (0.12385321100917432, -0.4345991561181435), (0.12844036697247707, -0.4092827004219409), (0.13302752293577982, -0.3502109704641351), (0.13761467889908258, -0.24894514767932485), (0.14220183486238533, -0.11392405063291144), (0.14678899082568808, 0.029535864978903037), (0.15137614678899083, 0.03797468354430378), (0.1559633027522936, 0.139240506329114), (0.16055045871559634, 0.28270042194092837), (0.1651376146788991, 0.4430379746835442), (0.16972477064220184, 0.5021097046413503), (0.1743119266055046, 0.5527426160337552), (0.17889908256880735, 0.620253164556962), (0.1834862385321101, 0.6624472573839661), (0.18807339449541285, 0.6962025316455696), (0.1926605504587156, 0.729957805907173), (0.19724770642201836, 0.7805907172995781), (0.2018348623853211, 0.8227848101265822), (0.20642201834862386, 0.8481012658227849), (0.21100917431192662, 0.8481012658227849), (0.21559633027522937, 0.8312236286919832), (0.22018348623853212, 0.7974683544303798), (0.22477064220183487, 0.7890295358649788), (0.22935779816513763, 0.7721518987341771), (0.23394495412844038, 0.7552742616033756), (0.23853211009174313, 0.7215189873417722), (0.24311926605504589, 0.7046413502109705), (0.24770642201834864, 0.6877637130801688), (0.25229357798165136, 0.6540084388185654), (0.25688073394495414, 0.620253164556962), (0.26146788990825687, 0.5611814345991561), (0.26605504587155965, 0.4599156118143459), (0.2706422018348624, 0.36708860759493667), (0.27522935779816515, 0.31645569620253156), (0.2798165137614679, 0.24894514767932496), (0.28440366972477066, 0.1898734177215189), (0.2889908256880734, 0.11392405063291133), (0.29357798165137616, 0.09704641350210963), (0.2981651376146789, 0.029535864978903037), (0.30275229357798167, -0.04641350210970463), (0.3073394495412844, -0.18143459915611815), (0.3119266055045872, -0.24894514767932485), (0.3165137614678899, -0.19831223628691985), (0.3211009174311927, -0.13080168776371304), (0.3256880733944954, -0.06329113924050633), (0.3302752293577982, 0.012658227848101333), (0.3348623853211009, 0.08860759493670889), (0.3394495412844037, 0.139240506329114), (0.3440366972477064, 0.2067510548523206), (0.3486238532110092, 0.240506329113924), (0.3532110091743119, 0.2742616033755274), (0.3577981651376147, 0.31645569620253156), (0.3623853211009174, 0.33333333333333326), (0.3669724770642202, 0.35021097046413496), (0.37155963302752293, 0.3586497890295359), (0.3761467889908257, 0.39240506329113933), (0.38073394495412843, 0.40928270042194104), (0.3853211009174312, 0.4008438818565401), (0.38990825688073394, 0.2911392405063291), (0.3944954128440367, 0.23206751054852326), (0.39908256880733944, 0.1898734177215189), (0.4036697247706422, 0.14767932489451474), (0.40825688073394495, 0.08016877637130793), (0.41284403669724773, 0.021097046413502074), (0.41743119266055045, -0.08860759493670889), (0.42201834862385323, -0.16455696202531644), (0.42660550458715596, -0.24894514767932485), (0.43119266055045874, -0.3502109704641351), (0.43577981651376146, -0.4008438818565401), (0.44036697247706424, -0.49367088607594933), (0.44495412844036697, -0.5780590717299579), (0.44954128440366975, -0.6455696202531646), (0.4541284403669725, -0.6455696202531646), (0.45871559633027525, -0.4683544303797469), (0.463302752293578, -0.36708860759493667), (0.46788990825688076, -0.24894514767932485), (0.4724770642201835, -0.08860759493670889), (0.47706422018348627, 0.00421940928270037), (0.481651376146789, 0.13080168776371304), (0.48623853211009177, 0.2742616033755274), (0.4908256880733945, 0.38396624472573837), (0.4954128440366973, 0.4345991561181435), (0.5, 0.6118143459915613), (0.5045871559633027, 0.6793248945147679), (0.5091743119266054, 0.6877637130801688), (0.5137614678899083, 0.7805907172995781), (0.518348623853211, 0.7805907172995781), (0.5229357798165137, 0.6793248945147679), (0.5275229357798165, 0.5696202531645569), (0.5321100917431193, 0.5443037974683544), (0.536697247706422, 0.4599156118143459), (0.5412844036697247, 0.39240506329113933), (0.5458715596330275, 0.31645569620253156), (0.5504587155963303, 0.21518987341772156), (0.555045871559633, 0.1223628691983123), (0.5596330275229358, 0.06329113924050622), (0.5642201834862385, -0.021097046413502074), (0.5688073394495413, -0.08016877637130804), (0.573394495412844, -0.08860759493670889), (0.5779816513761468, -0.18143459915611815), (0.5825688073394495, -0.21518987341772156), (0.5871559633027523, -0.2573839662447257), (0.591743119266055, -0.24894514767932485), (0.5963302752293578, -0.2236286919831224), (0.6009174311926605, -0.21518987341772156), (0.6055045871559633, -0.2067510548523207), (0.6100917431192661, -0.189873417721519), (0.6146788990825688, -0.189873417721519), (0.6192660550458715, -0.18143459915611815), (0.6238532110091743, -0.18143459915611815), (0.6284403669724771, -0.18143459915611815), (0.6330275229357798, -0.18143459915611815), (0.6376146788990825, -0.18143459915611815), (0.6422018348623854, -0.18143459915611815), (0.6467889908256881, -0.2067510548523207), (0.6513761467889908, -0.21518987341772156), (0.6559633027522935, -0.21518987341772156), (0.6605504587155964, -0.2236286919831224), (0.6651376146788991, -0.2236286919831224), (0.6697247706422018, -0.2236286919831224), (0.6743119266055045, -0.2236286919831224), (0.6788990825688074, -0.21518987341772156), (0.6834862385321101, -0.21518987341772156), (0.6880733944954128, -0.2236286919831224), (0.6926605504587156, -0.36708860759493667), (0.6972477064220184, -0.5021097046413502), (0.7018348623853211, -0.6286919831223629), (0.7064220183486238, -0.7383966244725738), (0.7110091743119266, -0.8396624472573839), (0.7155963302752294, -0.9409282700421941), (0.7201834862385321, -1.0), (0.7247706422018348, -0.9915611814345991), (0.7293577981651376, -0.9915611814345991), (0.7339449541284404, -0.9915611814345991), (0.7385321100917431, -1.0), (0.7431192660550459, -1.0), (0.7477064220183486, -0.9831223628691983), (0.7522935779816514, -0.9662447257383966), (0.7568807339449541, -0.9578059071729957), (0.7614678899082569, -0.9578059071729957), (0.7660550458715596, -0.9578059071729957), (0.7706422018348624, -0.9662447257383966), (0.7752293577981652, -0.9831223628691983), (0.7798165137614679, -0.9831223628691983), (0.7844036697247706, -0.8818565400843882), (0.7889908256880734, -0.8481012658227848), (0.7935779816513762, -0.6455696202531646), (0.7981651376146789, -0.49367088607594933), (0.8027522935779816, -0.4008438818565401), (0.8073394495412844, -0.26582278481012656), (0.8119266055045872, -0.09704641350210974), (0.8165137614678899, -0.05485232067510548), (0.8211009174311926, 0.012658227848101333), (0.8256880733944955, 0.1223628691983123), (0.8302752293577982, 0.240506329113924), (0.8348623853211009, 0.33333333333333326), (0.8394495412844036, 0.38396624472573837), (0.8440366972477065, 0.5358649789029535), (0.8486238532110092, 0.6624472573839661), (0.8532110091743119, 0.7383966244725739), (0.8577981651376146, 0.7468354430379747), (0.8623853211009175, 0.8987341772151898), (0.8669724770642202, 0.9578059071729959), (0.8715596330275229, 0.9831223628691983), (0.8761467889908257, 0.9831223628691983), (0.8807339449541285, 0.9831223628691983), (0.8853211009174312, 0.9831223628691983), (0.8899082568807339, 0.9746835443037976), (0.8944954128440367, 0.9746835443037976), (0.8990825688073395, 0.9746835443037976), (0.9036697247706422, 0.9578059071729959), (0.908256880733945, 0.9578059071729959), (0.9128440366972477, 0.9578059071729959), (0.9174311926605505, 0.9578059071729959), (0.9220183486238532, 0.9578059071729959), (0.926605504587156, 0.9746835443037976), (0.9311926605504587, 0.9831223628691983), (0.9357798165137615, 1.0), (0.9403669724770642, 0.9156118143459915), (0.944954128440367, 0.7046413502109705), (0.9495412844036697, 0.5527426160337552), (0.9541284403669725, 0.4430379746835442), (0.9587155963302753, 0.29957805907172985), (0.963302752293578, 0.139240506329114), (0.9678899082568807, 0.06329113924050622), (0.9724770642201835, -0.04641350210970463), (0.9770642201834863, -0.11392405063291144), (0.981651376146789, -0.189873417721519), (0.9862385321100917, -0.19831223628691985), (0.9908256880733946, -0.21518987341772156), (0.9954128440366973, -0.2067510548523207), (1.0, -0.19831223628691985)]  
txlist = np.asarray(txlist)  
  
plt.figure()  
plt.scatter(txlist[:,0], txlist[:,1])  
plt.savefig('fft02.jpg')  
plt.show()

위와 같은 그래프로 표현되는 원본 시그널이 있을 때, 수집된 샘플 데이터의 수가 부족할 수도 있다. 이 때는 보간법으로 점들 사이의 데이터들을 추정하여 채울 수 있다.
일정한 시간간격으로 추정된 위치값을 보간법으로 구해 데이터 수를 확장해 보자.

보간법

우리가 필요한 샘플링 주기는 최대 주파수 설정에 따른다.
최대 500Hz까지를 검사하여 성분 분석을 하려면 그 두배인 1000Hz를 maxfreq로 설정한다.
(나중에 나오지만 주파수 스펙트럼을 그려보면 중앙을 기준으로 좌우 대칭으로 나온다. 따라서 최대 주파수 *2를 해준다.)
1000Hz를 maxfreq로 잡으면 샘플링 주기는 1/1000 sec로 한다.
일정한 시간간격 (1ms)마다의 신호크기를 추정해 다시 그려보자.

from scipy.interpolate import splrep, splev  
  
spl = splrep(txlist[:,0], txlist[:,1])
fs = 1000 # max 500Hz *2  
dt = 1/fs   # 0.001  
spl = splrep(txlist[:,0], txlist[:,1])  
newt = np.arange(0, 1, dt)  
newx = splev(newt, spl)  
print(newt)  
print(newx)  
if True:  
    plt.figure()  
    plt.scatter(newt, newx)  
    plt.savefig('fft02_2.jpg')  
    plt.show()

fft02_2

FFT

위 신호를 분해해 보자.
먼저 주파수 스펙트럼을 구해서 어떤 주파수를 사용해야 하는지를 분석한다. 스펙트럼 그래프에서 높은 값을 가진 성분의 주파수를 선택하면 된다.

  
# 주파수 생성  
nfft = len(newt)  # number of sample count.  
print('nfft = ', nfft)  
df = fs/nfft    # 주파수 증가량 = max freq / 샘플개수  
k = np.arange(nfft)  
f = k*df      # 0부터~최대주파수까지의 범위 (sample count 개수 만큼, df증가량으로 분포)  
  
# 주파수 스펙트럼은 중앙을 기준으로 대칭이 된다. 반만 구한다.  
nfft_half = math.trunc(nfft/2)  
f0 = f[range(nfft_half)]      # only half size check for get hz.  
y = np.fft.fft(newx)/nfft * 2 # 증폭을 두 배로 한다. (반만 계산해서 에너지가 반으로 줌)  
y0 = y[range(nfft_half)]       # one side.  
amp = abs(y0)  # 벡터(복소수) norm 측정. 신호 강도. 
if True:  
    plt.figure()  
    plt.plot(f0, amp)  
    plt.savefig('fft02_3.jpg')  
    plt.show()

fft02_3
위 그래프의 가로축은 주파수이고 세로축은 신호 강도이다.
작은 값을 버리고 강도가 센 주파수만 선별하면 된다.
top N개를 설정해서 몇 개만 할 수 도 있지만, 몇 개가 최적인지 알 수 없기에 사분위수의 극단점을 이용해 보았다. (데이터 분포의 25%~75%범위의 끝에서 해당 크기의 1.5배 이상 떨어진 데이터)
굳이 이렇게까지 할 필요는 없고 특정 개수로 (예를 들면 10개로) 설정해도 된다.

  
# outlier 찾기. 사분위수 사용. boxplot.  
ampsort = np.sort(amp)  
q1, q3 = np.percentile(ampsort, [25, 75])  
iqr = q3-q1  
upper_bound = q3+1.5*iqr  
print('q1=',q1, 'q3=',q3, 'upper_bound=', upper_bound)  
outer = ampsort[ampsort>upper_bound]  
print('outer cnt=', len(outer))  
topn = len(outer)  
print(outer)

1000 개중에 특이하게 높은 값 101개를 찾았다.

nfft =  1000
q1= 2.7017249783348636e-05 q3= 0.00031241349163501486 upper_bound= 0.0007405078544125142
outer cnt= 101
[0.00081545 0.00085501 0.00086458 0.00090005 0.00090194 0.00091519
 0.00091733 0.00093784 0.00096499 0.00097396 0.00099638 0.00104299
 0.00107283 0.00126076 0.00126265 0.00127681 0.00129231 0.00131356....]

상위 101개의 주파수를 찾는다.

idxy = np.argsort(-amp)  
for i in range(topn):  
    print('freq=', f0[idxy[i]], 'amp=', y[idxy[i]])

마지막으로 주파수만으로 원본을 추정해 그려본다.

  
# recover  
newy = np.zeros((nfft,))  
arfreq = []  
arcoec = []  
arcoes = []  
for i in range(topn):  
    freq = f0[idxy[i]]  
    yx = y[idxy[i]]  
    coec = yx.real  
    coes = yx.imag * -1  
  print('freq=', freq, 'coec=', coec, ' coes', coes)  
    # newy += coec * np.cos( 2*np.pi*freq*newt+ang) + coes * np.sin( 2*np.pi*freq*newt+ang)  
  newy += coec * np.cos(2 * np.pi * freq * newt) + coes * np.sin(2 * np.pi * freq * newt)  
    arfreq.append(freq)  
    arcoec.append(coec)  
    arcoes.append(coes)  
  
plt.figure()  
plt.plot(txlist[:,0], txlist[:,1], c='r', label='orginal')  
plt.plot(newt, newy, c='b', label='fft')  
plt.legend()  
plt.savefig('fft02_4.jpg')  
plt.show()

fft02_4

거의 복원된 모습을 확인할 수 있다.

주성분 주파수를 하나씩 추가하여 변화하는 모습을 확인해 보자.

  
# progress ...  
plt.figure()  
plti = 0  
ncnt = 15  
  
newy = np.zeros((nfft,))  
for i in range(ncnt+1):  
    freq = f0[idxy[i]]  
    yx = y[idxy[i]]  
    coec = yx.real  
    coes = yx.imag * -1  
  print('freq=', freq, 'coec=', coec, ' coes', coes)  
    newy += coec * np.cos(2 * np.pi * freq * newt) + coes * np.sin(2 * np.pi * freq * newt)  
  
    plti+=1  
  plt.subplot(4,4, plti)  
    plt.title("N={}".format(i+1))  
    plt.plot(newt, newy)  
  
plt.savefig('fft02_5.jpg')  
plt.show()

fft02_5
주파수를 추가할 때 마다 점점 원본의 모습으로 바뀌어진다.

Authors: crazyj7@gmail.com
Written with StackEdit.

'Python' 카테고리의 다른 글

진행(progress)바/ tqdm  (2) 2019.08.28
Google Drive file upload/download  (0) 2019.08.20
[UI] Qt5  (0) 2019.05.17
두 선분의 교차여부 체크  (0) 2019.04.11
두 선분의 교점 찾기  (0) 2019.04.11
반응형
calculus_int_ln_gamma

01ln(Γ(x))dx \int_{0}^{1} ln(\Gamma(x))dx


We know this.
Γ(x)=0tx1etdtΓ(x)Γ(1x)=πsin(πx) \Gamma(x) = \int_{0}^{\infty}t^{x-1}e^{-t} dt \\ \Gamma(x) \Gamma(1-x) = \frac {\pi}{sin(\pi x)}
take log.
ln(Γ(x)Γ(1x))=lnπsin(πx)ln(Γ(x))+ln(Γ(1x))=lnπln(sin(πx)) ln(\Gamma(x) \Gamma(1-x)) = ln { \frac {\pi}{sin(\pi x)} }\\ ln(\Gamma(x))+ln(\Gamma(1-x)) = ln \pi - ln (sin(\pi x))
take integral.
ln(Γ(x))+ln(Γ(1x))=lnπln(sin(πx))01ln(Γ(x))dx+01ln(Γ(1x))dx=01lnπdx01ln(sin(πx))dx01ln(Γ(x))dx+01ln(Γ(u))du=01lnπ01ln(sin(πx))201ln(Γ(x))dx=01lnπdx01ln(sin(πx))dx201ln(Γ(x))dx=lnπ01ln(sin(πx))dx \int ln(\Gamma(x))+ \int ln(\Gamma(1-x)) = \int ln \pi - \int ln (sin(\pi x))\\ \int_0^1 ln(\Gamma(x)) dx+\int_0^1 ln(\Gamma(1-x)) dx = \int_0^1 ln \pi dx- \int_0^1 ln (sin(\pi x)) dx \\ \int_0^1 ln(\Gamma(x))dx+\int_0^1 ln(\Gamma(u)) du=\int_0^1 ln \pi - \int_0^1 ln (sin(\pi x))\\ 2\int_0^1 ln(\Gamma(x))dx=\int_0^1 ln \pi dx- \int_0^1 ln (sin(\pi x))dx\\ 2\int_0^1 ln(\Gamma(x))dx=ln\pi - \int_0^1 ln (sin(\pi x))dx
And watch the last part.
01ln(sin(πx))dx(u=πx,du=πdx)=0πln(sin(u))1πdu=1π0πln(sin(u))du \int_0^1 ln (sin(\pi x))dx\\ (u=\pi x , du=\pi dx) \\ =\int_0^{\pi} ln(sin(u)) \frac{1}{\pi} du\\ =\frac{1}{\pi} \int_0^{\pi} ln(sin(u)) du
We know
0π2ln(sin(x))dx=π2ln2 \int_0^{\frac{\pi}{2}}ln(sin(x))dx = -\frac{\pi}{2}ln2
So,
1π0πln(sin(u))du=1π20π2ln(sin(x))dx=1π2(π2ln2)=ln201ln(sin(πx))dx=ln2 \frac{1}{\pi} \int_0^{\pi} ln(sin(u)) du=\frac{1}{\pi} 2 \int_0^{\frac{\pi}{2}}ln(sin(x))dx \\ =\frac{1}{\pi} 2 (-\frac{\pi}{2}ln2) \\ = - ln 2\\ \int_0^1 ln (sin(\pi x))dx=-ln2
So,
201ln(Γ(x))dx=lnπ01ln(sin(πx))dx=lnπ(ln2)=lnπ+ln2 2\int_0^1 ln(\Gamma(x))dx=ln\pi - \int_0^1 ln (sin(\pi x))dx\\ =ln\pi - (-ln2) = ln \pi + ln 2
01ln(Γ(x))dx=lnπ+ln22=ln(2π)2 \therefore \int_0^1 ln(\Gamma(x))dx = \frac {ln \pi + ln 2} {2} = \frac {ln(2\pi)}{2}

Author
crazyj7@gmail.com
Written with StackEdit.

'Math' 카테고리의 다른 글

Integral100 [11-20]  (0) 2019.10.13
Integral100 [1-10]  (2) 2019.10.12
integral ln sin  (0) 2019.08.01
Gaussian integration  (0) 2019.07.26
적분 순서 치환방법 정리  (0) 2019.05.05
반응형
ASN1C

ASN.1 c/cpp code

What is ASN.1

Abstract Syntax Notation One 이란 뜻.
ITU에서 네트웍 데이터 교환을 정의한 프로토콜로 사용하는 표준화 포맷임. (X.680, X.681, X.682, X.683, X.690, X.691, X.692, X.693 등에 설명)
이 기종 장치들 간의 데이터 교환시 표준화가 필요하다. (byte ordering 등 여러가지 문제)
여러가지 ISO 표준 문서에서 사용하는 자료 구조 형태를 보면 ASN.1 문법으로 사용한다.
ASN.1 에서는 자료 구조들을 정의하는데, 길이라던지 범위라던지 등의 제약 조건 등도 포함된다. 자료 구조를 정의하는 문법의 문서 형태라서 소프트웨어 구현시에는 자체로 사용할 수 없고, ASN.1을 인코딩하여 사용한다. 이런 인코딩 들을 하기 위한 작업을 개발 언어별로 소스를 자동으로 만들어 주는 역할을 하는 것이 ASN.1 컴파일러 이다.

BER는 ASN.1의 기본 인코딩 규칙을 나타낸다. ASN.1 데이터를 인코딩하는 다른 방법으로는 DER, CER, PER 등이 있다.

ASN.1 compiler는 ASN.1 문법으로 작성된 문서를 읽어 원하는 언어의 소스 파일로 만들어 주는 역할을 한다. (asn1c는 c 소스 코드를 생성한다.)

compiler download

Download asn1c(Compiler) source code and build.
버전에 따라 생성되는 코드가 다를 수 있다. 가장 최신 버전을 사용하는 것이 좋다. 상용으로 컴파일러를 파는 곳도 많다.

# wget https://lionet.info/soft/asn1c-0.9.28.tar.gz
# tar xvfz asn1c-0.9.28.tar.gz
# cd asn1c-0.9.28
./configure
./make
./make install
# asn1c -h
ASN.1 Compiler, v0.9.28

# Installation path may be /usr/local/bin.

Syntax

문법은 ASN.1 Syntax 검색하여 자세한 것은 찾아보고, 여기서는 간단한 예제 맛 보기.

Order ::= SEQUENCE {
  header Order-header,
  items SEQUENCE OF Order-line
  }
Order-header ::= SEQUENCE {
  number Order-number,
  date	Date,
  client Client,
  payment Payment-method
}

Certificate ::= SEQUENCE {
  tbsCertificate TBSCertificate,
  signatureAlgorithm AlgorithmIdentifier,
  signatureValue BIT STRING
}

TBSCertificate ::= SEQUENCE {
  version 	[0] EXPLICIT Version DEFAULT v1,
  serialNumber CertificateSerialNumber,
  signature	AlgorithmIdentifier,
  issuer	Name,
  validity	Validity,
  ...
}

Test ASN1c

asn 파일을 만들었으면 asn1c로 c코드를 생성한다.
Makefile을 만들어 사용하기.

--build.sh
#!/bin/sh
make -f Makefile.asn

--Makefile.asn
CC=cc
CPP=g++

.SUFFIXES=.c .o
.SUFFIXES=.cpp .o

all:
	asn1c format_iso.asn
	-rm converter-sample.c converter-sample.o
	$(CC) -c -fPIC -g *.c -I.
	$(CPP) -c -fPIC -g *.cpp -I.
#	$(CPP) -o a.out *.o

--Makefile.api
...
all:
	$(CC) -c -fPIC *.c -I.
	$(CPP) -c -fPIC asnapi.cpp -I . -D_LITTLE_ENDIAN_

test:
	$(CPP) -c -fPIC asnapitest.cpp -I.
	$(CPP) -o a.out *.o 
		

위에서 converter-sample.c를 참고하여 인코딩을 하는 것을 쉽게 따라해 볼 수 있다.
실제 사용하지는 않을 테니까 rm으로 빌드시 삭제하였다.

ASN api wrapper

ASN1 문서가 asn1c에 의해 컴파일되면 소스 코드들이 잔뜩 생긴다. 정의한 자료구조마다 헤더파일과 소스 파일이 각각 생성되어 생성된 소스 파일들이 너무 많다.
자료구조들을 사용하기 위해서는 wrapper하여 변환하는 함수를 만드는 것이 좋다.
ASN1 문서에 자료 구조 정의한 이름으로 소스 파일들이 생성되니, 최상위에 정의한 자료구조 명으로된 헤더 파일을 include하여 작성한다. 타입은 자료구조명에 _t가 붙어서 자동으로 생성된다.

wrapper example)

-- asnapi.h
#include "myData.h"
...
myData_t* mynotation2iso(string mynote) ;
myData_t* xer2iso(string mynote) ;
string iso2xer(myData_t *mydata) ;
myData_t* bin2iso(char *bin) ;
char* iso2bin(myData_t *mydata, OUT int *retbufsize) ;
...

--asnapi.cpp
위 wrapper 함수들을 구현

ASN 자료구조 생성

mynotation2iso():
mydata_t *mydata ;
// 메모리 초기화
mydata = (mydata_t*) calloc(1, sizeof *mydata) ;
// 메모리 해제 함수 연결. 메모리 해제시 내부의 리스트 엘리먼트들에 할당한 
// 메모리들이 있을 때는 수동으로 메모리 해제 함수를 만든다.
mydata->bodies.list.free = free_body ;

// 스트링 할당. 4바이트. 마지막 null 포함하여 octet string자료 구조내에 저장. 
// 내부에서 contents 메모리 할당이 발생함. free 필요.  
OCTET_STRING_fromBuf(&mydata->header.formatId, "abc", 4) ;
mydata->header.number = 1 ;

Body_t* body=NULL;
body = (Body_t*) calloc(1, sizeof *body) ;
body->reprenentation.qualityRecord.qualityBlock.list.free=free_qualityBlock ;

// 버퍼에서 스트링을 읽어 자료구조 octet 스트링에 복사. 일반 바이너리값 
// 바이트 어레이도 이렇게 저장 가능.  
OCTET_STRING_fromBuf( &body->representation.captureDateTime, 
	(const char*)&utc, 9) ;
QualityBlock_t *qb=NULL ;
qb = (QualityBlock_t*) calloc(1, sizeof *qb) ;
..
// 리스트 구조(sequence of)는 이렇게 추가한다.
asn_sequence_add(&body->representation.qualityRecord.qualityBlocks, qb) ;
...
int zero=0 ;

// new_fromBuf로 하면 octet 스트링 자료구조 메모리가 할당되어 반환된다. 
body->representationBody.extendedData = 
	OCTET_STRING_new_fromBuf(&asn_DEF_OCTET_STRING, (const char*)&zero, 2) ;
asn_sequence_add(&mydata->bodies, body) ;

// XER 포맷으로 변환하여 스트링 출력
xer_fprintf(stdout, &asn_DEF_mydata, mydata) ;
return mydata ;

free_body(Body_t *b):
free_scd(b->representation.channelDescription.descriptions.x) ;

// 리스트 해제. 내부에 free 지정 콜백이 돌아가면서 내부의 메모리 해제.
asn_sequence_empty(&b->representation.qualityRecord.qualityBlocks)

// 내부 버퍼 메모리 해제 및 OCTET_STRING 구조체 메모리도 해제.
// extendedData 자체가 OCTET_STRING* 타입. 별도 할당(new_fromBuf)한 
// 메모리 해제가 필요하여 마지막 플래그값으로 0이로 설정. 
OCTET_STRING_free(&asn_DEF_OCTET_STRINTG, b->representationBody.extendedData,0) ;

// 마지막플래그는 contents_only로 1이면 contents만 해제한다. 
// octet_string 구조체(컨테이너) 메모리는 해제하지 않음.
// captureDateTime 자체가 OCTET_STRING 타입으로 별도 할당한 메모리가 아니라
// 상위 구조체 할당시 잡힌 영역임. 여기서 해제 불필요.
OCTET_STRING_free(&asn_DEF_OCTET_STRINTG, &b->representation.captureDateTime,1) ;
free(b);

set_nodefree(mydata_t *mydata):
mydata->bodies.list.free=free_body ;
asn_anonymous_sequence_ *ss = _A_SEQUENCE_FROM_VOID( &mydata->bodies) ;
for (int j=0; j<ss->count; j++) {
	Body_t *body = (Body_t*)ss->array[j] ;
	body->representation.qualityRecord.qualityBlocks.list.free = 
		free_qualityBlock ;
}

위의 예제를 보면 복잡해 보인다. 실제 생성된 소스코드들을 분석해야지만 사용할 수 가 있다. 특히 리스트 사용이나 스트링 처리, 메모리 관리가 처음에 어려울 수 있다. 위의 예제를 참고하면 스트링이나 리스트 사용시 도움이 될 것이다. (주의: asn1c는 버전에 따라 Integer_t에 int 값 할당하는 것도 에러가 날 수 있다.)


Example

original page http://lionet.info/asn1c/examples.html

  • MyModule.asn1
MyModule DEFINITIONS ::=
BEGIN

MyTypes ::= SEQUENCE {
    myObjectId   OBJECT IDENTIFIER,
    mySeqOf      SEQUENCE OF MyInt,
    myBitString  BIT STRING {
                        muxToken(0), 
                        modemToken(1)
                 }
}

MyInt ::= INTEGER (0..65535)

END
  • asn1c MyModule.asn1

  • create structure files.

  • my-program.c

#include <stdio.h>	/* for stdout */
#include <stdlib.h>	/* for malloc() */
#include <assert.h>	/* for run-time control */
#include "MyTypes.h"	/* Include MyTypes definition */

int main() {
	/* Define an OBJECT IDENTIFIER value */
	int oid[] = { 1, 3, 6, 1, 4, 1, 9363, 1, 5, 0 }; /* or whatever */

	/* Declare a pointer to a new instance of MyTypes type */
	MyTypes_t *myType;
	/* Declare a pointer to a MyInt type */
	MyInt_t *myInt;

	/* Temporary return value */
	int ret;

	/* Allocate an instance of MyTypes */
	myType = calloc(1, sizeof *myType);
	assert(myType);	/* Assume infinite memory */

	/*
	 * Fill in myObjectId
	 */
	ret = OBJECT_IDENTIFIER_set_arcs(&myType->myObjectId,
			oid, sizeof(oid[0]), sizeof(oid) / sizeof(oid[0]));
	assert(ret == 0);

	/*
	 * Fill in mySeqOf with a couple of integers.
	 */

	/* Prepare a certain INTEGER */
	myInt = calloc(1, sizeof *myInt);
	assert(myInt);
	*myInt = 123;	/* Set integer value */

	/* Fill in mySeqOf with the prepared INTEGER */
	ret = ASN_SEQUENCE_ADD(&myType->mySeqOf, myInt);
	assert(ret == 0);

	/* Prepare another integer */
	myInt = calloc(1, sizeof *myInt);
	assert(myInt);
	*myInt = 111222333;	/* Set integer value */

	/* Append another INTEGER into mySeqOf */
	ret = ASN_SEQUENCE_ADD(&myType->mySeqOf, myInt);
	assert(ret == 0);

	/*
	 * Fill in myBitString
	 */

	/* Allocate some space for bitmask */
	myType->myBitString.buf = calloc(1, 1);
	assert(myType->myBitString.buf);
	myType->myBitString.size = 1;	/* 1 byte */

	/* Set the value of muxToken */
	myType->myBitString.buf[0] |= 1 << (7 - myBitString_muxToken);

	/* Also set the value of modemToken */
	myType->myBitString.buf[0] |= 1 << (7 - myBitString_modemToken);

	/* Trim unused bits (optional) */
	myType->myBitString.bits_unused = 6;

	/*
	 * Print the resulting structure as XER (XML)
	 */
	xer_fprint(stdout, &asn_DEF_MyTypes, myType);

	return 0;
}
  • $ cc -o a.out -I. *.c
  • ./a.out
<MyTypes>
    <myObjectId>1.3.6.1.4.1.9363.1.5.0</myObjectId>
    <mySeqOf>
        <MyInt>123</MyInt>
        <MyInt>111222333</MyInt>
    </mySeqOf>
    <myBitString>11</myBitString>
</MyTypes>
  • my-program2.c
#include <stdio.h>	/* for stdout */
#include <stdlib.h>	/* for malloc() */
#include <assert.h>	/* for run-time control */
#include "MyTypes.h"	/* Include MyTypes definition */

int main(int argc, char *argv[]) {
	char buf[1024];	/* Hope, sufficiently large buffer */
	MyTypes_t *myType = 0;
	asn_dec_rval_t rval;
	char *filename;
	size_t size;
	FILE *f;

	/*
	 * Target variables.
	 */
	int *oid_array;	/* holds myObjectId */
	int oid_size;
	int *int_array;	/* holds mySeqOf */
	int int_size;
	int muxToken_set;	/* holds single bit */
	int modemToken_set;	/* holds single bit */

	/*
	 * Read in the input file.
	 */
	assert(argc == 2);
	filename = argv[1];
	f = fopen(filename, "r");
	assert(f);
	size = fread(buf, 1, sizeof buf, f);
	if(size == 0 || size == sizeof buf) {
		fprintf(stderr, "%s: Too large input\n", filename);
		exit(1);
	}

	/*
	 * Decode the XER buffer.
	 */
	rval = xer_decode(0, &asn_DEF_MyTypes, &myType, buf, size);
	assert(rval.code == RC_OK);

	/*
	 * Convert the OBJECT IDENTIFIER into oid_array/oid_size pair.
	 */
	/* Figure out the number of arcs inside OBJECT IDENTIFIER */
	oid_size = OBJECT_IDENTIFIER_get_arcs(&myType->myObjectId,
			0, sizeof(oid_array[0]), 0);
	assert(oid_size >= 0);
	/* Create the array of arcs and fill it in */
	oid_array = malloc(oid_size * sizeof(oid_array[0]));
	assert(oid_array);
	(void)OBJECT_IDENTIFIER_get_arcs(&myType->myObjectId,
			oid_array, sizeof(oid_array[0]), oid_size);

	/*
	 * Convert the sequence of integers into array of integers.
	 */
	int_size = myType->mySeqOf.list.count;
	int_array = malloc(int_size * sizeof(int_array[0]));
	assert(int_array);
	for(int_size = 0; int_size < myType->mySeqOf.list.count; int_size++)
		int_array[int_size] = *myType->mySeqOf.list.array[int_size];

	if(myType->myBitString.buf) {
		muxToken_set   = myType->myBitString.buf[0]
					& (1 << (7 - myBitString_muxToken));
		modemToken_set = myType->myBitString.buf[0]
					& (1 << (7 - myBitString_modemToken));
	} else {
		muxToken_set = modemToken_set = 0;	/* Nothing is set */
	}

	return 0;
}

Authors
crazyj7@gmail.com
Written with StackEdit.

+ Recent posts