맥스웰 방정식으로 부터 전자기파의 유도 과정

맥스웰 방정식의 4개의 연립 미분 방정식을 통해 전자기파를 예언 하였던 유도 과정을 알아 보자.

멕스웰 방정식

  • 전기장에 대한 가우스법칙(전기장 발산) $$ \boldsymbol{\nabla} \boldsymbol{\cdot} \mathbf{E} = \frac{\rho}{\varepsilon_0} \tag{1} $$

  • 자기장에 대한 가우스 법칙(자기장 발산) $$ \boldsymbol{\nabla} \boldsymbol{\cdot} \mathbf{B} = 0 \tag{2} $$

  • 페러데이 전자 유도(전기장의 회전) $$ \boldsymbol{\nabla} \boldsymbol{\times} \mathbf{E} = -\frac{\partial \mathbf{B}}{\partial t} \tag{3} $$

  • 앙페르-맥스웰법칙(자기장의 회전) $$ \boldsymbol{\nabla} \boldsymbol{\times} \mathbf{B} = \mu_0\mathbf{J} + \varepsilon_0\mu_0 \frac{\partial\mathbf{E}}{\partial t} \tag{4} $$

전자기파 유도

자유 공간에서 전하 밀도 $\rho$ 와 전도 전류 밀도 $\mathbf{J}$ 가 $0$ 이므로 멕스웰의 방정식 $(1)$ 과 $(4)$는 다음과 같이 쓸 수 있다.

$$ \boldsymbol{\nabla} \boldsymbol{\cdot} \mathbf{E} = 0 \tag{1} $$

$$ \boldsymbol{\nabla} \boldsymbol{\times} \mathbf{B} = \varepsilon_0\mu_0 \frac{\partial\mathbf{E}}{\partial t} \tag{4} $$

(4) 식의 우항에 있는 $\mathbf{E}$를 소거하기 위해 (4) 식의 양변에 회전 연산을 취하면 다음과 같이 쓸 수 있다.

$$ \boldsymbol{\nabla} \boldsymbol{\times} (\boldsymbol{\nabla} \boldsymbol{\times} \mathbf{B}) = \boldsymbol{\nabla} \boldsymbol{\times} (\varepsilon_0\mu_0 \frac{\partial\mathbf{E}}{\partial t}) $$

좌항은 백터 3중곱의 연산에 의해 $$ \boldsymbol{\nabla} \boldsymbol{\times} (\boldsymbol{\nabla} \boldsymbol{\times} \mathbf{B}) = \boldsymbol{\nabla}(\boldsymbol{\nabla} \cdot \mathbf{B}) - (\boldsymbol{\nabla} \cdot \boldsymbol{\nabla}) \mathbf{B} $$ 가 되고 식 (2)의해 $\boldsymbol{\nabla} \cdot \mathbf{B} = 0$ 이므로 다음과 같이 정리 된다.

$$ \boldsymbol{\nabla}(\boldsymbol{\nabla} \cdot \mathbf{B}) - (\boldsymbol{\nabla} \cdot \boldsymbol{\nabla}) \mathbf{B} = -\boldsymbol{\nabla}^2 \mathbf{B} $$

우항은 우항의 $\boldsymbol{\nabla} \boldsymbol{\times}\mathbf{E}$를 $-\frac{\partial \mathbf{B}}{\partial t}$로 치환하면

$$ \varepsilon_0\mu_0 \frac{\partial}{\partial t}(\boldsymbol{\nabla} \boldsymbol{\times}\mathbf{E}) = \varepsilon_0\mu_0 \frac{\partial}{\partial t}(-\frac{\partial \mathbf{B}}{\partial t}) = - \varepsilon_0\mu_0 \frac{\partial^2\mathbf{B}}{\partial t^2} $$

좌변과 우변을 정리하면 다음과 같이 정리 되고

$$ -\boldsymbol{\nabla}^2\mathbf{B} = - \varepsilon_0\mu_0 \frac{\partial^2\mathbf{B}}{\partial t^2} $$ $-$를 곱하여 소거하면

$$ \boldsymbol{\nabla}^2\mathbf{B} = \varepsilon_0\mu_0 \frac{\partial^2\mathbf{B}}{\partial t^2} \tag{5} $$ 가 된다.

(3) 식의 우항에 있는 $\mathbf{B}$를 소거하기 위해 (3) 식의 양변에 회전 연산을 취하면 다음과 같이 쓸 수 있다.

$$ \boldsymbol{\nabla} \boldsymbol{\times} (\boldsymbol{\nabla} \boldsymbol{\times} \mathbf{E}) = \boldsymbol{\nabla} \boldsymbol{\times} (-\frac{\partial\mathbf{B}}{\partial t}) $$

앞서 (4) 번 식과 같은 방법으로 정리하면 좌항은 다음과 같이 정리된다.

$$ \boldsymbol{\nabla}^2 \mathbf{E} $$

우항은 다음과 같이 정리 된다.

$$ \boldsymbol{\nabla} \boldsymbol{\times} (-\frac{\partial\mathbf{B}}{\partial t}) = \frac{\partial}{\partial t}(\boldsymbol{\nabla} \boldsymbol{\times}\mathbf{B}) = -\frac{\partial}{\partial t}(\varepsilon_0\mu_0 \frac{\partial \mathbf{E}}{\partial t}) = - \varepsilon_0\mu_0 \frac{\partial^2\mathbf{E}}{\partial t^2} $$

우항과 좌항을 같이 정리 하면

$$ -\boldsymbol{\nabla}^2\mathbf{E} = - \varepsilon_0\mu_0 \frac{\partial^2\mathbf{E}}{\partial t^2} $$ $-$를 곱하여 소거하면

$$ \boldsymbol{\nabla}^2\mathbf{E} = \varepsilon_0\mu_0 \frac{\partial^2\mathbf{E}}{\partial t^2} \tag{6} $$ 가 된다.

식 (5) 와 식(6)은 아래와 같은 식 (7)의 파동방정식을 만족한다.

$$ \boldsymbol{\nabla}^2\mathbf{\mathbf{\psi}} = \frac{1}{v_2}\frac{\partial^2\mathbf{\mathbf{\psi}}}{\partial t^2} \tag{7} $$

파동방정식을 만족하는 대상은 파동으로 존재 함으로 전기장과 자기장은 파동으로 존재 한다고 할 수 있으며 식(3) 과 식 (4)의 해 시변 자기장에 의해 전기장이 형성되고 이렇게 형성된 시변 전기장에 의해 또다시 시변 자기장이 형성되고 무한이 반복되어 파동의 형태로 퍼저 나가는 것을 알 수 있다.

이때 식 (7) 우항의 $v$ 는 파동의 속도를 나타낸다. 식(5) 와 식(6) 에서 파동의 속도 $v$를 유도하면 다음과 같다.

$$ \frac{1}{v^2} = \varepsilon_0\mu_0 $$

양변에 역수를 취하면

$$ v^2 = \frac{1}{\varepsilon_0\mu_0} $$

양변에 제곱근을 취하면 다음과 같이 풀 수 있다.

$$ v = \frac{1}{\sqrt{\varepsilon_0\mu_0}} = 2.99 \times 10^8 \ \mathrm{m}/\mathrm{s} $$

이를 통해 전자기파의 속도가 빛의 속도와 같음을 알 수 있다. 이를 통해 빛 이 전자기파의 일종임을 유추 할 수 있다.

오픈 소스 구현을 이용한 NETCONF Hands-On

오픈 소스 구현을 이용한 NETCONF Hands-On

오픈소스를 이용하여 NETCONF 의 간단한 동작을 확인 해보자.

사용할 오픈소스 구현은 다음과 같다.

  • libyang: YANG 데이터 모델링 언어의 파서와 툴킷을 제공한다. sysrepo, libnetconf2, netopeer2에서 사용된다.
  • sysrepo: YANG 으로 모델링된 데이터의 데이터 스토어를 제공한다.
  • libnetconf2: NETCONF 서버와 클라이언트에서 사용되는 라이브리를 제공한다.
  • netopeer2: NETCONF 서버와 테스트용 클라이언트를 제공한다.

설치 하기

설치에 시간이 걸리기 때문에 빠른 테스트를 위해 도커 이미지를 만들어 놓았다.

시스템에 도커가 설치되어 있다면 별도의 설치 없이 테스트가 가능하다.

빌드 방법을 알고 싶다면 Dockerfile을 참조 하자.

sysrepo와 netopeer2는 개발과정에는 필요 하지 않기 때문에 테스트용 이미지와 개발용 이미지를 분리 하였다. 다음은 개발용 이미지 생성을 위한 Dockefile이다.

테스트를 위한 netconf 도커 네트워크를 생성한다.

docker network create netconf

서버 실행

NETCONF 서버 실행을 위해

docker run --name netconf-server \
--rm \
--network netconf \
-p 830:830 \
-it \
euikook/netconf \
bash

Docker 쉘이 뜨면 아래 명령을 실행 하여 NETCONF 서버(netopeer2-server)를 실행한다.

netopeer2-server -d -v2

-d 옵션은 Debug 모드로 실행한다. 데몬 모드로 실행 되지 않고 포그 그라운드에서 실행된다. -v2 옵션은 Logging Level을 Warning 뿐 아니라 일반 디버깅 메시지도 출력 하도록 한다.

서버의 로그 메시지를 보면 클라이언트의 접속, RPC 수신및 요청에 대한 응답 정보를 볼 수 있다.

클라이언트 실행

docker run --name netconf-client \
--rm \
--network netconf \
-it \
euikook/netconf \
bash

Docker 쉘이 뜨면 아래 명령을 실행 하여 NETCONF 서버(netopeer2-cli)를 실행한다.

netopeer2-cli 프롬프트(>)가 뜬다.

NETCONF 서버에 접속

connect 명령을 이용하여 netconf-server에 접속한다.

connect --ssh --host netconf-server --login netconf

아래는 접속 예제다. 따라서 접속 해보자.

> connect --ssh --host netconf-server --login netconf
The authenticity of the host 'netconf-server' cannot be established.
ssh-rsa key fingerprint is a4:06:93:97:84:18:6b:56:15:d1:8f:0b:a2:61:75:4e:e0:cc:93:fd.
Are you sure you want to continue connecting (yes/no)? yes
netconf@netconf-server password:

비밀전호는 netconf 다.

help 명령을 입력 하면 가능한 명령 리스트를 볼 수 있다.

RPC 테스트

get-config 명령은 <get-config> RPC를 호출하여 설정 정보만을 가저 온다. 옵션으로 타킷 데이터 스토어를 지정 해 주어야 한다.

> get-config --source running

아래는 get-config 예제다.

> get-config --source running
DATA
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <keystore xmlns="urn:ietf:params:xml:ns:yang:ietf-keystore">
    <asymmetric-keys>
      <asymmetric-key>
        <name>genkey</name>
        <algorithm>rsa2048</algorithm>
        <public-key>MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArWDnLGZ670b5boVK9/brTTGBpc26pLMWPyvOqC81ujYQ7Rgc48rytcrCsiIXa7X/0gY9Oajbq5Swf9mWk+eev8fwdV6P/lrYfUN2nTiMTfLhGq3DcgG+jWObIEiXEB6KIY37awKstUmsxddcA0PG8G5excMFdAfU22jGSRMIudfRhjgFjaQPfuHAYKTUR5O+GiZdn/C9RzJ9yQgxpp1A3XbNT1oiey87BfV3yz8pSK/EgsK48/oq7hTLDGS28asNdEmOqx7oBto16TsACcQTZSNpAlMZzHZAUCUOe3AETaDi/qGGW3JtY6reHqAO1VLOYK8H9pQin67b91VtP7qQNQIDAQAB</public-key>
      </asymmetric-key>
    </asymmetric-keys>
  </keystore>
  <netconf-server xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server">
    <listen>
      <endpoint>
        <name>default-ssh</name>
        <ssh>
          <tcp-server-parameters>
            <local-address>0.0.0.0</local-address>
            <keepalives>
              <idle-time>1</idle-time>
              <max-probes>10</max-probes>
              <probe-interval>5</probe-interval>
            </keepalives>
          </tcp-server-parameters>
          <ssh-server-parameters>
            <server-identity>
              <host-key>
                <name>default-key</name>
                <public-key>
                  <keystore-reference>genkey</keystore-reference>
                </public-key>
              </host-key>
            </server-identity>
            <client-authentication>
              <supported-authentication-methods>
                <publickey/>
                <passsword/>
              </supported-authentication-methods>
            </client-authentication>
          </ssh-server-parameters>
        </ssh>
      </endpoint>
    </listen>
  </netconf-server>
</data>

get 명령은 <get> RPC 를 호출 하여 서버에서 설정정보와 운용상태 정보를 가저 온다.

> get
> get
DATA
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <keystore xmlns="urn:ietf:params:xml:ns:yang:ietf-keystore">
    <asymmetric-keys>
      <asymmetric-key>
        <name>genkey</name>
        <algorithm>rsa2048</algorithm>
        <public-key>MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArWDnLGZ670b5boVK9/brTTGBpc26pLMWPyvOqC81ujYQ7Rgc48rytcrCsiIXa7X/0gY9Oajbq5Swf9mWk+eev8fwdV6P/lrYfUN2nTiMTfLhGq3DcgG+jWObIEiXEB6KIY37awKstUmsxddcA0PG8G5excMFdAfU22jGSRMIudfRhjgFjaQPfuHAYKTUR5O+GiZdn/C9RzJ9yQgxpp1A3XbNT1oiey87BfV3yz8pSK/EgsK48/oq7hTLDGS28asNdEmOqx7oBto16TsACcQTZSNpAlMZzHZAUCUOe3AETaDi/qGGW3JtY6reHqAO1VLOYK8H9pQin67b91VtP7qQNQIDAQAB</public-key>
      </asymmetric-key>
    </asymmetric-keys>
  </keystore>
  <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
    <capabilities>
      <capability>urn:ietf:params:netconf:base:1.0</capability>
      <capability>urn:ietf:params:netconf:base:1.1</capability>
      <capability>urn:ietf:params:netconf:capability:writable-running:1.0</capability>
      <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
      <capability>urn:ietf:params:netconf:capability:confirmed-commit:1.1</capability>
      <capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
      <capability>urn:ietf:params:netconf:capability:validate:1.1</capability>
      <capability>urn:ietf:params:netconf:capability:startup:1.0</capability>
      <capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>
      <capability>urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&amp;also-supported=report-all,report-all-tagged,trim,explicit</capability>
      <capability>urn:ietf:params:netconf:capability:notification:1.0</capability>
      <capability>urn:ietf:params:netconf:capability:interleave:1.0</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-yang-metadata?module=ietf-yang-metadata&amp;revision=2016-08-05</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&amp;revision=2013-07-15</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&amp;revision=2013-07-15</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-acm?module=ietf-netconf-acm&amp;revision=2018-02-14</capability>
      <capability>urn:ietf:params:netconf:capability:yang-library:1.1?revision=2019-01-04&amp;content-id=1892760158</capability>
      <capability>urn:sysrepo:plugind?module=sysrepo-plugind&amp;revision=2022-08-26</capability>
      <capability>urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&amp;revision=2013-09-29&amp;features=writable-running,candidate,confirmed-commit,rollback-on-error,validate,startup,url,xpath</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults?module=ietf-netconf-with-defaults&amp;revision=2011-06-01</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-notifications?module=ietf-netconf-notifications&amp;revision=2012-02-06</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04</capability>
      <capability>urn:ietf:params:xml:ns:netmod:notification?module=nc-notifications&amp;revision=2008-07-14</capability>
      <capability>urn:ietf:params:xml:ns:netconf:notification:1.0?module=notifications&amp;revision=2008-07-14</capability>
      <capability>urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name?module=ietf-x509-cert-to-name&amp;revision=2014-12-10</capability>
      <capability>urn:ietf:params:xml:ns:yang:iana-crypt-hash?module=iana-crypt-hash&amp;revision=2014-08-06</capability>
    </capabilities>

결론

오픈 소스 구현을 이용하여 NETCONF 서버와 클라이언트를 실행 하고 간단한 테스트를 진행 해 보았다. 다음은 간단한 YANG 모듈을 모델링하고 하고 생성된 YANG 모듈을 NETCONF 서버에 설치 하는 방법에 대하여 알아보도록 한다.

YANG - Data Modeling Language

YANG: Data Modeling Language

개요

IETF NETCONF Working Group 에서 네트워크 관리 프로토콜인 NECONF의 데이터 모델링을 위해 개발한 데이터 모델링 언어다. NETCONF 프로토콜(RFC 6241은 표준에서 정의한 4 계층 중 Operation, Message, Transport 계층에 대해 정의 하였지만 최상위 계층인 Content 계층의 내용에 대해서는 정의하지 않았다.

SNMP에서 MIB를 정의 하기 위해 SMI를 정의 하였듯이 NETCONF에서 관리 데이터를 정의 하기 위해 데이터 모델링을 위한 언어인 YANG을 정의 하였다.

YANG은 매우 확장성 있는 데이터 모델링 언어로 당초 목적인 네트워크의 설정 데이터와 운용 데이터의 모델링 뿐 아니라 다른 분야 에서도 사용되고 있다.

데이터 구조

데이터 구조는 계층적이며 트리 구조를 가진다. 트리를 구성하는 각 노드는 이름을 가지며 스스로 특정 값을 가지거나 하위 노드는 가진다. YANG은 각 노드와 이러한 노드간의 관계를 대해 명확하고 간결하고 정의 한다.

YANG 의 데이터 모델은 모듈(Module) 과 하위모듈(Submodule)로 구성된다. 모듈은 다른 외부 모듈에서 정의를 가져올수(import) 있으면 하위 모듈은 정의를 포함 할 수 있다. 계층 구조는 확장(agument) 할 수 있으며 다른 모듈에서 정의된 계층 구조에 노드를 추가할 수 있다.

예를 들어 ietf-ip 모듈의 ipv4 타입에는 dscp 값을 설정 할 수 없지만 내부 적으로 QoS나 서비스구분을 위해 DSCP 필드의 설정이 필요하다면 DSCP 노드를 추가하여 확장할 수 있다.

augment "/if:interfaces/if:interface/ip:ipv4" {
  description "augments for QoS";  
  leaf qos-marking {    
    type inet:dscp;    
    default 0;    
    description "0 represents best effort'";  
   }
}

이러한 확장 기능은 조건부로 특정 노드의 값이 조건에 일치할 때만 적용 할수도 있다.

YANG 데이터 모델은 데이터 계층 구조에 특정 노드가 존재 하는지의 여부나 그 노드의 값에 근거하여 특정 노드의 존재 여부나 노드의 값을 제한하여 노드의 데이터가 반드시 지켜야 하는 제약 조건(constraints)을 정의할 수 있다.

이러한 제약조건(constraints)이용하여 데이터를 정교하게 모델링 한다면 의존성 있는 설정의 누락에 의한 설정 오류를 디바이스에 내리기 전에 검증할 수 있다.

예를 들어 Interface가 L3 모드인 경우에만 IP 주소를 설정 할 수 있도록 하는 제약 조건을 생각해 볼 수 있다.

데이터 모델링

leaf

정수, 문자열 같은 단순한 데이터를 가질 수 있다. 반드시 특정 형식을 가지는 하나의 값을 가져야하며 하위 노드를 가질 수 없다.

leaf-list

특정타입을 가지는 연속적인 값이다.

container

하위 트리에서 관련노드들을 그룹화 하는데 이용된다.

list

list에는 리스트 엔드리의 시퀀스를 정의한다. container 와 같은 각 엔트리는 key leaf 를 가지며 key leaf의 값에 의해 고유하게 식별된다.

설정 및 상태 데이터

YANG에서는 설정(Configuration) 과 상태(Operation state) 데이터로 구분된다. 이는 NETCONF를 정의할 때 논의 되었던 주요 요구사항중 하나다. YANG에서는 config 문을 통해 상태 데이터를 구분한다. 아래 예제를 보자 interface 노드는 namekey인 리스트다. interface 노드는 config 값이 true 이므로 설정 가능한 노드다. speed 리프는 열거형이고 10, 100, auto 중 선택가능하다. 명시적인 config 문은 없지만 부모 노드로 부터 상속받으므로 설정가능한 노드다. observed-speedconfig 문이 false이므로 운용상태를 나타내는 노드다. speedauto로 설정 되어 있을 때 자동 협상(auto negotiation)을 통해 결정된 속도가 반영될 것이다.

list interface {
  key "name";       
  config true;       
  leaf name {         
    type string;      
  }       
  leaf speed {       
    type enumeration {           
      enum 10m;         
      enum 100m;         
      enum auto;        
    }       
  }      
  leaf observed-speed {         
    type uint32;         
    config false;       
  }     
}

정리하자면 설정데이터와 상태 데이터의 구분은 config문에 의해 결정되며 명시적으로 지정되지 않았을 경우 부모 노드의 설정값이 상속된다.

데이터 타입

Built-In Data Types

다른 언어들과 비슥하게 YANG에서도 사전정의된 데이터 타입을 제공한다. 해당목록은 아래와 같다.

TypeDescriptions
binaryAny binary data
bitsA set of bits or flags
boolean“true” or “false”
decimal6464-bit signed decimal number
emptyA leaf that does not have any value
enumerationOne of an enumerated set of strings
indentifyrefA reference to an abstract identity
instance-identifierA reference to a data tree node
int88-bit signed integer
int1616-bit signed integer
int3232-bit signed integer
int6464-bit signed integer
leafrefA reference to a leaf instance
stringA character string
uint88-bit unsigned integer
uint1616-bit unsigned integer
uint3232-bit unsigned integer
uint6464-bit unsigned integer
unionChoice of member types

Drived Types(typedef)

YANG은 기본 데이터 타입에서 파생된 데이터 타입을 정의 할 수 있다. 파생된 데이터 타입을 typedef 문을 통해 정의된다. 기본 데이터 타입을 사전정의된 내장 데이터 타입뿐 아니라 파생데이터 타입을 수도 있다.

아래 예제는 uint8 데이터 타입에서 파생된 percent 타입을 정의하는 예제다. range 문을 통해 0에서 100 사이의 값만을 가질수 있는 제약사항이 적용된 uint8 타입이다.

typedef percent {
  type uint8 {
    range "0 .. 100";
  }
}
leaf completed {
  type percent;
}

다음에는 앞으로 사용할 예제 YANG 모듈을 모델링하고 YANG 파일로 표현해 보도록 한다.

References

  1. RFC 7950 - The YANG 1.1 Data Modeling Language

NETCONF - Network Configuration Protocol

개요

IETF NETCONF Working Group에서 발표한 네트워크 관리 프로토콜이다.

기존에 사용되던 SNMP를 대체 하기 위해 개발 되었으며 네트워크 오퍼레이터의 요구 사항을 반영하여 개발되었다. 최신 개정판은 RFC 6241 이다.

출연 배경

이전에 정의된 SNMP가 있었다. SNMP는 버전 3 까지 정의 되었다. SNMPv1 은 SNMP의 첫 번째 표준이다. 사실 IETF에서는 체계적인 관리 체계를 개발 하기 원했고 SNMPv1 은 더 나은 관리 프로토콜을 개발할기 까지 과도적으로 사용되는 임시 프로토콜로서 개발 되었다. 하지만 SNMPv1은 구현의 간편함으로 인해 널리 사용되었고 IETF에서는 새로운 프로토콜을 구현하는 대신 대신 SNMP를 발전 시키려고 하였다. 버전 1 에서 문제가 되었던 인증 관련 기능등의 추가 기능이 정의된 SNMPv2를 발표 하였으나 SNMPv1이 널리 사용되게 되었던 원인인 구현의 간편함이 없어졌기 때문에 사용자의 외면을 받았다. 이에 IETF에서는 SNMPv2에서 문제가 되었던 복잡한 인증 관련 기능을 제거한 SNMPV2c 를 발표 하였다. 이후 구현된 SNMPv3에서는 이전 버전에서 문제가 되었던 보안성이 강화되어 데이터의 기밀성, 무결성, 인증관련 기능들이 추가 되었다.

이러한 네트워크 관리 프로토콜(SNMP)의 발전에도 불구하고 메이저 밴더들은 SNMP를 모니터링이나 간단한 설정 기능을 위해 제한적으로 사용하였고 전체 네트워크 관리를 위해 사용되지 않았다. IETF에서는 이러한 이유에 대해 고찰 하였고 RFC 3535에서 그 내용을 볼 수 있다.

그이유는 SNMP는 간단한 모니터링에만 사용되었고 설정등은 원격 쉘을 통한 스크립팅으로 처리 되는게 대부분이었다.

간단한(단일 파라미터 대한) 설정은 상관 매우 잘 처리 할 수 있지만 파라미터를 순차적으로 설정 해야만 하는(Context를 가지는) 동작은 SNMP로 구현 하기가 쉽지 않다. 그리고 네트워크 운영자는 장비의 설정을 텍스트 형식의 파일로 관리하는 것을 선호 한다는 것이다. 새 장비가 설치 되거나 설정이 변경 되엇을 경우 설정을 하나 하나 실행하기 보다는 설정 파일을 변경 한 다음 설정 파일을 장비에 업로드 하여 한번에 적용 하는 경우가 많다. 이렇게 텍스트로 설정을 관리 하면 git로 버젼 관리가 가능해 잔다는 장점이 있다.

앞서 언급된 문제점을 해결하기 위하여 IETF의 NETCONF Working Group에서 SNMP를 대체할 수 있는 네트워크 관리 프로토콜의 개발을 시작 하였다. 2006년에 RFC 4741으로 처음 발표되었고 최신 개정판은 2011년에 발표된 RFC 6241 다.

프로토콜 구성

NETCONF 프로토콜은 아래와 같이 4 계층으로 구성된다.

  • 컨텐츠 계층(Content Layer)은 설정(Configuration), 운용상태(Operation State), 알림(Notification) 데이터로 구성된다. XML 기반이다.
  • 오퍼레이션 계층(Operation Layer)은 설정 데이터를 수정하기 위한 방법을 정의 한다.
  • 메시지 계층(Message Layer)은 RPC및 Notification 메시지를 인코인 하는 방법을 정의 한다.
  • 전송 계층(Transport Layer)은 클라이언트와 서버간에 메시지 전송을 위한 보안 채널을 정의 한다.

Content

설정 정보나 운영 상태 정보등을 정의 한다. 설정 정보나 상태 정보는 XML로 표현되며 이를 모델링 하기 위해 데이터 모델링 언어인 YANG을 정의 하였다.

JSON으로도 인코딩 할 수 있다.

Operation

설정 데이터를 열람 하거나 수정, 삭제, 장금등 데이터(Content)에 대한 동작을 정의 한다.

아래와 같은 동작이 있다.

  • get
  • get-config
  • set-config
  • copy-config
  • delete-config
  • lock
  • unlock
  • close-session
  • kill-session

Message

RPC(<rpc>) 와 RPC(<rpc-reply>)에 대한 응답, 알림(<notification) 등을 정의 한다.

Transport

클라이언트와 서버간에 메시지 전송을 위한 보안 채넣을 제공한다. TLS 와 SSH중 하나를 사용할 수 있다. 보통 SSH를 사용한다.

NETCONF는 텍스트 기반 프로토콜이기 때문에 netconf용 계정에 일반 SSH 클라이언트로 접속하여 직접 RPC를 보내도 NETCONF 서버는 올바게 응답한다.

 <rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><get-config><source><running/></source></get-config></rpc>

구글 도메인에서 DDNS 사용하기

DDNS with Google Domains

잠시 짬을 내어 창고에서 잠자고 있던 구형 PC로 개발 서버로 쓰기 위해 리눅스도 설치 하고 몇가지 개발 환경을 구축 했다. 유동 IP를 쓰다 보니 할당받은 IP가 변경 되었을 때 외부에서 접속할 방법이 마땅치 않아 내가 사용하는 도메인 네임 서비스인 구글 도메인즈에 을 통해 DDNS 설정을 하기로 하였다.

DDNS 구글 도메인즈 뿐만 아니라 많은 도메인 등록 업체나 네임서버 서비스 업체에서 제공하는 기능이기 때문에 아래 설명을 활용해 볼 수 있다.

아래는 구글 도메인에서 DDNS 레코드를 만들고 우분투 서버에서 DDNS 클라이언트를 설정 하는 방법에 대해 적어 본다.

동적 DNS를 이해 하기 위해서는 먼저 DNS를 이해 해야 한다.

DNS 란

우리가 크롬과 같은 브라우저를 통해 웹 페이지에 접속 할 때 사용하는 주소가 도메인 네입이다. 구글에 접속 한다고 가정한다면 우리는 웹 브라우저 주소창에 google.com을 입력 할 것이다. 이때 입력하는 google.com 이 도메인 네임이다.

거의 모둔 브라우저가 도메인 네임만 입력하면 자동적으로 프로토콜과 구분자를 자동적으로 추가 하여 https://google.com과 같이 입력된다. 이때 https 는 응용 프로토콜을 지정하고 :// 는 구분자이다. 그다음에 오는 google.com 이 도메인 네임이다.

하지만 내 브라우저가 구글의 웹 서버에 접속 하기 위해서는 우리가 자동차 네비게이션을 사용하때 코엑스를 목적지로 설정하면 네비게이션이 알아서 코엣스의 주소인 서울특별시 강남구 영동대로 513로 변환하여 안내 해주는 것 처럼 도메인 네임에 매핑된 IP 주소를 알아야 한다.

DNS는 우리에게 더 친숙한 도메인 네임을 컴퓨터가 이해 할 수 있는 32비트나 128 비트로 구성된 IP주소로 변환해 주는 인터넷의 코어 서비스 중 하나이다.

IP주소는 버전 4(IPv4) 기준으로 32비트이고 약 40억개가 있다. 32비트를 8비트씩 4그룹으로 나누고 각 그룹을 10진수로 표기한다. 그룹간의 구분 dot(.)으로 구분한것이 우리가 아는 1.2.3.4 같은 IP 주소이다. 이렇게 구분한 것을 우리는 dot-decimal notation 이라고 한다.

여담으로 IP 의 여섯번째 버전(IPv6)는 주소가 128 비트로 구성되어 있다. IPv4와 같이 8비트로 나눌경우 16그룹으로 나누어지기 때문에 표기하기가 어렵다. 따라서 16비트씩 여덟 그룹으로 나누고 각각을 16비트를 16빈수로 표기한다. 각 그룹의 구분은 콘론(:)을 사용한다. 이러한 방식을 colon-hex notation 이라고 한다.

기본적으로 도메인 네임과 IP주소는 $1:N$ 매핑이다. 네임서버의 정책에 따라 우리가 같은 도메인네임에 대한 IP주소를 요청하도라도 다른 IP 주소가 반환될 수 있다.

DDNS

기본적으로 도메인 네임과 IP주소를 $1:N$ 매핑이지만 우리는 서버를 여러대 하용하여 로드를 분산 시키거나 가용성을 위해 여러 서버를 두지 않을 것 이기 때문에 여기서는 $1:1$ 매핑으로 가정하고 설명을 진행한다.

보통 우리가 ISP(KT나 SKT등 통신 서비스를 저공해 주는 업체)에 인터넷에 인터넷을 설치 하면 ISP에서는 인터넷을 연결 해준다. 이때 우리가 인터넷 접속을 위해 UTP 케이블을 단말(PC나 노트묵)에 연결 하게 되면 단말은 DHCP 프로토콜을 통해 IP를 할당 받게 된다.

이 때 할당 받은 IP 주소는 우리가 사용하는 단말에 고정적으로 할당된 주소가 유동 IP를 할당 받게 된다. 단말을 재 시작하거나 UTP 케이블의 연결을 뺐다 다 시 연결 하였을 경우 단말은 DHCP를 통해 IP를 다시 할당 받게 되는데 이때 할당 받은 IP주소는 이전에 할당 받은 IP주소와 다를 수 있다.

DHCP서버는 IP 주소를 할달 할때 단말에 Lease 타임을 같이 알려 주는데 이는 해당 IP의 대여 시간이다. 보통 24시간이 설정된다. 단말은 IP를 할당 받은 이후 이 Lease 타임 안에 다시 IP를 요청하여 IP주소를 재 할당 받아야 한다. 이때 재할당 받은 주소는 이전주소와 같을 수도 있고 다를 수도 있다.

우리가 할당 받은 IP주소는 자주 변경되지 않는다고 하더라도 유동 IP이기 때문에 IP주소가 변결 될 때마다 DNS 서버에 변경된 IP주소를 업데이트해 주어야 한다. 여간 번거로운 일이 아닐 수 없다.

이때 사용할 수 있는 방법이 DDNS 서비스이다.

DDNS를 사용하기 위해서는 자신이 이용하는 도메인의 네임서버(NS)가 DDNS를 지원 해야 한다.

동작원리

DDNS 서비스가 어떻게 동작 하는지 알이 위해서는 먼저 개략적인 DNS 서버의 동작 원리를 알아야 한다.

우리가 브라우저를 통해 google.com에 접속한다고 생각해보자.

우리는 간단하게 크롬의 주소창에 google.com 을 입력 하였지만, 브라이저와 운영시스템(OS) 에서 www.google.com에 접속하기 위해 아주 많은 일들이 일어난다.

아주 이러한 동작들을 DNS관점에서 아주 간단하게 설명하자면 아래와 같은 일들이 일어난다.

  1. 브라우저는 www.google.com 에 접속하기 위해 운영체제에게 www.google.com에 대한 IP 주소를 요청한다.
  2. 운영체제는 자신이 가지고 있는 DNS 캐시에 www.google.com에 대한 IP주소가 있는지 확인하고 있을 경우 브라우저에게 해당되는 IP주소를 반환한다. DNS 캐시에 해당 도메인에 대한 매핑 정보가 없을 경우 설정된 DNS 서버로 DNS 쿼리를 요청한다. (이 서버를 클라이언트측 DNS 서버라고 하자)
  3. DNS 쿼리 요청을 받은 클라이언트측 DNS 서버는 자신의 DNS 캐시에 해당 도메인에 대한 매핑정보가 있는지 확인하고 매핑정보가 있을 경우 IP주소를 반환한다. 캐시에 매핑정보가 없는 경우 google.com의 네임서버(NS)에 매핑정보를 요청한다.
  4. google.com 네임서버는 google.com 도메인 이름에 대한 모든 설정 정보를 관리하고 있기 때문에 www.google.com 도메인에 대한 IP주소 정보를 반환한다.
  5. 네임서버로 부터 응답을 받은 클라이언트측 네임서버는 매핑정보를 자신의 캐시에 저장하고 클라이언트로 응답한다.
  6. 클라이언트측 DNS 서버로 부터 쿼리에 대한 응답을 받은 운영체제는 매핑정보를 로컬 캐시에 저장하고 브라우저에 IP주소를 반환한다.
  7. 브라이저는 해당 IP로 TCP 연결을 요청하고 정상적으로 연결 되었다면 HTTP나 HTTPS 프로토콜의 절차에 따라 윕페이지를 가져 온다.

위 과정에서 우리가 중요하게 보아야 하는 관정이 캐싱 과정이다. 캐싱 과정이 없다면 클라이언트측 네임서버는 google.com에 대한 DNS 요청이 발생 할때마다 google.com의 네임서버에 DNS 쿼리를 수행 해야 하기 때문에 불필요한 트래픽이 발생하게 되어 네트워크 낭비를 물론 네임서버의 부하가 커지에 된다. 사람들이 많이 접속 하는 도메인에 대한 IP주소는 캐시에 있을 확률이 높으므로 DNS서버가 쿼리 요청 없이 직접 응답 함으로서 불필요한 트래픽의 낭비를 줄일 수 있을 뿐만 아니라 빠른 응답을 보장할 수 있다.

이러한 캐싱은 매우 좋은 기능이지만 google.com의 관리자가 www.google.com의 IP주소를 변경 하였을 경우를 생각해보자. google.com의 관리자는 변경된 IP주소로 트래픽이 오기를 기대 하지만 클라이언트측 DNS 서버에 캐싱된 매핑정보를 응답 하기 때문에 문제가 발생한다.

이런 문제를 방지 하기 위해 DNS 레코드 마다 TTL(Time To Live)을 부여 하여 캐싱된 DNS 레코드가 얼마의 시간 동안 유효 한지를 알려 준다. DNS 서버에 캐싱된 정보는 레코드에 설정된 TTL 시간 동안만 유효 하고 그 이후에 는 유효하지 않기 때문에 캐시에서 삭제된다.

아래는 dig 명령으로 www.google.com에 대한 DNS 정보를 토청 한 것이다.

$ dig www.google.com
; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> www.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49873
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;www.google.com.			IN	A

;; ANSWER SECTION:
www.google.com.		218	IN	A	142.250.206.196

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Thu Dec 14 12:48:38 UTC 2023
;; MSG SIZE  rcvd: 59

ANSER SECTION 에 보면 www.google.com 다음이 있는 218 이 TTL 값이다. 218초 후에 해당 레코드는 유효 하지 않다는 의미이다.

DDNS는 DNS레코드의 업데이트를 관리자가 수동으로 하는것이 아니라 DDNS 클라이언트의 요청에 의해 자동으로 업데이트 할 수 있도록 하고 해당 레코드에 매우 짧은 TTL을 부여 하여 (보통 1분) 레코드의 IP가 변경 되더라도 매우 빠른 시간 내에 변경정보가 전파 될 수 있게 한 것이다.

DDNS A레코드 추가 하기

Google Domains 에서 DDNS에서 사용할 A 레코드를 추가 한다.

  1. 내도메인 에서 추가 하고 싶은 도메인을 선택한다.
  2. 오른쪽 사이드 메뉴에서 DNS를 선택한다.
  3. 메인 페이지 맨 아래쪽의 고급설정표시를 클릭 하여 고급 설정 을 연다.
  4. 동적 DNS 관리 버튼을 클릭하면 및에 DDNS 호스트를 입력 할 수 있는 입력 창이 나타난다.
  5. 입력항에 원하는 호스트 이름을 입력하고 저장 버튼을 누른다.
  6. 동적 DNS 하위 메뉴에 도메인에 동적 DNS가 설정됨을 클릭하면 설정된 동적 DNS 호스트를 확인할 수 있다.
  7. 사용자 인증 정보 보기 버튼을 클릭하면 DDNS 클라이언트에서 사용할 사용자 이름과 비밀번호가 나온다. 보기 버튼을 클릭하면 나오는 사용자 이름과 비밀번호를 별도 파일에 저장한다.

DDNS 클라이언트 설치

DDNS 클라이언트로 ddclient를 설치 한다.

apt 명령을 사용하여 ddclient를 설치 한다.

sudo apt install ddclient

우분투에서 apt 명령을 통해 ddclient 설치하면 설정 마법사가 자동으로 실행된다.

아래와 같이 설정한다.

  1. Dynamic DNS service providerdomains.google 로 선택한다.
  2. Optional HTTP proxy 그냥 빈칸으로 설정한다.
  3. UsernamePassword를 입력한다. 입력값은 앞서 저장한 인증 정보를 사용해야 한다.
  4. IP address discovery methodweb-based IP discovery service 를 선택한다.
  5. web-based IP discovery servicegoogledomains https://domains.google.com/checkip를 선택한다.
  6. Time between address check는 5분(5m) 그대로 사용하거나 원하는 값을 입력한다.
  7. Host to update에는 사용하고자 하는 도메인 이름을 입력한다.

설정이 완료 되었다.

설정 마법사에서 생성한 설정파일은 /etc/ddclient.conf 에 위치한다.

protocol=googledomains 
use=web, web=https://domains.google.com/checkip 
login=XLinEKbiWcJDHNlx 
password='4p5Gzes23RxsfaUw' 
ddns.oneuon.com

ddclient 설정을 변경하고 싶을 경우 아래와 같이 dpkg 명령을 통해 재설정 할 수 있다.

sudo dpkg-reconfiguration ddclient

설정 업데이트 이후 데몬은 자동으로 재시작 된다.

클라이언트의 설정은 변경없이 네임서버의 DDNS A레코드를 삭제 했다가 다시 생성한경우 ddclient 데몬을 재시작 하더라도 네입서버의 IP주는 업데이트 되지 않는다. 이유는 ddclient는 네임서버로 주소 업데이트 요청을 하기전 캐시 파일과 현재 구성을 피교 하여 구성이 없데이트 되었을 경우에만 네입서버로 업데이트 요청을 하기 때문이다. 캐시파일은 /var/cache/ddclient/ddclient.cache에 위치한다.

아래와 같이 캐시 파일을 삭제 하고 데몬을 제사작한다.

sudo cat /var/cache/ddclient/ddclient.cache
sudo systemctl restart ddclient

2 전력계법 - 3상 전력을 측정하는 방법

2 전력계법

이전 글에서 단상부하의 경우 유효전력을 측정하기 위한 3 전압계법3 전류계법에 대하여 알아보았다. 이번에는 평형 삼상회로 부하에서 2개의 유효전력계를 이용하여 3상 유효 전력을 측정하는 방법에 대해 알아본다.

유효전력계는 전압계, 전류계, 역률계로 구성되어 있으므로 전압계, 전류계, 역률계가 각각 2개씩 있으면 유효전력을 측정할 수 있다.

세상의 전압과 전류의 크기가 같고 그 위상이 서로 $120^\circ$ 차이날 때 평형삼상 이라고 한다. 평형 삼상회로에서 3상의 전압과 전류의 합은 $0$이다.

유효전력

3상에서 유효전력을 구하기 위해서는 선간전압과 선전류의 곱에$\sqrt{3}$배를 해주고 역률을 곱해 주어야 한다.

$$ P = \sqrt{3}VI\cos{\theta} $$

3상 부하의 전력은 각 상에서 소비하는 전력의 합이다. 한상의 소비전력은 $EI\cos{\theta}$ 이므로 3상 부하의 소비전력은 $3EI\cos{\theta}$가 된다. $Y$ 결선일 경우 선간전압이 상전압의 $\sqrt{3}$배이고 $\Delta$ 결선일 경우 선전류가 상전류의 $\sqrt{3}$배이기 때문에 소비 전력을 선간전압과 선간 전류로 나타내면 $\sqrt{3}VI\cos{\theta}$ 가 된다.

결선도

3상의 각 상을 $A$, $B$, $C$라고 하자.

Two Wattmeter Method Circuit Diagram
2 전력계법 결선도

$W_1$ 은 전압 $V_{ab}$, 전류 $I_a$와 이 둘 사이의 위상차 $\cos{\phi_1}$를 측정한다.

$$ W_1= V_{ab} \times I_a \times \cos{\phi_1} $$

$W_2$ 은 전압 $V_{cb}$, 전류 $I_c$와 이 둘 사이의 위상차 $\cos{\phi_2}$를 측정한다.

$$ W_2= V_{cb} \times I_c \times \cos{\phi_2} $$

삼상 평형이므로 삼상의 선간전압과 선전류는 그 크기가 같고 각 상의 위상이 $120^\circ$차 이기 때문에 그 크기만을 나타내는 $V_{ab}$와 $V_{cb}$는 $V$로 $I_1$과 $I_2$는 $I$로 바꾸더라고 등식이 성립한다.

$$ V = V_{ab} = V_{cb} $$

$$ I = I_a = I_c $$

3상 평형일 경우 위와 같은 등식이 성립함으로 $W_1$ 과 $W_2$를 다음과 같이 고쳐 쓸 수 있다.

$$ W_1= V \times I \times \cos{\phi_1} $$

$$ W_2= V \times I \times \cos{\phi_2} $$

페이저도

앞서 알아본 바와 같이 $W_1$과 $W_2$이 측정하는 값은 다음과 같다.

  • $W_1$ 은 전압 $V_{ab}$, 전류 $I_a$와 이 둘 사이의 위상차 $\cos{\phi_1}$를 측정한다.
  • $W_2$ 은 전압 $V_{cb}$, 전류 $I_c$와 이 둘 사이의 위상차 $\cos{\phi_2}$를 측정한다.

측정값을 페이저도로 나타내면 다음과 같다.

Two Wattmeter Method Phase Diagram
2 전력계법 페이저도

페이저 도에서 보면,

$\phi_1$은 $V_{ab}$ 와 $I_a$ 사이의 위상차이고 $V_a$ 와 $V_{ab}$ 사이의 위상차에 $V_a$ 와 $I_a$ 사이의 위상차의 더한 값이다.

$\phi_2$은 $V_{cb}$ 와 $I_c$ 사이의 위상차이고 $V_c$ 와 $V_{cb}$ 사이의 위상차에서 $V_c$ 와 $I_c$ 사이의 위상차를 뺀 값이다.

$Y$ 결선의 경우 상전압과 선간 전압은 $30^\circ$의 위상차가 있으므로 다음과 같이 나태낼 수 있다.

$$ \phi_1 = 30 + \theta $$

$$ \phi_2 = 30 - \theta $$

$W_1$ 과 $W_2$의 $\phi_1$과 $\phi_2$를 앞에서 구한 값으로 치환 하면 다음과 같이 고쳐 쓸 수 있다.

$$ W_1= V \times I \times \cos{\phi_1} = V \times I \times \cos{(30 + \theta)} $$

$$ W_2= V \times I \times \cos{\phi_2} = V \times I \times \cos{(30 - \theta)} $$

위 식은 삼각함수 덧셈정리를 이용하면 다음과 같이 나타낼 수 있다.

삼각함수 덧셈정리 $\cos{(\alpha \pm \beta)} = \cos{\alpha} \cos{\beta} \mp \sin{\alpha} \sin{\beta}$

$$ W_1= V \times I \times (\cos{30}\cos{\theta} - \sin{30}\sin{\theta}) = VI\cos{30}\cos{\theta} - VI\sin{30}\sin{\theta} $$

$$ W_2= V \times I \times (\cos{30}\cos{\theta} + \sin{30}\sin{\theta}) = VI\cos{30}\cos{\theta} + VI\sin{30}\sin{\theta} $$

우효전력, 무효전력, 피상전력 그리도 역률

$W_1$ 과 $W_2$를 더해보자. $$ W_1 + W_2 = 2VI\cos{30}\cos{\theta} = 2 VI \frac{\sqrt{3}}{2}\cos{\theta} = \sqrt{3}VI\cos{\theta} $$

따라서 유효전력 $P$는 다음과 같이 나타낼 수 있다.

$$ P = W_1 + W_2 $$

이번에는 $W_1$에서 $W_2$를 빼보자

$$ W_1 - W_2 = 2VI\sin{30}\sin{\theta} = 2 VI \frac{1}{2}\cos{\theta} = VI\cos{\theta} $$

위의 최종 값에 $\sqrt{3}$ 만 곱해주면 무효전력 $P_r$을 유도할 수 있다.

$$ P_r = \sqrt{3}(W_1 - W_2) $$

이제 우리는 유도한 유효전력과 무효전력을 통해 피상전력 $P_a$와 역률 $\cos{\theta}$를 유도할 수 있다.

$$ P_a = \sqrt{P^2 + P_r^2} = 2\sqrt{W_1^2 + W_2^2 - W_1W_2} $$

$$ \cos{\theta} = \frac{P}{P_a} = \frac{W_1 + W_2}{2\sqrt{W_1^2 + W_2^2 - W_1W_2}} $$

결론

2 전력계법을 통해 우리는 유효젼럭과 무효전력을 유도할 수 있고 이를 통해 피상전력과 역률을 유도할 수 있다는 것을 알았다.

$$ P = W_1 + W_2 $$

$$ P_r = \sqrt{3}(W_1 - W_2) $$

$$ P_a = 2\sqrt{W_1^2 + W_2^2 - W_1W_2} $$

$$ \cos{\theta} = \frac{W_1 + W_2}{2\sqrt{W_1^2 + W_2^2 - W_1W_2}} $$

3 전류계법 - 단상 전력을 측정하는 방법

개요

이전 글인 3전압계법을 다룬 글에서 이미 설명 했듯이 교류(AC) 회로에서 부하전압과 부하전류간 위상차가 존재하기 때문에 전원측에서 공급하는 전력과 실제 부하에서 소비되는 전력과 크기가 다르다. 교류 회로에서는 전원측에서 공급되는 전력을 피상전력($P_a$)이라고 하고 실제 부하에서 소비되는 전력을 유효전력($P$)이라고 한다. 피상전력으로부터 유효전력을 계산하기위해 역률($\cos{\theta}$)을 곱해주어야 한다. 자세한 내용은 3전압계법 의 개요를 참고하자.

본문에서는 전류계 3개를 이용하여 유효전력을 측정하는 방법을 알아본다.

들어가기 앞서

3전류계법을 시작하기 앞서 결론을 먼저 설명 하자면 역률을 유도하는 과정이 전압 $V$를 전류 $I$ 로 치환하면 될 정도로 3 전압계법과 거의 같다.

3전전류계법

아래와 같은 교류회로가 있다고 가정하자. 전원($V_{in}$) 과 부하($Z_L$) 사이에 하나의 병렬 저항과 3개의 전류계가 있다. $I_1$은 전원측에서 측정한 전류, $I_2$는 부하와 병렬로 연결된 저항 $R$에 흐로는 전류, $I_3$는 부하에 흐르는 전류를 측정한다.

Three Voltmeter Method Circuit Diagram

공급전류

전원측에서 공급되는 전류($I_1$)을 측정해보자. 다음 그림과 같이 저항기 앞단에 전원과 직렬로 연결하고 전류계의 지시값을 읽으면 전원 측에서 공급되는 진류를 알 수 있다.

부하전류 ($V$)

부하에 흐르는 전류는 저항 다음단에서 부하와 직렬로 전류계를 연결하고 전류계의 지시값을 읽으면 된다.

저항에 흐르는 전류($V$)

부하에 흐르는 전류를 측정해보자. 저항에 흐르는 전류를 구하기 측정하기 위해서는 부하와 병렬로 연결된 저항 $R$과 직렬로 전류계를 연결하고 전류계의 지시값을 읽으면 된다. 병렬회로에서는 전압이 같으므로 저항 $R$에 인가되는 전압을 계산하면 부하에 인가되는 전압을 유도할 수 있다. 저항에 인가되는 전압은 다음 식을 통해

$$ V = I \times R $$

$I$ 와 $R$의 곱임을 알 수 있다.

저항은 부하와 병렬로 연결되어 있고 병렬 회로에서는 전압이 일정 하기 때문에 저항에 인가되는 전압과 부하에 인가되는 전압은 그 크기와 위상이 같다.

역률 ($\cos{\theta}$)

부하에 인가되 전압($V = I \times R $) 와 부하에 흐르는 전류 ($I_3$)를 알았으니 역률 $\cos{\theta}$를 알면 부하에서 소비되는 전력 $P$를 구할 수 있다. 앞서 측정한 공급전류($I_1$), 저항에서의 흐르는 전류($I_2$), 부하에 흐르는 전류($I_3$)을 가지고 역률을 유도해 보자.

아래와 같은 조건을 기억하면서 페이저도를 그려보자.

  • 부하 $Z_L$를 지상 부하라고 가정한다.
  • 부하에 흐르는 전류 $\hat{I_3}$ 는 저항에 흐르는 전류 $\hat{I_2}$ 보다 지상이다. $\hat{I_2}$와 $\hat{I_3}$위상차를 $\phi$ 라고 하자.
  • 키르히호프의 전류 법칙(KCL)에 의해 회로내 임이의 지점에서 들어오는 전류의 합과 나가는 전류의 합은 같으므로 $\hat{I_1}$ 를 다음과 같이 표현할 수 있다.

$$ \hat{I_1} = \hat{I_2} + \hat{I_3} $$

  • 저항 $R$은 순저항 부하이기 때문에 $R$에 흐르는 전류 $\hat{I_2}$는 저항 $R$에 인가되는 전압과 위상이 같다.
  • 부하 $Z_L$은 저항 $R$과 병렬로 연결되어 있으므로 부하 $Z_L$에 인가되는 전압은 저항 $R$에 인가되는 전압과 크기 및 위상이 같다.
  • 따라서 부하 $Z_L$에 인가되는 전압($\hat{V}$)은 전류 $\hat{I_2}$와 위상이 같다.

$I_2$를 기준으로 페이저도를 그리면 다음과 같은 페이저도를 얻을 수 있다.

Three Voltmeter Method Circuit Diagram

페이저도를 통해 $\hat{I_2}$와 $\hat{V}$ 사이의 역률각 $\theta$는 다음과 $180 - \phi$ 임을 알 수 있다.

$$ \theta = 180 - \phi $$

우리가 알고 있는 정보로는 $\theta$ 를 직접 구할 수 없지만 $\phi$를 통해 역률각 $\theta$를 유도할 수 있다.

$\phi$ 가 속해 있는 삼각형의 세 변의 길이를 알고 있으므로 코사인 법칙을 이용하여 $\phi$ 를 구한다.

코사인 법칙을 통해 삼각형에서 두 변의 길이와 그 사잇각으로 부터 제 3변의 길이 구하거나 삼각형 세변의 길이를 알고 있을 경우 세 각을 크기를 알 수 있다.

$$ I_1^2 = I_2^2 + I_3^2 - 2I_2I_3\cos{\phi} $$

$\cos{\phi}$ 에 대하여 식을 정리하면 다음과 같다.

$$ \cos{\phi} = -\frac{I_1^2-I_2^2 - I_3^2 }{2I_2I_3} $$

코사인의 특성을 이용하면 $\cos{(180 - \phi)}= -\cos{\phi}$ 이고 $\theta = 180 - \phi$ 이므로 $\cos{(180 - \phi)}$ 를 $\cos{\theta}$ 로 치환한 뒤 $\cos{\phi}$에 대하여 정리하면 $\cos{\phi} = -\cos{\theta}$ 가 된다.

앞에서 구한 $\cos{\phi}$ 를 $-\cos{\theta}$로 치환한 뒤 $\cos{\theta}$에 대하여 정리 하면 역률을 $\cos{\theta}$ 를 다음과 같음을 알 수 있다.

$$ \cos{\theta} = \frac{I_1^2-I_2^2 - I_3^2 }{2I_2I_3} $$

유효전력

앞에서 우리는 유효전력을 구하기 위한 필요한 3가지 값을 측정 또는 계산 하였다.

  • 부하에 인가되는 전압

$$ V_{L} = R \times I_2 $$

  • 부하에 흐르는 전류

$$ I_L = I_3 $$

  • 역률 $$ \cos{\theta} = \frac{I_1^2-I_2^2 - I_3^2 }{2I_2I_3} $$

이제 위의 세 값을 모두 곱한 곱하면 유효전력을 구할 수 있다.

$$ P = R \times I_2 \times I_3 \times \frac{I_1^2-I_2^2 - I_3^2 }{2I_2I_3} $$

약분하여 정리하면 다음과 같은 식을 얻을 수 이다.

$$ P = \frac{R}{2} \times (I_1^2-I_2^2 - I_3^2) $$

결론

전류계 3개를 용하여 부하에서 소비되는 전력을 구하는 공식은 다음과 같다.

$$ P = \frac{R}{2} \times (I_1^2-I_2^2 - I_3^2) $$

3 전압계법 - 단상 전력을 측정하는 방법

개요

직류(DC) 회로에서 전력을 구하려면 부하전압(부하에 인가되는 전압)과 부하전류(부하에 흐르는 전류)의 곱으로 계산할 수 있지만 교류(AC) 회로에서 부하전압과 부하전류간 위상차가 존재하기 때문에 전원측에서 공급하는 전력과 실제 부하에서 소비되는 전력과 크기가 다르다. 교류 회로에서는 전원측에서 공급되는 전력을 피상전력($P_a$)이라고 하고 실제 부하에서 소비되는 전력을 유효전력($P$)이라고 한다. 피상전력으로부터 유효전력을 계산하기위해 역률($\cos{\theta}$)을 곱해주어야 한다.

$$ P = VI\cos{\theta} $$

역률은 부하전압과 부하전류의 위상차를 코사인 값으로 나타낸 것이다. 역률은 피상전력에 대한 유효전력의 비로 나타낼 수 있다.

$$\cos{\theta} = \frac{P}{P_a}$$

앞서 설명한 바와 같이 유효전력을 측정 하기 위해서는 부하에 인가되는 전압, 전류 그리고 역률을 알아야 한다. 전압계 3개를 이용하여 유효전력을 측정하는 방법을 알아보자.

3 전압계법

아래와 같은 교류회로가 있다고 가정하자. 전원($V_{in}$) 과 부하($Z_L$) 사이에 하나의 직렬 저항과 3개의 전압계가 있다. $V_1$은 입력전압, $V_2$는 부하와 직렬로 연결된 저항 $R$에서의 전압강하, $V_3$는 부하에 인가되는 전압을 측정한다.

Three Voltmeter Method Circuit Diagram

부하전압 ($V$)

부하에 인가되는 전압은 저항 다음단에서 부하와 병렬로 전압계를 연결하고 전압계의 지시값을 읽으면 된다. ( 전류를 측정하기 위해 부하와 전원 사이에 직렬 저항을 추가 하였기 때문에 공급전압과 부하전압 사이에서 $V_2$ 만큼의 전압차가 발생한다. )

저항기에서의 전압강하($I$)

전원측의 공급 전압을 측정 했으니 이제 부하에 흐르는 전류를 구해보자. 저항에 흐르는 전류를 구하기 위해서는 저항 의 크기와 저항에서 발생하는 전압 강하를 측정해야 한다. 저항의 크기와 저항에서의 전압 강하를 알면 다음 식을 통해 전류를 구할 수 있다.

$$ I = \frac{V_2}{R} $$

저항과 전압계를 병렬로 연결하고 전압계의 지시값($V_2$)을 읽는다.

저항은 부하와 직렬로 연결되어 있고 직렬로 회로에서는 전류가 일정 하기 때문에 저항에 흐르는 전류와 부하에 흐르는 전류는 같다.

공급전압

전원측에서 공급되는 전압($V_1$)을 측정해보자. 다음 그림과 같이 전압계 저항기 앞단에 전원과 병렬로 연결하고 전압계에 지시값을 읽으면 전원 측에서 공급되는 전압을 알수 있다.

역률 ($\cos{\theta}$)

이제 부하에 인가되 전압 $V_3$ 와 부하에 흐르는 전류 ($I$ = $\frac{V_2}{R})$를 알았으니 역률 $\cos{\theta}$를 알면 부하에서 소비되는 전력 $P$를 구할 수 있다. 앞서 측정한 공급전압($V_1$), 저항에서의 전압강하($V_2$), 부하전압($V_3$)을 가지고 역률을 구해보자.

$V_2$를 기준으로 페이저도를 그려보자.

  • 대부분의 부하는 지상 부하이기 때문에 부하 $Z_L$를 지상 부하라고 가정한다.
  • 부하에 인가되는 전압 $\hat{V_3}$ 는 저항에서 강하되는 전압 $\hat{V_2}$ 보다 지상이다. $\hat{V_2}$와 $\hat{V_3}$위상차를 $\phi$ 라고 하자.
  • 직류회로에서 모든 전압의 합은 0 이므로 $\hat{V_1}$ 을 다음과 같이 표현할 수 있다.

$$ \hat{V_1} = \hat{V_2} + \hat{V_3} $$

  • 저항 $R$은 순저항 부하이기 때문에 $R$에 인가되는 전압 $\hat{V_2}$는 회로에 흐르는 전류($\hat{I}$)와 위상이 같다.

다음과 같은 페이저도를 그릴 수 있다.

Three Voltmeter Method Circuit Diagram

페이저도를 통해 $\hat{V_3}$와 $\hat{I}$ 사이의 역률각 $\theta$는 다음과 $180 - \phi$ 임을 알 수 있다.

$$ \theta = 180 - \phi $$

우리가 알고 있는 정보로는 $\theta$ 를 직접 구할 수 없지만 $\phi$ 구한 후 위식에 대입하여 역률각 $\theta$를 알 수 있다.

$\phi$ 가 속해 있는 삼각형의 세 변의 길이를 알고 있으므로 코사인 법칙을 이용하여 $\phi$ 를 구해 보자.

코사인 법칙을 통해 삼각형에서 두 변의 길이와 그 사잇각으로 부터 제 3변의 길이 구하거나 삼각형 세변의 길이를 알고 있을 경우 세 각을 크기를 알 수 있다.

$$ V_1^2 = V_2^2 + V_3^2 - 2V_2V_3\cos{\phi} $$

$\cos{\phi}$ 에 대하여 식을 정리하면 다음과 같다.

$$ \cos{\phi} = -\frac{V_1^2-V_2^2 - V_3^2 }{2V_2V_3} $$

코사인의 특성을 이용하면 $\cos{(180 - \phi)}= -\cos{\phi}$ 이고 $\theta = 180 - \phi$ 이므로 $\cos{(180 - \phi)}$ 를 $\cos{\theta}$ 로 치환한 뒤 $\cos{\phi}$에 대하여 정리하면 $\cos{\phi} = -\cos{\theta}$ 가 된다.

앞에서 구한 $\cos{\phi}$ 를 $-\cos{\theta}$로 치환한 뒤 $\cos{\theta}$에 대하여 정리 하면 역률을 $\cos{\theta}$ 를 다음과 같음을 알 수 있다.

$$ \cos{\theta} = \frac{V_1^2-V_2^2 - V_3^2 }{2V_2V_3} $$

유효전력

앞에서 우리는 유효전력을 구하기 위한 필요한 3가지 값을 측정 또는 계산 하였다.

  • 부하에 인가되는 전압

$$ V_3 $$

  • 부하에 흐르는 전류

$$ \frac{V_2}{R} $$

  • 역률 $$ \frac{V_1^2-V_2^2 - V_3^2 }{2V_2V_3} $$

이제 위의 세 값을 모두 곱한 곱하면 유효전력을 구할 수 있다.

$$ P = V_3 \times \frac{V_2}{R} \times \frac{V_1^2-V_2^2 - V_3^2 }{2V_2V_3} $$

약분하여 정리하면 다음과 같은 식을 얻을 수 이다.

$$ P = \frac{1}{2R} \times (V_1^2-V_2^2 - V_3^2) $$

결론

3전압계법을 이용하여 부하에서 소비되는 전력을 구하는 공식은 다음과 같다.

$$ P = \frac{1}{2R} \times (V_1^2-V_2^2 - V_3^2) $$

GDM 모니터 설정 변경하기

사용자 모니터 설정은 ~/.config/monitors.xml에 저장된다. GNOME에서 사용하는 모니터 설정을 GDM에도 적용하자.

sudo cp ~/.config/monitors.xml ~gdm/.config/monitors.xml
sudo chmod gdm:gdm  ~gdm/.config/monitors.xml

monitors.xml를 복사해도 설정이 적용 안되는 경우 아래와 같이 GDM과 GNOME에서 사용하는 디스플레이 서버가 같은지 확인해 보자. 다음과 같은 경우일 수 있다.

  • GDM은 Wayland를 사용하고 GNOME은 Xorg를 사용하는 경우
  • GDM은 Xorg를 사용하고 GNOME은 Wayland를 사용하는 경우

Xorg와 Wayland에서 사용하는 monitors.xml 파일의 포멧이 틀려서 발생하는 문제다.

GNOME에서 사용하는 X 서버로 GDM을 변경 하도록 한다.

Xorg에서 GDM을 시작 하고자 할때,

cat /etc/gdm/custom.conf

[daemon]
WaylandEnable=false

Wayland에서 GDM을 시작 하고자 할때, cat /etc/gdm/custom.conf

[daemon]
# WaylandEnable=false

이동평균에 대하여 (feat. Python)

이전에 평균에 대한 글을 쓴 적이 있다. 그 다음 편으로 예정 되어 있던 이동 평균에 대한 알아보자.

이동평균

통계에서 이동평균은 전체 데이터 집합의 여러 하위 집합에 대한 일련의 평균을 만들어 데이터 요소를 분석하는데 사용되는 계산이다. 금융에서 이동평균은 분석에 일반적으로 사용되는 주식 차트 이다.

  • 이동평균은 기술분석에서 일반적으로 사용되는 주식 지표이다.
  • 주식의 이동 평균을 계산하는 이유는 지속적으로 업데이트되는 평균가적을 생성하여 지정된 기간동안의 가격 데이터를 평활화 하기 위해서이다.
  • 단순 이동평균은 과거의 특정 일수 동안 주저진 가격 세트의 산술 평균이다. 예를들어 15, 30, 100일 또는 200일이 될 수 있다.
  • 결과값이 지연되어 나타나는 경향이 있다.
  • 이동평균의 기간이 길어질 수록 지연이 커진다.
  • 최근값에 더 많은 가중치를 두려면 가중이동 평균이나 지수이동평균을 사용해야한다.

지난번 알아 보았던 평균과 평균 필터는 전체 값중 중간 값을 알수 있기 때문에 유용하지만 전체 샘플의 수가 많으면 최근 값이 평균값에 미치는 영향이 작아 지기때문에 누적 데이터가 많아 질수록 현재의 변화 상태를 반영하지 문하는 문제가 있다.

이 포스트에서 사용된 Raw 데이터는 Bitcoin data at 1-min intervals from select exchanges, Jan 2012 to March 2021에서 다운 받은 데이터 중 최근 365일 데이터를 사용하였다.

주식에서

주식 가격의 추이 분석에 사용된다. 보통 주식 가격의 변화는 매우 빠르고 자주 바뀌기 때에 단기간의 변화를 평활화 하여 가경의 변동 추이를 분석 하기 위해 사용된다. 단기적인 추세 분석을 위해 10일, 20일, 50일 이동평균을 사용하고 장기적인 추세 분석을 위해 100일 또는 200일 이동평균을 사용한다.

공학에서

디지털 신호처리에서 잡음을 제거하고 데이터의 평활화하는데 사용된다. 저대역 필터(Low Pass Filter) 역할을 한다.

단순이동평균

단순하게 평균을 구하는 시점에서 이전 $N$ 샘플 이전 까지의 평균을 구하는 방법이다.

all_frames = pd.read_csv('data.csv')
df = all_frames.tail(365)
price = df.Close
sma = price.rolling(N, min_periods=1).mean()

$$ SMA_n = \frac{p_{N-n+1} + p_{N-n+2} … + p_n}{n} $$

아래는 $N$ 이 15, 30, 60, 90, 120 일때의 단순 이동평균 그래프다.

Simple Moving Average

단순 이동평균은 평균을 계산하는데 사용되는 데이터의 가중치가 같다. 과거의 데이터가 극단적으로 높거나 낮을 경우 과거 데이터에 의한 현재 데이터의 외곡 현상이 나타날 수 있다. 즉, 최근 데이터와 같은 가중치를 가지기 때문에 평균선이 현재 데이터변화 추이를 제대로 반영하지 못한다는 단점이 있다.

누적이동평균

누적 이동평균은 우리가 알고 있는 일반적인 평균과 같다. 즉, 처음 측정 시점부터 현재 까지의 모든 데이터의 평군이다.

보통 특정 주식이나 제품의 가격에 대해 현재까지의 평균 거래 가격등을 구하는데 사용된다.

누적 이동평균은 평균을 계산하는데 사용되는 데이터에 대한 가중치가 같다.

$$ CMA_n = \frac{x_1 + … + x_n}{n} $$

all_frames = pd.read_csv('data.csv')
df = all_frames.tail(365)
price = df.Close
cma = price.expanding().mean()

Cumulative Moving Average

가중이동평균

단순 이동평군에서 모든 데이터에 같은 가중치를 사용함에서 오는 단점을 해결하기 위한 이동 평균이다. 보통 실생활에서는 과거의 데이터 보다 최신 데이터가 더 중요하기 때문에 $n$ 일 동안의 온도변화에 대한 가중이동평균을 구하기 다고 가정하면 최신 날짜인 $n$일의 가중치는 $n$ 이고 그다음 최신 날따인 $n - 1$ 일의 온도에 대한 가중치는 $n - 1$ 이다. 가중치는 날짜가 지남에 따라 $1$씩 줄어 들어 최종적으로 $1$이 될때까지 줄어 든다. $n$일 이전 온도 데이터는 가중이동평균의 계산 결과에 영향을 주지 않는다.

$$ WMA_M = \frac{np_M + (n-1)p_{M-1} + … + 2p_{((M - n) + 2)} + p_{((M-n) + 1)} }{n + (n - 1) + … + 2 + 1} $$

$$ Total_{M+1} = Total_M + p_{M+1} - p_{M-n+1} $$

all_frames = pd.read_csv('data.csv')
df = all_frames.tail(365)
price = df.Close
sma = price.rolling(N).apply(lambda x: np.dot(x, w)/w.sum(), raw=True)

아래는 $N$ 이 15, 30, 60, 90, 120 일때의 가중이동평균 그래프다.

Weighted Moving Average

지수이동평균

가중이동평균의 단점이라고 할 수 있는 $n$ 개 이전의 데이터가 평균 계산 결과에 영향을 주지 않는 문제를 해결 하기 위해 산술적으로 감소하는 가중치가 아닌 지수적으로 감소하는 가중치를 적용한 것이다. 가중치는 기하급수적으로 감소하지만 결코 0이 도달 하지는 않는다.

$$ EMA_n = \alpha X_n + (1 - \alpha)EMA_{n-1} $$

여기서 계수 $\alpha$ 를 평활계수 (smooth factor) 라고 부른다. $\alpha$ 가 커질수록 최근 샘플에 주어지는 가중치가 커진다. $\alpha$ 는 0과 1사이의 값을 가져야 한다. $\alpha$ 가 커지면 최근 데이터의 가중치가 커지고 이전 데이터의 가중치가 더 빠르게 줄어 든다.

$\alpha$ 값은 임의로 선택 가능 하지만 보통 다음 값을 사용한다.

$$ \alpha = \frac{2}{(N+1)} $$

하지만 반드시 ${2}/{(N+1)}$ 를 사용해야 하는것은 아니다. 입력 값이나 원하는 결과값에 따라 조절 할 수 있다. 예를 들어 최근 값 보다는 이전 값에 더 많은 가중치를 두고 싶다면 $\alpha$ 값을 $0.00001$ 로 두고 계산 할 수도 있다.

all_frames = pd.read_csv('data.csv')
df = all_frames.tail(365)
price = df.Close
sma = price.ewm(alpha=2/(N+1)).mean()

아래는 $N$ 이 15, 30, 60, 90, 120 일때의 지수이동평균 그래프다.

Exponential Moving Average

가중치 변화

다음 그래프는 $N$이 15일 때 각 이동 평균의 가중치 변화를 그래프로 나타낸 것이다.

Weights for Moving Average

지수 이동 평균의 평활 지수는 $\frac{2}{(N+1)}$ 로 설정 하였다. $N$이 15이기 때문에 $\frac{1}{8}$ 이 된다.

이 그래프를에서 $N = 15$ 임으로 중간 값인 $7$ 일때의 가중치를 보면 단순이동평균(SMA)의 가중치와 지수이동평균(EMA)의 가중치가 같다.

예제

2020년 3월 부터 2021년 3월 까지의 비트 코인 시세를 각 이동평균 계산법으로 계산하면 다음과 같은 그래프를 얻을 수 있다. ($N=15$)

Moving Average

차트를 만드는데 사용된 소스코드는 Python Moving Average Examples with Pandas에서 확인할 수 있다.