컴퓨터

GNU Radio를 이용한 AM 구현

뽕다르 2008. 8. 4. 21:35
사용자 삽입 이미지

GNU Radio & USPR

GNU Radio는 GNU General Public License하에 배포되는 signal processing package로서 electromagnetic spectrum을 이용해 radio spectrum을 이해하고 쉽게 사용할 수 있게 해주는 장치 입니다. GNU Radio는 modular pipeline structure와 python언어의 쉬운 configuration과 flexibility 성질을 이용하여 프로그래밍 하기 쉽도록 만들어져있어 처음 접하는 사람들도 쉽게 이해하고 다양하게 활용할 수 있습니다. .

USRP는 software radio를 만들기 위한 high speed USB기반의 장치로서 4개의 high speed digital to analog converter와 4개의 high speed digital to analog converter, FPGA, glue logic으로 구성되어 있습니다. USRP는 GNU Radio와 무료로 제공되는 라이브러리를 이용해 자유롭게 다양한 어플리케이션을 구현할 수 있습니다.


AM Radio


AM은 Amplitude Modulation의 약자로 말 그대로 carrier 신호의 주파수의 진폭을 변조해서 정보를 전달하는 방식입니다. 이에 반해서 FM은 주파수를 변조해서 정보를 정송하는 방식이죠. 변조방식을 이용해 신호를 전단하기 위해서는 아래와 같은 과정을 거쳐서 신호를 전달하게 됩니다.

사용자 삽입 이미지

Modulation Processing Block.

기저신호(Baseband Signal)에 캐리어 신호를 넣는 변조 과정을 저쳐 변조된 신호를 전송하고 수신단에서는 그 신호를 받아 다시 복조 과정을 거쳐서 원 신호를 복원하게 되는것입니다.

AM 변조방식에는 여러가지가 있는데 여기에서는 DBS-LC Modulation라는 방식을 이용한다는것만 알고 넘어가겠습니다. 아래 그림은
DBS-LC방식을 나타내는 그림입니다.
사용자 삽입 이미지

DBS-LC Modulation Process.



GNU Radio를 이용한 AM 구현

사용자 삽입 이미지

AM Receiver Signal Process.


#!/usr/bin/env python
from gnuradio import gr, eng_notation,optfir
from gnuradio import audio
from gnuradio import usrp
from gnuradio import blks
from gnuradio.eng_option import eng_option
from optparse import OptionParser
import sys
import math
from usrpm import usrp_dbid
from gnuradio.wxgui import stdgui, fftsink,scopesink,fftsink2,form
import wx

def pick_subdevice(u):
    return usrp.pick_subdev(u, (usrp_dbid.BASIC_RX,
                                usrp_dbid.LF_RX,
                                usrp_dbid.TV_RX,
                                usrp_dbid.TV_RX_REV_2,
                usrp_dbid.TV_RX_REV_3))

class wfm_rx_graph (stdgui.gui_flow_graph):
    def __init__(self,frame,panel,vbox,argv):
        stdgui.gui_flow_graph.__init__ (self,frame,panel,vbox,argv)

        adc_rate = 64e6
        usrp_decim = 250
        if_rate = adc_rate / usrp_decim  #256k
        if_decim = 4
        demod_rate = if_rate / if_decim   #64k
   
        audio_decimation = 2
        audio_rate = demod_rate / audio_decimation  #32k
        interpolator = gr.fractional_interpolator_ff(0, 32.0/48.0)

        src = usrp.source_c ()
        src.set_decim_rate(usrp_decim)       
        subdev = usrp.selected_subdev(src, pick_subdevice(src))            
        usrp.tune(src, 0, subdev, 1107e3+64000)           
   
        channel_coeffs = gr.firdes.low_pass (1, if_rate, 8000, 1000, gr.firdes.WIN_HANN)         
        ddc = gr.freq_xlating_fir_filter_ccf (if_decim, channel_coeffs, 64000, if_rate)           
           
        #mag
        magblock = gr.complex_to_mag()
           
        #vol
        volumecontrol = gr.multiply_const_ff(.5)

        #audio filetr
        audio_coeffs =   gr.firdes.low_pass (1.0, demod_rate, 9e3, 4e3, gr.firdes.WIN_HANN)
        audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)

        # sound card as final sink
        audio_sink = audio.sink (int (audio_rate))
 
        # now wire it all together
        self.connect (src, ddc)
        self.connect (ddc, magblock)
        self.connect (magblock, audio_filter)
        self.connect (audio_filter, volumecontrol)
        self.connect (volumecontrol, interpolator)
        self.connect (interpolator, (audio_sink, 0))
       
        #GUI
        pre_demod, fft_win1 = fftsink.make_fft_sink_c (self,panel, "AM_Data from USRP", 512, 256e3,-140,20)
        self.connect (src, pre_demod)
        vbox.Add (fft_win1, 3, wx.EXPAND)
           
        post_ddc, fft_win2 =  fftsink.make_fft_sink_c (self, panel, "post_ddc",512, 64e3, -140, 20)
        self.connect (ddc, post_ddc)
        vbox.Add (fft_win2, 3, wx.EXPAND)
       
        ost_filt, fft_win3 =  fftsink.make_fft_sink_f (self, panel, "audio_filter",512, 32e3, -140, 20)
        self.connect (audio_filter, ost_filt)
        vbox.Add (fft_win3, 3, wx.EXPAND)
   
if __name__ == '__main__':
    app = stdgui.stdapp (wfm_rx_graph, "WFM RX")
    app.MainLoop ()


USRP Block


USRP의 RF단을 통해 Radio Signal을 수신하기 위해서는 interface설정이 필요합니다. USRP를 설정하기 위한 코드는 다음과 같습니다.

src = usrp.source_c ()
src.set_decim_rate(usrp_decim)
subdev = usrp.selected_subdev(src, pick_subdevice(src))
usrp.tune(src, 0, subdev, 1107e3+64000)

usrp.source_c() 함수는 USRP Rx path interface로 연결하는 기능을 합니다. 이때 ‘_c’ 는 complex로 데이터를 수신함을 의미합니다. USRP내부의 ADC sampling rate는 64Mhz로 수행됩니다.

다음으로 usrp.tune() 함수를 이용해 center frequency를 setting하게 되는데 함수 인자 및 각각의 의미는 다음과 같습니다.

usrp.source_x.tune(u, chan, subdev, target_freq)
Parameters  u: instance of usrp.source_*
                 chan: DDC number
                 subdev: daughterboard subdevice
                 target_freq: frequency in Hz

위 sample source에서는 1107khz+64khz를 중심 주파수로 설정된 상태입니다. 아래 그림은 sample source가 실행될 때 USRP를 통해 들어오는 signal를 frequency domain에서 본 모습입니다.

사용자 삽입 이미지

Signal from USRP in frequency domain. Frequency centered at 1171khz.



Digital Down Converter (DDC) Block

USRP를 통해 64Mhz로 sampling된 signal은 DDC기능을 하는 gr.freq_xlating_fir_ccf() 함수를 통해 down converting되게 됩니다.

gr. freq_xlating_fir_filter _xxx (decimation, taps, center_freq, sampling_freq)
Parameters  decimation: integer
                 taps: depends on function
                 center_freq: double
                 sampling_freq: double

gr.freq_xlating_fir_ccf() 함수는 내부적으로 frequency translation, FIR filter, decimation 과정을 수행합니다. 이런 기능을 통해 원하는 channel을 효과적으로 selection하고 wide bandwidth input을 narrow band signal로 decimate하게 됩니다. ‘_ccf’는 complex input complex output을 의미합니다.  

channel_coeffs = gr.firdes.low_pass (1, if_rate, 8000, 1000, gr.firdes.WIN_HANN)         
ddc = gr.freq_xlating_fir_filter_ccf (if_decim, channel_coeffs, 64000, if_rate)

위 sample source에서는 중심 주파수를 64khz로 설정하고 sampling_freq 265khz, cutoff_freq 8khz, transition_with 1khz인 Low Pass Filter (LPF)와 계수가 4인 decimation을 통해 최종적으로는 64khz로 sampling된 signal이 나오게 됩니다.

아래 그림은 DDC를 통과한 신호의 frequency domain에서의 모습입니다.
사용자 삽입 이미지

Post-DDC Signal in frequency domain.


Magnitude Block

DSB-LC방식의 AM signal을 demodulation 하기 위해서 주로 envelope detection을 거치게 됩니다. software frequency에서는 magnitude를 통해 같은 과정을 수행하게 됩니다. 이때 사용되는 함수가 gr.complex_to_mag()입니다.

magblock = gr.complex_to_mag()

gr.complex_to_mag() 함수는 complex signal을 받아 float형식의 magnitude를 출력으로 내보내는 역할을 합니다. 이 과정을 거치면서 modulated signal이 demodulation이 되면서 original signal이 복원되게 됩니다.



LPF Block

Magnitude를 거쳐 복원된 original signal에서 불필요한 부분을 줄이고 가청 주파수 대역만 남기기 위해 LPF를 이용합니다. gr.fir_filter_fff() 함수가 그 역할을 하게 됩니다.

gr. fir_filter_xxx (decimation, taps)
Parameters    decimation: integer
                taps: depends on function

gr.fir_filter_fff()는 float 형식의 Signal을 입력 받아 low pass filter와 decimation을 수행하고 float형식으로 내보내게 됩니다.

audio_coeffs = gr.firdes.low_pass (1.0, demod_rate, 9e3, 4e3, gr.firdes.WIN_HANN)
audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)

위 sample source에서는 sampling_freq 64khz, cutoff_freq 8khz, transition_with 4khz인 Low Pass Filter와 계수가 2인 audio_decimation을 지나면서 최종적으로 32khz로 sampling된 signal이 출력됩니다. 아래 그림은 audio_filter을 통과한 signal의 frequency domain에서의 모습입니다.

사용자 삽입 이미지

Post-LPF Signal in frequency domain.


출력되는 sound signal의 volume을 설정하기 위해서는 gr.multiply_const_ff() 함수를 이용합니다.

volumecontrol = gr.multiply_const_ff(.5)

gr.multiply_const_ff() 함수는 float형식의 constant signal을 입력 받아 크기를 증가 시켜 float형식으로 출력하게 됩니다. 이렇게 나온 signal는 sound_sink() 함수를 통해 PC의 sound card로 입력되어 PC와 연결된 스피커를 통해 signal을 들을 수 있게 되는것입니다.
함수별 인자, 기능설명 :