<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Hyeon-II</title>
        <link>https://velog.io/</link>
        <description>Hi, there 👋</description>
        <lastBuildDate>Mon, 15 Dec 2025 12:29:47 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Hyeon-II</title>
            <url>https://velog.velcdn.com/images/hyeon-ii/profile/86516b18-02eb-4c39-a7ef-9cbab598ca0f/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Hyeon-II. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyeon-ii" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Structural Testing]]></title>
            <link>https://velog.io/@hyeon-ii/Structural-Testing</link>
            <guid>https://velog.io/@hyeon-ii/Structural-Testing</guid>
            <pubDate>Mon, 15 Dec 2025 12:29:47 GMT</pubDate>
            <description><![CDATA[<h2 id="structural-testing">Structural Testing</h2>
<p>Structural testing을 이해하기 위해서는 먼저 &quot;프로그램이 왜 실패하는가?&quot;, &quot;어떤 조건에서 실패가 발생하는가?를 짚어야 한다.</p>
<p>사용자가 기대한 결과를 제공하지 못하는 경우를 프로그램 실패 <strong>(failure)</strong>라고 정의한다. 예를 들어 정상적으로 작동해야 하는 기능이 엉뚱한 값을 출력하거나, 프로그래밍 멈추거나, 충돌하는 것까지 모두 여기에 포함되어 있다.</p>
<p>이러한 실패는 결국 코드 내부에 존재하는 <strong>fault(버그)</strong>가 특정 입력에 의해 실행되면서 실패로 발전하는 과정을 갖는데, 이를 PIE 모델로 보면 아래와 같다.</p>
<ul>
<li><strong>Execution</strong>: 프로그램 실행이 해당 버그가 포함된 부분까지 도달해야 한다.</li>
<li><strong>Infection</strong>: 그 버그가 잘못된 상태를 만들어야 한다.</li>
<li><strong>Propagation</strong>: 그 잘못된 상태가 사용자에게 보이는 잘못된 출력으로 이어져야 한다.</li>
</ul>
<p>이 세 단계 중 하나라도 충족되지 않으면 버그는 찾을 수 없게 된다. 즉, 테스트가 버그를 드러내려면 &quot;버그를 실행시키고 전파되도록 만드는 입력&quot;&quot;을 찾아야 한다.</p>
<h3 id="software-test-목적">Software Test 목적</h3>
<p>테스트는 &quot;미리 정의된 입력 (test case)과 기대 출력 (expected output)&quot;을 비교하여 실패를 찾아내는 활동이다.
이때 동일한 프로그램이라도</p>
<ul>
<li>사용자 요구사항 기반 테스트</li>
<li>코드 구조 기반 테스트</li>
</ul>
<p>두 관점을 모두 사용해야 결함을 충분히 탐지할 수 있다.</p>
<p>Blackbox가 요구사항 충족 여부에 초점을 둔다면, whitebox는 코드 내부 구조를 모두 충분히 실행해보는 것에 초점을 둔다.
구조 기반 테스트는 프로그램의 내부 구조, 즉 소스 코드 자체를 기준으로 테스트 케이스를 설계하는 기법이다. 이는 블랙박스 테스트와 달리 코드를 직접 읽고, 그 코드의 제어 흐름과 데이터 흐름을 모델링하여 테스트를 만든다.</p>
<h3 id="program-failure">Program Failure</h3>
<p>사용자는 프로그램이 모든 입력에 대해, 주어진 시간 안에, 올바른 출력을 제공하기를 기대한다.</p>
<p>프로그램 실패란 프로그램 실행 결과가 요구사항을 만족하지 못할 때 발생한다.</p>
<ul>
<li>논리 오류 (assertion failure)</li>
<li>메모리 오류</li>
<li>리소스 누수</li>
<li>Deadlock, timeout 등 concurrency 오류</li>
<li>Crash (segmentation fault 등)</li>
</ul>
<p>테스트는 fault가 failure로 이어지는 세 단계를 모두 일으키는 입력을 찾아야 한다는 점에서 중요하다.</p>
<h3 id="testing">Testing</h3>
<p>테스트란</p>
<ul>
<li>입력 (test case)을 넣고</li>
<li>실제 출력 (actual output)을 얻어</li>
<li>기대 출력 (expected output)과 비교하여<ul>
<li>같으면 test success</li>
<li>다르면 test failure</li>
</ul>
</li>
</ul>
<p>여기서 <strong>test oracle</strong>이란 <strong>정답을 제공하는 기준</strong>이다.</p>
<h3 id="foundation-of-software-testing">Foundation of Software Testing</h3>
<p>블랙박스와 화이트박스 테스트의 관점을 나누기 위해 다음 세 가지를 정의한다.</p>
<ol>
<li><strong>Requirement Spec</strong>: 시스템이 해야 할 일을 정의한다.</li>
<li><strong>Program</strong>: 명세를 구현한 실제 소스 코드</li>
<li><strong>Test Case</strong>: 입력과 예상 출력의 조합</li>
</ol>
<p>Whitebox 테스트는 프로그램의 내부 구조를 보고 테스트 케이스를 선택한다는 점이 핵심이다.</p>
<p>다양한 테스트 기법이 있으나 비용과 효과 측면에서 whitebox testing인 brach coverage가 가장 효율성이 크다.</p>
<h3 id="structural-testing-1">Structural Testing</h3>
<p>Structural testing에서는 보통 아래 두 모델을 사용한다.</p>
<ol>
<li>Control Flow Graph (CFG)</li>
<li>Data Flow Graph (Defs &amp; Uses)</li>
</ol>
<p>소스 코드를 기반으로 그래프를 생성한 뒤에는 이 그래프를 기반으로 커버리지 기준을 충족시켜야 한다.</p>
<ol>
<li>Node Coverage</li>
<li>Edge Coverage</li>
<li>Loop Coverate</li>
<li>Condition Coverage</li>
<li>Path Coverate</li>
</ol>
<p>그래프 기반 모델링이 구조 기반 테스트의 핵심이다.</p>
<h2 id="graph-basics">Graph Basics</h2>
<p>그래프는 소프트웨어 구조를 일반화하여 표현할 수 있는 강력한 수단이다. 테스트는 결국 그래프를 어떻게 방문할 것인가의 문제이다.</p>
<h3 id="definition-of-a-graph">Definition of a Graph</h3>
<p>그래프는 다음 요소로 구성된다.</p>
<ul>
<li><strong>Node</strong>: 실행 지점, 문장 또는 basic block</li>
<li><strong>Edge</strong>: 제어 흐름 (a → b)</li>
<li><strong>초기 노드</strong> $(N_0)$</li>
<li><strong>종료 노드</strong> $(N_f)$</li>
<li><strong>경로</strong>: 노드들의 연속 $[n_1, n_2, \cdots, n_M]$<ul>
<li>길이: edge 개수</li>
<li>subpath: 경로의 부분 경로</li>
<li>Reach ($n$): $n$에서 도달 가능한 그래프 부분</li>
</ul>
</li>
</ul>
<h4 id="test-path">Test Path</h4>
<p>초기 노드에서 시작하여 마지막 노드에서 끝나는 실제 실행 흐름을 test path라고 한다. 특히, 하나의 진입점과 하나의 종료점을 갖는 그래프를 <strong>SESE (Single-Entry Single-Exit)</strong>라고 한다.</p>
<p>Test path가 특정 노드나 엣지를 포함할 때, 해당 노드/엣지를 <strong>visit</strong> 한다고 표현한다. 또한 test path가 subpath 전체를 순서대로 포함할 때 <strong>tour</strong>라고 표현한다.</p>
<h2 id="control-flow-coverage">Control Flow Coverage</h2>
<h3 id="node-and-edge-coverage">Node and Edge Coverage</h3>
<p>모든 노드/엣지를 한 번 이상 방문하면 충족된다. Edge coverage가 Node coverage보다 조금 더 강력하다.</p>
<h4 id="edge-pair-coverage">Edge-Pair Coverage</h4>
<p>길이가 2인 모든 subpath를 방문하면 충족된다. 이때 test requriement는 다음과 같이 표현된다. $\text{TR}_\text{EPC}=[0,1,2], [1,2,3]$ 등</p>
<h3 id="loops-in-coverage">Loops in Coverage</h3>
<p>Loop가 있으면 경로가 무한히 길어지므로 complete path coverage는 불가능하다. 이를 다루기 위해 loop를 1회만 수행하거나, prime path를 도입하여 가장 합리적인 path를 선택하는 등의 방법이 제시되었다.</p>
<h4 id="simple-path-vs-prime-path">Simple Path vs Prime Path</h4>
<ul>
<li>내부에 중복 노드가 없는 경로를 <strong>Simple Path</strong>라고 한다.</li>
<li>Simple path 중 다른 simple path의 proper subpath가 아닌 것 즉, 가장 긴 유효 simple path를 <strong>Prime Path</strong>라고 한다.</li>
</ul>
<p><strong>Prime Path Coverage</strong>는 EC, EPC, NC를 모두 포함한다.</p>
<h4 id="round-trip-coverage">Round Trip Coverage</h4>
<p>시작과 끝이 같은 prime path를 <strong>Round Trip Coverage</strong>라고 한다. Loop 중심 coverage를 표현하지만, NC/EC보다 약한 경우도 있다.</p>
<h4 id="sidetrip--detours">Sidetrip &amp; Detours</h4>
<p>Subpath를 순서대로 포함하되, 중간에 다른 노드를 거쳤다가 다시 돌아올 수 있다. (sidetrip)</p>
<p>Subpath의 노드들을 순서대로 방문하는 것을 detour라고 한다.</p>
<h3 id="pure-structural-coverage의-한계">Pure Structural Coverage의 한계</h3>
<p>Branch coverage 100%를 달성해도 의미적 오류를 잡을 수 없다. 즉, 구조적 기준만으로는 의미적 오류를 잡을 수 없다.</p>
<h2 id="data-flow-coverage">Data Flow Coverage</h2>
<p>데이터 흐름 기반 테스트는 값이 어디에서 정의되고 어떻게 사용되는지를 추적함으로써 테스트가 충분한지 판단한다. 단순히 노드와 엣지 같은 구조를 보는 구조적 테스트와 달리, 값이 실제로 어떻게 흐르는지 분석한다는 점에서 의미적인 오류를 찾는 데 효과적이다.</p>
<ul>
<li>Goal: 모든 변수들이 올바르게 계산되는지 보장하는 것</li>
<li>Definition: 변수가 메모리에 저장되는 시점</li>
<li>Use: 변수에 접근하는 (읽는) 시점</li>
</ul>
<h3 id="du-pair">DU pair</h3>
<p>특정 변수를 정의하고 사용하는 지점이 $l_i$와 $l_j$일 때 두 지점을 연결하는 def-clear path가 존재해야 DU-pair가 성립한다.</p>
<p><strong>def-clear</strong>란 경로 위에서 변수가 다시 정의되지 않는 경로를 뜻한다. 즉, $l_i$에서 정의된 값이 손상되지 않고 $l_j$까지 도달하는 것을 의미한다.</p>
<p><strong>DU-Path</strong>는 DU-pair를 만족시키는 simple path (자시 반복이 없는 경로)를 말한다. 변수 $v$에 대해 def-clear 조건을 만족해야 한다. 테스트 경로가 특정 DU-Path를 따랐다고 인정되려면 다음 조건을 만족해야 한다.</p>
<ul>
<li><strong>DU-Tour</strong>: 테스트 경로가 해당 DU-Path를 순서대로 포함하면서, 전체 경로가 $v$에 대해 def-clear 상태여야 한다.</li>
<li>다른 커버리지 기준과 마찬가지로 sidetrip (다른 경로로 샜다가 다시 돌아오는 것)을 허용할 수 있다. 점검 방식은 이전의 prime path touring과 동일하다.</li>
</ul>
<h3 id="data-flow-coverage-1">Data Flow Coverage</h3>
<p>데이터 흐름 기반 커버리지는 다음 세 단계로 구성된 테스트 강도 계층 구조를 갖는다.</p>
<ol>
<li><strong>All-defs Coverage (ADC)</strong>: 모든 정의가 적어도 하나의 use에 도달해야 한다. 즉, 정의되었는데 사용되지 않는 값이 있어서는 안 된다.</li>
<li><strong>All-uses Coverage (AUC)</strong>: def가 도달 가능한 모든 use를 test path가 커버해야 한다. 각 def는 가능한 모든 use와의 조합을 만족해야 한다.</li>
<li><strong>All-du-paths Coverage (ADUP)</strong>: def와 use 사이 가능한 모든 def-clear du-path를 탐색해야 한다. AUC보다 더 강력하고, 데이터 흐름 기반 기준 중 가장 강도 높은 기법이다.</li>
</ol>
<p>구조 기반 테스팅에서는 prime path coverage가 매우 강력하지만, 데이터 흐름 기반 기준으로는 ADUP가 가장 강력하다.</p>
<h2 id="structural-coverage-for-source-code">Structural Coverage for Source Code</h2>
<h3 id="control-flow-graph">Control Flow Graph</h3>
<p>CFG는 프로그램의 실행 가능한 모든 흐름을 노드와 엣지로 시각화한 모델이다.</p>
<ul>
<li>Node: 분기가 없는 연속 실행 구문</li>
<li>Edge: 제어 흐름 (분기, 반복 등)</li>
</ul>
<p>예를 들어 if 문에서 각 return은 독립된 노드로 취급되어야 한다.</p>
<h4 id="edge-coverage">Edge Coverage</h4>
<p>CFG의 모든 edge를 방문해야 한다.</p>
<h4 id="edge-pair-coverage-1">Edge-Pair Coverage</h4>
<p>길이 2인 모든 subpath를 방문해야 한다. EC에서 보이지 않던 숨겨진 버그를 EPC에서 탐지할 수 있다.</p>
<h4 id="prime-path-coverage">Prime Path Coverage</h4>
<p>Simple path 중 더 이상 확장될 수 없는 path를 모두 커버해야 한다. Primt path coverage에서 infeasible 경로가 존재할 수 있다는 것을 밝힌다.</p>
<p>CFG 기반 테스트는 연구가 잘 되어 있으며 비교적 체계적이다. 하지만 실제 코드를 CFG로 옮길 때는 subtle 설계 결정이 필요하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Blackbox Testing]]></title>
            <link>https://velog.io/@hyeon-ii/Blackbox-Testing</link>
            <guid>https://velog.io/@hyeon-ii/Blackbox-Testing</guid>
            <pubDate>Thu, 11 Dec 2025 02:36:01 GMT</pubDate>
            <description><![CDATA[<h2 id="systematic-testing">Systematic Testing</h2>
<p>Systematic testing은 테스트를 시스템처럼 조직적으로 수행하기 위한 절차를 의미한다. 주요 구성 요소는 다음과 같다.</p>
<ul>
<li>테스트 케이스 선택 및 생성</li>
<li>테스트 실행과 결과 문서화</li>
<li>결과 평가 (가능하다면 자동화)</li>
<li>테스트 종료 시점 결정 (언제 &quot;충분히&quot; 테스트했다고 볼 것인가?)</li>
</ul>
<p>완전한 테스트는 현실적으로 불가능하기 때문에, 특정 criterion을 정의하고 그에 따라 테스트를 수행한다. (예를 들어, 모든 if 문이 true/false 양쪽으로 한 번씩 실행되도록 테스트하기)</p>
<h3 id="kinds-of-tests-black-box-vs-white-box-testing">Kinds of Tests: Black Box vs White Box Testing</h3>
<p>Testing은 black box testing과 white box testing으로 나눌 수 있다.</p>
<p><strong>Black box testing</strong>은 코드를 보지 않고 요구사항과 명세서를 기반으로 테스트를 작성하는 기법이다. 이는 개발 과정과 병렬로 진행할 수 있기 때문에 대형 프로젝트에서 유리하다.</p>
<p><strong>White box testing</strong>은 코드를 보고 실제 로직과 구조를 기반으로 테스트를 작성하는 기법이다.</p>
<h2 id="black-box-testing">Black Box Testing</h2>
<p>Black box testing은 functional specification 정보를 사용한다.</p>
<h3 id="functional-specification">Functional Specification</h3>
<p>소프트웨어 요구사항은 일반적으로 다음 세 가지를 포함한다.</p>
<ul>
<li><strong>입력</strong>: 어떤 입력을 받을 수 있는가.</li>
<li><strong>행동</strong>: 입력을 처리할 때 어떤 동작을 해야 하는가.</li>
<li><strong>출력</strong>: 어떤 출력을 생성해야 하는가.</li>
</ul>
<p>이 세가지 요소를 기반으로 세 가지 black box test가 생긴다.</p>
<h3 id="three-kinds-of-black-box-methods">Three Kinds of Black Box Methods</h3>
<h4 id="input-coverage-testing">Input Coverage Testing</h4>
<p>입력 공간을 분석해서 입력에 대한 테스트를 체계적으로 커버하는 기법</p>
<p>테스트 기법은 다음과 같다.</p>
<ul>
<li><strong>Exhaustive Testing</strong>: 입력 가능한 모든 조합을 테스트하는 방법<ul>
<li>예를 들어 32-bit 정수 두 개를 입력으로 받는 경우 약 $1.6\times10^{19}$개의 조합이 존재한다. 이처럼 현실적으로 불가능한 경우가 대부분이다.</li>
<li>그러나 입력 도메인이 0과 99 사이의 값으로 제한된 경우 자동화가 가능하다. 완전 검사가 가능한 경우는 매우 드물다.</li>
</ul>
</li>
<li><strong>Input Partitioning</strong>: 입력 공간을 의미 있는 그룹으로 나누고, 각 그룹에서 대표 입력값을 선택하는 방법<ul>
<li>전형적이며 가장 많이 쓰이는 black box 기법이다.</li>
<li>두 정수 $x, y$를 입력받아, $x$ 이하의 수 중 $y$로 나누어 떨어지는 모든 수를 출력하라. 단, $x$ 또는 $y$가 0이면 0만 출력해야 하는 경우 입력을 $x=0, y=0, x\neq0\cap y\neq0$ 같은 특수 케이스로 ㄴ누어 양수와 음수까지 확장 가능한 partition으로 나눈다.</li>
<li>Partitioning은 입력 종류를 모두 테스트 했는지 명확하게 알 수 있다. 또한 여러 관점에서 partition할 수 있어 설계 실수도 발견할 수 있다. Partitioning을 통해 단순 대표 입력만 테스트해도 충분한 신뢰를 확보할 수 있다.</li>
</ul>
</li>
<li><strong>Shotgun Testing</strong>: 랜덤 입력을 다량 생성하는 방식의 난수 기반 테스트<ul>
<li>예기치 못한 입력 조합을 탐색할 수 있고, 특정 버그를 운 좋게 발견할 수 있다. 하지만 체계성이 없고 언제 테스트가 끝났는지 판단할 수 없다.</li>
<li>이러한 이유로 shotgun은 단독으로 쓰기 보다는 input partitioning을 강화하는 데 사용한다. 즉, 각 partition 안에서 다양한 random 입력을 추가로 테스트한다.</li>
</ul>
</li>
<li><strong>Input Robustness Testing</strong>: 입력이 잘못되어도 프로그램이 죽지 않는지 확인하는 테스트로, random garbage input과 boundary value testing 두 가지가 있다.</li>
<li><strong>Input Boundary Testing</strong>: 실제 프로그램 오류가 주로 입력 범위 경계에서 발생한다. Boundary testing은 체계적이며, 경계값을 모두 테스트하면 종료한다는 명확한 기준이 있다.</li>
</ul>
<h4 id="output-coverage-testing">Output Coverage Testing</h4>
<p>출력 가능한 값들을 분석해서 각각을 유도하는 입력을 설계하는 기법으로, 입력 중심이 아닌 출력 도메인을 기반으로 테스트한다. 이때 요구사항을 깊이 있게 분석해야 하기 때문에 상당히 복잡하지만 문제 발견 능력은 매우 뛰어나다. 또한 출력의 종류가 적을 때에는 exhaustive output testing이 가능하다.</p>
<ul>
<li>Input coverage와 비교해보면, 예를 들어 <strong>&quot;두 입력이 같으면 1, 다르면 0을 출력&quot;</strong>해야 하는 요구사항이 있을 때 input partitioning으느 수많은 입력 경우의 수를 따져보아야 하지만, output coverage는 0 또는 1 두 개의 테스트로 완전 커버가 가능하다.</li>
</ul>
<p>Output partition만 설정하면 끝이 아니다. 각 partition을 발생시키는 입력을 역으로 찾아야 한다. 이 과정이 매우 어렵고 시간도 오래 걸린다. 하지만 이 과정에서 다음과 같은 문제를 발견할 수 있다.</p>
<ul>
<li>특정 출력 class가 실제로는 발생할 수 없음</li>
<li>요구사항이 애초에 잘못 정의됨</li>
<li>partition이 잘못 설계됨</li>
</ul>
<p>입력 파일이 여러 개거나 출력이 여러 개라면, input stream, output stream을 독립적인 partition 그룹으로 보고 각각에 대해 별도의 input/output partitioning을 수행해야 한다.</p>
<h4 id="functionality-coverage-testing">Functionality Coverage Testing</h4>
<p>요구사항을 작은 단위로 나누어 각 기능 단위를 독립적으로 테스트하는 기법</p>
<p>요구사항은 보통 여러 기능이 묶여 있지만 testability는 기능 단위로 분할할 때 높아진다. 이를 requirement partitioning이라고 한다.</p>
<p>예를 들어, 요구사항이 <strong>&quot;두 정수 $x, y$를 입력받아, $x$ 이하의 수 중 $y$로 나누어 떨어지는 모든 수를 출력하라. 단, $x$ 또는 $y$가 0이면 0만 출력한다.&quot;</strong>라고 한다면 요구사항은 다음과 같이 분해된다.</p>
<ul>
<li>두 정수를 입력받아야 한다.</li>
<li>출력은 0개 이상의 정수여야 한다.</li>
<li>출력값은 모두 $x$ 이하여야 한다.</li>
<li>출력값은 모두 $y$로 나누어 떨어져야 한다.</li>
<li>조건을 만족하는 모든 값을 출력해야 한다.</li>
<li>$x=0$ 또는 $y=0$이면 출력은 무조건 0 하나여야 한다.</li>
</ul>
<p>이 여섯가지 요구사항에 대해 테스트 케이스가 각각 수 개씩 만들어진다. 그 중 조건을 만족하는 가장 단순한 케이스로 테스트를 진행한다.</p>
<p>Functionality Coverage는 요구사항 기반 테스트이므로 acceptance test와는 다르다. 요구사항을 독립 요소로 취급하지만 실제로는 기능 간 상호작용이 존재할 수 있으므로 완전 대체할 수 없다. 그래도 테스트 완료 기준이 명확하다. (각 요구사항에 대해 최소 하나의 테스트가 존재할 것)</p>
<h3 id="test-case-design의-원칙">Test Case Design의 원칙</h3>
<p>Black box testing은 실험(experiment)이다. 따라서 실험 설계 원리를 따른다.</p>
<ul>
<li>변수(원인)를 분리하여 관찰해야 한다.<ul>
<li>테스트 입력을 단순하게 유지하고, 하나의 입력만 변화시키며 나머지는 동일하게 유지해야 한다. </li>
</ul>
</li>
<li>불필요한 변동을 제거해야 한다.<ul>
<li>임의의 복잡한 입력을 넣는 것은 오류 원인을 찾기 어렵게 만든다.</li>
</ul>
</li>
</ul>
<p>(가장 간단한 테스트를 사용하지 않으면 검증이 어려워진다.)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Introduction to Testing and Verification]]></title>
            <link>https://velog.io/@hyeon-ii/Introduction-to-Testing-and-Verification</link>
            <guid>https://velog.io/@hyeon-ii/Introduction-to-Testing-and-Verification</guid>
            <pubDate>Wed, 10 Dec 2025 11:41:53 GMT</pubDate>
            <description><![CDATA[<h2 id="testing-and-verification-are-hard">Testing and Verification are HARD</h2>
<p>현재 소프트웨어는 매우 복잡하며, 오류 발생 시 사회·경제적 손실이 막대하다. 다음 세 가지 실제 사례는 소프트웨어 오류가 얼마나 심각한 결과를 초래하는지 보여준다.</p>
<ul>
<li>Toyota 급가속 사고 (2010s) — 89명 사망, 12억 달러 벌금</li>
<li>Boeing 737 MAX 사고 (2018–2019) — 346명 사망, 기체 전 세계 운항 금지</li>
<li>CrowdStrike 장애 (2024) — 전 세계 IT 인프라 마비, 약 100억 달러 피해 추정</li>
</ul>
<h3 id="소프트웨어-검증이-어려운-이유">소프트웨어 검증이 어려운 이유</h3>
<p><strong>테스트 비용이 매우 크다.</strong>
Microsoft 사례에서 언급된 내용에 따르면,</p>
<ul>
<li>개발자 수만큼의 테스터가 필요</li>
<li>테스트를 위한 코드 (test harness)가 실제 프로그램보다 3배 이상 긴 경우도 있다.</li>
</ul>
<p>즉, 품질 확보는 개발보다 더 많은 자원을 요구할 수 있다.</p>
<h3 id="eg-삼각형-판단-프로그램">e.g) 삼각형 판단 프로그램</h3>
<ul>
<li>문제 정의<ul>
<li>정수 세 개를 입력받아 삼각형의 유형을 scalene, Isosceles, equilateral 중 한 가지로 판단한다.</li>
</ul>
</li>
</ul>
<p>이 문제는 단순해 보이지만 고려해야 할 사항이 많다.</p>
<ol>
<li><p>입력 유효성 검사 필요</p>
<ul>
<li>조건 1: 입력된 세 정수는 0보다 커야 한다.</li>
<li>조건 2: 한 변의 길이는 나머지 두 변의 길이의 합 보다 작아야 한다.</li>
<li>Overflow 고려 필요</li>
<li>개발자는 명시되지 않은 조건을 놓치기 쉽다. (Cause of many hard-to-find bugs)</li>
</ul>
</li>
<li><p>실행 경로가 많다.</p>
<ul>
<li>문서에 따르면 총 11개의 실행 경로가 존재한다.</li>
<li>직관적으로 보이는 테스트 몇 개만으로는 충분하지 않다.</li>
</ul>
</li>
</ol>
<h4 id="테스트가-더-어려워지는-이유-프로그램의-변화">테스트가 더 어려워지는 이유: 프로그램의 변화</h4>
<p>소프트웨어는 지속적으로 변하므로 테스트 또한 지속적으로 수행되어야 한다.</p>
<ul>
<li>입력 타입을 <code>int</code>에서 <code>float</code>으로 바꾸면 오류 처리가 필요하다.</li>
<li>직각삼각형 판별 기능이 추가되면 기존 테스트 재검증이 필요하다.</li>
</ul>
<p>코드 변경 시 기존 기능이 깨지지 않는지 변경의 안전성을 보장하기 위해서 반복적으로 검사하는 <strong>regression testing</strong>이 중요하다.</p>
<p>기존 기능이 깨지지 않았는지 테스트하는 활동인 regression testing은 서로 다른 코드 두 개의 결과를 비교해서 이미 발견된 버그가 재발하지 않도록 방지하고 품질을 유지할 수 있다.</p>
<h3 id="concurrency-programming에서-검증의-어려움">Concurrency programming에서 검증의 어려움</h3>
<p>예를 들어 두 개의 스레드 각각 세 개의 연산을 수행한다면 가능한 스케줄은 $(3+3)!/(3!\times3!)=20$이지만 결과는 11 가지로 수렴한다. 이때 어떠한 곳에서 문제가 발생하는지 찾는 것은 매우 어렵다.</p>
<p>Concurrency로 인한 bug는 재현성이 낮고, 타이밍에 따라 드러나므로 테스트로 발견하기 가장 어려운 유형 중 하나이다.</p>
<h2 id="testing-and-verification-have-many-facets">Testing and Verification Have Many Facets</h2>
<h3 id="소프트웨어-분석에서-반드시-고려해야-하는-근본-질문">소프트웨어 분석에서 반드시 고려해야 하는 근본 질문</h3>
<ol>
<li>명세 (specification)은 올바른가?<ul>
<li>사용자의 요구를 잘 반영했는지 확인 필요 (validation)</li>
</ul>
</li>
<li>시스템은 명세를 충족하는가?<ul>
<li>구현이 명세대로 동작하는지 확인 (verification)</li>
</ul>
</li>
<li>시스템은 사용자 니즈를 충족하는가?<ul>
<li>사용자가 진정으로 원하는 기능을 제공하는가</li>
</ul>
</li>
<li>시스템이 잘못 동작하지 않음을 어떻게 보장할 것인가?<ul>
<li>오류가 드러나는 조건은 보통 특정 경계 상황, 드문 조합, 비정상 입력 등에서 발생한다. 이런 영역을 체계적으로 탐색하는 것이 테스트의 핵심 난점이다.<h3 id="verification-vs-validation">Verification vs Validation</h3>
</li>
</ul>
</li>
</ol>
<p><strong>Verification</strong>은 명세/설계/코드가 올바른지 확인하는 것을 목적으로 한다. <strong>Validation</strong>은 사용자 요구를 충족하는 것을 목적으로 한다.</p>
<p>예를 들어 계산기 앱이 사칙연산을 정확히 수행하는지 확인하는 것은 verification, 계산기의 기능이 실제 사용자 니즈를 충족하는지 확인하는 것은 validation이다.</p>
<p>올바르게 만들었는가 vs 올바른 것을 만들었는가</p>
<h3 id="단일-기법으로는-충분하지-않은-이유">단일 기법으로는 충분하지 않은 이유</h3>
<p>소프트웨어 시스템은 구조, 규모, 사용 목적이 다양한다. 게임은 사용성, 반응성이 중요하고 항공 소프트웨어는 안전성과 신뢰성이 요구된다. 따라서 어떤 분석 기법을 사용할지는 시스템의 종류, 규모, 품질 목표, 자원 등에 따라 달라진다.</p>
<h3 id="definition-software-analysis">Definition: Software Analysis</h3>
<p>소프트웨어 분석은 소프트웨어 산출물 (artifact)을 체계적으로 분석하여 그 속성을 파악하는 것을 뜻한다. 여기서 artifact의 범위는 매우 넓다.</p>
<ul>
<li>코드, 모듈, 시스템, 실행 trace, 테스트 케이스, 설계 문서, 요구사항 문서 등</li>
</ul>
<h4 id="소프트웨어-분석-기술">소프트웨어 분석 기술</h4>
<ul>
<li>Dynamic: 실행 (run-time)을 기반으로 분석한다.<ul>
<li>Testing: 테스트 데이터로 프로그램을 직접 실행하여 결과를 검사한다.</li>
<li>Analysis: 실행 중 수집한 데이터를 기반으로 커버리지 분석, 메모리 누수 탐지 등 검사한다.</li>
</ul>
</li>
<li>Static: 코드를 실행하지 않고 분석한다.<ul>
<li>Inspection: 사람이 직접 코드를 검토하며 fault를 조기에 발견한다.</li>
<li>Analysis: 도구를 이용하여 제어 흐름, 데이터 흐름, 타입 정보 등을 자동으로 분석한다.</li>
</ul>
</li>
</ul>
<p>다양한 분석/테스트 기법이 존재하지만, 어떤 기술도 단독으로는 충분하지 않다. 또한 시스템 특성, 품질 목적, 보안/안전 요구사항, 예산 등에 따라 기술 조합이 달라진다. <strong>따라서 test strategy를 설계하는 것이 소프트웨어 품질 보증의 핵심이다.</strong></p>
<h2 id="classic-testing">Classic Testing</h2>
<p>(전통적 소프트웨어 테스팅 즉, 기능적 정확성을 중심으로 한 테스트의 목표와 한계)</p>
<h3 id="what-is-testing">What is Testing?</h3>
<p>Testing은 통제된 환경에서 테스트 데이터를 사용하여 실제 코드를 실행하는 활동을 칭한다. 즉, 테스트는 컴파일만 하거나 코드를 눈으로 보는 것이 아니라 프로그램을 실행한 결과를 관찰하는 활동이라는 점이 핵심이다.</p>
<p>Testing의 주요 목적은 다음과 같다.</p>
<ul>
<li><strong>Verification</strong>: 프로그램이 요구사항을 정확히 만족하는지 확인한다.</li>
<li><strong>Defect Testing</strong>: 프로그램을 실행하면서 오류를 찾는다.</li>
</ul>
<p>또한 testing은 결함을 발견하고 품질을 평가하고, 명세와 문서를 명확히하는 것도 목적으로 한다.</p>
<p>하지만 아무리 많은 테스트를 수행해도 실행되지 않는 경로에 숨어 있는 버그는 여전히 존재할 수 없다. 따라서 <strong>테스트는 버그 &quot;없음&quot;을 절대 보장할 수 없다.</strong></p>
<h3 id="bug-defect-error-failure">Bug, Defect, Error, Failure</h3>
<table>
<thead>
<tr>
<th>용어</th>
<th>정의</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>Error</td>
<td>사람이 만든 실수</td>
<td>time=0인 경우를 고려하지 않음</td>
</tr>
<tr>
<td>Fault (Defect, Bug)</td>
<td>코드에 존재하는 문제</td>
<td>divide-by-zero 예외 처리가 없음</td>
</tr>
<tr>
<td>Failure</td>
<td>Fault가 실행되어 실제로 잘못된 결과 발생</td>
<td>time=0 실행 시 예외 발생</td>
</tr>
</tbody></table>
<p>Error가 fault로 fault가 failure로 이어질 수 있지만 fault가 실행되지 않으면 failure는 발생하지 않는다.</p>
<h4 id="debugging-is-not-testing">Debugging is Not Testing</h4>
<ul>
<li><strong>Debugging</strong>: 실패가 발생한 후 원인을 분석하고 수정하는 과정이다.</li>
<li><strong>Testing</strong>: 실패를 찾아내기 위해 체계적으로 검색하는 과정이다. 여기에서 코드 수정은 포함하지 않으므로 debugging을 완전히 대체할 수 없다.</li>
</ul>
<h3 id="testing-levels">Testing Levels</h3>
<table>
<thead>
<tr>
<th>Level</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Unit Testing</td>
<td>개별 모듈 (함수/클래스)을 독립적으로 테스트</td>
</tr>
<tr>
<td>Integration Testing</td>
<td>모듈 간 상호작용 테스트</td>
</tr>
<tr>
<td>System Testing</td>
<td>전체 시스템이 하나의 제품으로서 정상 동작하는지 화인</td>
</tr>
</tbody></table>
<h3 id="test-driven-development-tdd">Test-Driven Development (TDD)</h3>
<p>테스트를 먼저 작성하는 개발 방법을 Test-Driven Development라고 한다. 이때 실패하는 테스트 없이는 코드를 작성하면 안 된다. 이러한 agile 기법의 기대 효과는 다음과 같다.</p>
<ul>
<li>인터페이스 우선 설계 유도</li>
<li>불필요한 코드 감소</li>
<li>결함 감소 및 코드 품질 향상</li>
<li>테스트 커버리지 향상</li>
<li>생산성 증가 사례 존재</li>
</ul>
<h3 id="continuous-integration">Continuous Integration</h3>
<p>코드가 커밋될 때마다 자동으로 빌드하고 테스트를 실행해서 결과를 기록하면 빠른 피드백을 통해 회귀 발생을 빠르게 감지할 수 있고 협업 개발 시 품질 유지에 도움이 된다.</p>
<h3 id="oracle-problem">Oracle Problem</h3>
<p>프로그램이 정답을 출력했는지 자동으로 판단하기 어렵다는 근본적인 문제가 있다.
실제 시스템에서 Input generator로 이상적 정답인 golden oracle을 만들기는 어렵다. 결론적으로 테스트에서 오라클 비용은 매우 크며, 자동화의 가장 큰 장애 요소 중 하나이다.</p>
<h2 id="testing-beyond-functional-correctness">Testing Beyond Functional Correctness</h2>
<p>기능적 정확성만으로 실제 소프트웨어 품질을 충분히 설명할 수 없다. 테스트는 기능과는 다른 영역 (사용성, 보안, 성능)으르 포함해야 하지만, 정답이 명확하지 않고 자동화가 쉽지 않다.</p>
<h3 id="testing-usability">Testing Usability</h3>
<p>사용성 테스트가 어려운 이유는 아래와 같다.</p>
<ul>
<li><strong>Specification</strong>: 사용성은 명확한 규격으로 정의하기 어렵다.</li>
<li><strong>Test harness / Environment</strong>: 다양한 사용자·브라우저·기기 환경에서 동작해야 하기 때문에 통일된 테스트 환경을 정의하기 어렵다.</li>
<li><strong>Nondeterminism</strong>: 사용자의 행동은 예측할 수 없고, 실험마다 달라진다.</li>
<li><strong>Unit testing / Automation / Coverage</strong>: 사용성을 코드 단위로 분해하거나 자동화하기는 거의 불가능하다. 또한 coverage라는 개념 자체가 적용되기 어렵다.</li>
</ul>
<p>즉 사용성은 기능처럼 정답이 있는 테스트가 아니며, 사람의 행동과 경험이 관여하기 때문에 자동화가 매우 어렵다.</p>
<p>또한 GUI/Web 사용성을 테스팅하는 것 또한 상당히 어려운 문제이다.</p>
<ul>
<li>Capture and Replay 방식<ul>
<li>마우스 클릭이나 키보드 입력 같은 시스템 이벤트를 녹화 후 반복 실행하면서 테스트 하게 된다.</li>
<li>이러한 방식은 간단한 테스트에는 유용하지만 UI 변경에는 매우 취약하고 타이밍이나 환경 차이를 반영하기 어렵다.</li>
</ul>
</li>
<li>GUI 테스트에 과도하게 의존하게 되면 유지비가 커질 수 있어서 모델과 GUI를 분리하여 테스트 부하를 줄여야 한다.</li>
</ul>
<h4 id="manual-testing">Manual Testing</h4>
<p>수동 테스트에서는 다음과 같은 고려사항이 있다.</p>
<ul>
<li>실제 시스템에서 테스트해야 하는가?</li>
<li>별도 환경이 필요한가?</li>
<li>사용성 결과는 자동 assert가 불가능하다.</li>
<li>비용이 매우 크다.</li>
<li>재현성이 낮다.</li>
</ul>
<p>즉, 사용성 테스트는 잦동화가 어렵고 비용이 크며, 정량 평가가 어렵다는 특징을 가진다.</p>
<h4 id="ab-testing">A/B Testing</h4>
<p>Usability 평가에서 가장 실용적인 접근 중 하나로 A/B Testing이 있다. A와 B 두 변형을 그룹에 나누고 클릭 수 같이 실제 사용자 행동을 지표로 삼아 비교하는 방법이다. 이는 광고, GUI 배치, UX 디자인 결정에 자주 사용된다.</p>
<p>A/B Testing은 표본을 기반으로 하는 통계적인 비교이기 때문에 명확한 정답이 없는 사용성 평가에서 실질적인 도구가 된다.</p>
<h3 id="testing-security--robustness">Testing Security &amp; Robustness</h3>
<p>보안 테스트는 기능 테스트보다 훨씬 복잡하며, 다음의 근본적 문제들이 있다.</p>
<ul>
<li><strong>Specification</strong>: &quot;보안적으로 안전해야 한다&quot;는 모호한 요구. 명세가 어렵다.</li>
<li><strong>Test harness / Environment</strong>: 실제 공격자를 완전히 모사하기 어렵다.</li>
<li><strong>Nondeterminism</strong>: 공격 시나리오를 예측할 수 없다.</li>
<li><strong>Automation / Coverage</strong>: 악의적 입력은 무한하며, 이를 전부 테스트할 수는 없다.</li>
</ul>
<h4 id="random-testing">Random Testing</h4>
<p>프로그램의 입력 도메인에서 무작위 입력을 생성해서 테스팅하는 방식이다. 단순하지만 의외로 강력하며, 대규모 시스템 테스트에 활용된다.</p>
<p>예를 들어 23,000개의 무작위 입력에서 실패가 발생하지 않았다면 이 프로그램의 실패율은 최소 90%의 신뢰도로 1/10,000 이하로 추정할 수 있다. 즉, random testing은 기능 정확성보다 신뢰성을 확률적을 ㅗ보증할 수 있다는 장점이 있다.</p>
<h4 id="fuzz-testing-fuzzing">Fuzz Testing (Fuzzing)</h4>
<p>잘못된 입력이나 예상하지 못한 입력, 랜덤 변형 입력을 지속적으로 주입하여 보안 취약점이나 심각한 오류를 찾아내는 기법이다. 서비스가 중단되는 원인을 찾거나 강한 오류를 발생시키는 문제를 발견할 수 있다.</p>
<p>Fuzzing으로 발견할 수 있는 버그 유형은</p>
<ul>
<li>포인터/배열 접근 오류</li>
<li>반환 값 미확인</li>
<li>Boundary 오류</li>
<li>부호 오류</li>
<li>Race conditions
등이 있다.</li>
</ul>
<p>Fuzzing은 다음과 같은 흐름으로 진행된다.</p>
<ol>
<li>Seed input pool 유지</li>
<li>입력을 bit flip, byte flip 등의 방식으로 변형</li>
<li>새 경로를 커버하는 입력을 pool에 유지</li>
</ol>
<p>(AFL, libFuzzer 같은 현대적 fuzzer가 이 방식을 사용한다.)</p>
<p>Fuzzing은 단순 무작위가 아니라 새로운 코드 경로를 여는 입력을 학습하며 진화한다.</p>
<h3 id="testing-performance">Testing Performance</h3>
<p>성능 테스트는 기능이 정확히 돌아가는지보다, 시스템이 얼마나 빠르고 안정적으로 동작하는지를 검증하는 영역이다.</p>
<h4 id="unit--regression-performance-testing">Unit &amp; Regression Performance Testing</h4>
<p>핵심 컴포넌트들의 실행 시간을 측정해서 이전 버전과 비교한다. 성능 저하가 regression으로 발생했는지 감지할 수 있다. 또한 bottleneck을 빠르게 찾아낼 수 있다.</p>
<h4 id="profilling">Profilling</h4>
<p>CPU 사용량, 메모리 사용량을 파악하고 어떤 함수가 전체 실행 시간을 잡아먹는지 식별할 수 있는 기법이다. 이를 통해 어디를 최적화해야 하는지 알 수 있다.</p>
<h4 id="performance-testing-during-design">Performance Testing during Design</h4>
<p>코드가 완성되기 전에 모델링과 시뮬레이션을 통해 성능을 예측할 수 있다.
예를 들어 queuing 모델에서 서버 수, 요청 빈도, 처리 속도 등을 기반으로 병목을 예측할 수 있다. 이처럼 성능 테스트는 구현 이후뿐 아니라 설계 단계에서도 가능하다.</p>
<h4 id="stress-testing">Stress Testing</h4>
<p>정상 범위를 넘어서는 극단적인 부하를 주면서 강건성을 측정하는 기법이다.
소프트웨어의 오류 처리 능력을 파악하고, 복구 가능성을 예상할 수 있어서 결국 서비스의 지속성을 보장할 수 있는지 판단할 수 있다.</p>
<h4 id="soak-testing">Soak Testing</h4>
<p>메모리 누수 같은 문제들은 짧은 테스트에서는 드러나지 않을 수 있다. Soak testing은 오랜 시간 동안 일정한 부하를 주어 시스템을 테스트하는 기법이다.
메모리 누수를 포함하여 리소스가 고갈되는 문제처럼 오랜 시간 동안 실행했을 때 발생하는 문제를 탐지할 수 있다.</p>
<h4 id="chaos-engineering-infrastructure-level-fuzz-testing">Chaos Engineering (Infrastructure-level Fuzz Testing)</h4>
<p>넷플릭스에서는 무작위로 서버 인스턴스를 종료시키거나 네트워크 지연, 장애를 강제로 유발하여 시스템이 얼마나 탄력적인지 평가한다. 이 방법은 전통적 소프트웨어 테스트가 아니라, 대규모 분산 시스템의 안정성과 회복력을 검증하는 기법이다.</p>
<h2 id="limits-of-testing">Limits of Testing</h2>
<ul>
<li>실행되지 않은 코드의 오류는 발견할 수 없다.</li>
<li>정답을 자동으로 판정하지 어려운 oracle 문제</li>
<li>Nondeterminism</li>
<li>실행 시간이 오래 걸릴 수 있다.</li>
<li>많은 비용이 필요하다.</li>
<li>Verification 중심이며, validation은 충분히 보장하지 못한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lateral Control]]></title>
            <link>https://velog.io/@hyeon-ii/Lateral-Control</link>
            <guid>https://velog.io/@hyeon-ii/Lateral-Control</guid>
            <pubDate>Sun, 25 May 2025 12:37:53 GMT</pubDate>
            <description><![CDATA[<h2 id="lane-keeping-assistance-system">Lane Keeping Assistance System</h2>
<p>LKAS는 차량이 차선을 벗어나지 않도록 자동으로 조향을 조절하는 시스템이다. 운전자가 직접 조향을 하지 않아도 자동차가 도로 위의 차선을 따라 안정적으로 주행할 수 있도록 도와준다. 카메라와 센서로 현재 차량이 차선에서 얼마나 벗어났는지($e_1$), 차량의 방향이 도로와 얼마나 틀어졌는지($e_2$) 측정하여 차량을 원래 차선으로 되돌리도록 조향을 보정한다.</p>
<h3 id="lkas-제어-구조">LKAS 제어 구조</h3>
<p>카메라, GPU, IMU를 이용해서 도로 중심선과 차량 상태를 감지하면 제어기는 오차 $e_1, e_2$를 기반으로 제어량을 계산하여 실제로 핸들을 돌리는 구조로 동작한다.</p>
<h3 id="dynamic-bicycle-model-기반-상태공간">Dynamic Bicycle Model 기반 상태공간</h3>
<p>상태 변수 $e_1, e_2$는 LKAS의 핵심이다.</p>
<ul>
<li>$e_1$: 차량 중심이 차선 중심에서 얼마나 벗어났는지 나타내는 횡방향 오차로, $e_1&gt;0$이면 차량이 차선의 오른쪽으로 벗어난 것이다.</li>
<li>$e_2$: 차량이 도로 중심선에 비해 얼마나 기울어져 있는지 나타내는 헤딩각도 오차로, $e_2&gt;0$이면 차량이 도로보다 왼쪽을 향하는 것이다.</li>
</ul>
<p>이 오차를 줄이는 방향으로 핸들을 자동 조절하는 것이 제어기의 목표이다.</p>
<p>차량이 바퀴 두 개 달린 Bicycle Model이라고 가정한다면, 이 모델은 속도, 조향각, 타이어 힘 들을 바탕으로 회전을 설명할 수 있다. 예를 들어 차량이 일정 속도 $V_x$로 선회반경 $R$을 유지하면서 움직이고 있을 때 먼저 두 가지 개념을 잡아야 한다.</p>
<ul>
<li>$\dot\psi_\text{des}=\frac{V_x}{R}$: 목표 요레이트</li>
<li>$a_{y,\text{des}}=\frac{V_x^2}{R}=V_x\dot\psi_\text{des}$: 목표 횡가속도</li>
</ul>
<p>차량이 차선에서 얼마나 벗어났는지 측정하려면 두 개의 오차항의 수식을 정의해야 한다.</p>
<ul>
<li>$\ddot{e_1} =a_y-a_{y,\text{des}} = \ddot{y}+V_x\dot\psi-V_x\dot\psi_\text{des}$: 횡가속도 오차</li>
<li>$e_2=\psi-\psi_\text{des}$</li>
</ul>
<p>차량 속도 $V_x$가 일정하다고 가정하였으므로 $\ddot{e}_1$은 적분했을 때 다음과 같다.
$$
\dot{e}_1=\dot{y}+V_x(\psi-\psi_\text{des})
$$</p>
<p>이 두 값($e_1,e_2$)이 0이면 차량이 완벽하게 중심선을 따라가고 있는 것이고, 값이 클수록 많이 벗어난 것이다.</p>
<p>이 오차들을 포함한 시스템 전체($x$)를 상태공간으로 표현하면 다음과 같은 상태방정식을 얻게 된다.
$$
\frac{d}{dt} \begin{bmatrix}e_1 \ \dot{e}_1 \ e_2 \ \dot{e}_2 \end{bmatrix} = Ax+B_1\delta+B_2\dot\psi_\text{des}
$$</p>
<p>차량이 중심선에서 벗어나지 않도록 핸들을 자동으로 조정할 때 사용하는 것이 상태 피드백 제어기이다. 제어 입력, 즉 조향각은 다음과 같이 설계된다.
$$
\delta=-Kx=-k_1e_2-l_2\dot{e}_1-k_3e_2-k_4\dot{e}_2
$$
$x$는 현재 시스템의 상태이고, $K$는 설계해야 하는 gain 값이다. 즉, 오차가 클수록 핸들을 더 크게 꺾어서 위치를 보정하게 된다.</p>
<p>이 제어기를 제대로 동작하게 하려면, 제어 시스템의 고유값을 조절해줘야 한다. 이를 위해 Pole Placement 기법을 사용한다.</p>
<h2 id="차량-경로-제어-알고리즘">차량 경로 제어 알고리즘</h2>
<h3 id="pure-pursuit">Pure Pursuit</h3>
<p>Pure Pursuit은 차량이 특정 경로를 따라가기 위해 사용하는 대표적인 경로 추종 알고리즘 중 하나이다. 차량은 일정 거리 앞에 있는 목표 지점을 추적하도록 조향각을 계산한다. 핵심 아이디어는 차량 뒤 축 중심을 기준으로, 경로 상 일정 거리 떨어진 점을 목표로 회전 반경 $R$을 결정하고, 해당 반경에 맞는 조향각 $\delta$를 계산하는 것이다.</p>
<p>Pure Pursuit은 Kinematic Bicycle Model에 기반한다. 기하학적으로 조향각 $\delta$를 유도할 때 <strong>차량이 회전 반경 $R$로 곡선을 그리며 선회한다</strong>는 가정이 필요하다. 차량의 회전 중심을 기준으로 삼각형을 형성하면 아래와 같은 삼각 함수를 통해 조향각을 유도할 수 있다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/ceeb1311-0ad3-4882-8f01-c43acf1d657d/image.png" alt="">
$$
\frac{l_d}{\sin2\alpha}=\frac{R}{\sin(\frac{\pi}{2}-\alpha)}\quad\rightarrow\quad \frac{l_d}{2\sin\alpha\cos\alpha}=2R\quad\rightarrow\quad\kappa=\frac{1}{R}=\frac{2\sin\alpha}{l_d}
$$</p>
<p>여기서 $\alpha$는 차량 후륜과 목표 지점 사이의 헤딩각이고, $l_d$는 전방주시거리, $L$은 휠베이스일 때 조향각은 다음과 같이 유도된다.
$$
\delta_f=\tan^{-1}\frac{L}{R}=\tan^{-1}\kappa L=\tan^{-1}\Big(\frac{2L\sin\alpha}{l_d}\Big)
$$</p>
<p>보통 도로 위 실제 차량은 도로 중심선에서 얼마나 벗어났는지 측정할 수 있다. 이 오차를 통해 조향각을 단순하게 다음과 같이 유도할 수 있다.
$$
\delta_f\approx\frac{2L}{l_d^2}e
$$
이 조향각은 경로 오차 $e$에 비례하고, 전방주시거리 $l_d$의 제곱에 반비례하다. 이 관계는 차량이 경로에 빨리 복귀하려면 어떻게 조향해야 하는지 직관적으로 보여준다.</p>
<p>전방주시거리 $l_d$는 제어 성능을 좌우하는 중요한 파라미터이다.</p>
<ul>
<li>$l_d$가 크면 경로 오차가 커도 조향각은 작게 계산되어 부드럽게 움직이지만 반응이 느릴 수 있다.</li>
<li>$l_d$가 작으면 경로 오차가 작아도 조향각이 크게 계산되어 빠르게 반응하지만 과잉 반응할 수 있다. (초보운전)</li>
</ul>
<p>속도에 따라 전방주시거리를 조절할 수도 있다.</p>
<ul>
<li>고속 주행 시 $l_d$가 증가하므로 경로 오차가 크더라도 조향각이 작아서 안정적으로 조향할 수 있다.</li>
<li>저속에서는 $l_d$가 작아서 민감하게 반응한다.</li>
</ul>
<p>Pure Pursuit는 기하학적인 방법이므로 구현이 쉽고 직관적이지만, 타이어 슬립이 발생하는 고속 상황, 또는 정확한 경로 오차 계산이 어려운 경우에는 정확도가 떨어질 수 있다. 따라서 실내 자율주행 차량, 저속 주행에 주로 사용된다.</p>
<h3 id="stanley-control">Stanley Control</h3>
<p>Stanley Control은 차량이 도로 위 목표 경로를 잘 따라가게 만드는 방식이지만 Pure Pursuit과 달리, 전방주시거리 $l_d$를 사용하지 않고도 정확하게 조향각을 계산할 수 있다. 핵심 아이디어는 차량의 앞바퀴 중심을 기준으로 잡고 경로 오차와 헤딩 오차를 사용하는 것이다.</p>
<ul>
<li>횡 경로오차 $e$: 차량 앞바퀴 중심에서 목표 경로까지의 수직 거리</li>
<li>헤딩 오차 $\psi$: 차량이 향하고 있는 방향과 경로가 향하는 방향의 각도 차이</li>
</ul>
<p>조향각 $\delta_f$는 다음 두 항의 합으로 계산된다.</p>
<ol>
<li><strong>헤딩오차고려</strong>: 목표 경로의 방향과 차량 축방향을 일치시키기 위한 조향각도 (Feedforward 항)
$$
\delta_f=\psi
$$<ul>
<li>차량이 목표 경로 방향을 향하도록 조향각을 조절한다.</li>
</ul>
</li>
<li>경로오차고려: 아래 조건을 고려한 control law 설정 (Feedforward 항): Pure-pursuit과 유사<ul>
<li>경로 오차에 비례</li>
<li>차량 속도를 고려 (예: 고속에서 작은 조향각도)
$$
\delta_f=\tan^{-1}\Big( \frac{ke}{v_f} \Big)
$$</li>
<li>$k$는 튜닝 파라미터로, 경로 오차에 대한 민감도이다.</li>
<li>경로에서 벗어난 거리만큼 조향각을 조절한다. 차량 속도가 느릴수록 조향각을 더 크게 조절하여 빠르게 경로에 복귀한다.</li>
</ul>
</li>
</ol>
<p>두 항을 합치면 최종 조향각은 다음과 같이 계산된다.
$$
\delta_f=\psi+\tan^{-1}\Big( \frac{k\dot e}{v_f} \Big)
$$</p>
<p>Control Law를 구성하는 두 항의 크기에 따라 경로를 제어한 결과</p>
<p>Stanley 알고리즘은 차량이 경로를 따라가도록 지속적으로 방향을 조절한다.</p>
<ul>
<li>속도가 빠르면 조향각이 작아지므로 경로 오차를 부드럽게 수정한다.</li>
<li>속도가 느리면 조향각이 커지므로 경로 복귀를 빠르게 유도한다.</li>
<li>목표 경로에 가까워질수록 경로 오차는 감소하고, 조향각도 점차 줄어든다.</li>
</ul>
<p>속도 $v_f$가 너무 작아지면 조향각이 과도하게 커질 수 있기 때문에, 분모어 보정항 $k_s$를 추가하여 조정해야 한다.
$$
\delta_f=\psi+\tan^{-1}\Big( \frac{ke}{k_s+v_f} \Big)
$$
이렇게 하면 작은 경로 오차에서 과도한 조향각이 발생하는 것을 방지할 수 있다.</p>
<h3 id="pure-pursuit-vs-stanley">Pure Pursuit vs. Stanley</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>기준점</th>
<th>전방주시거리</th>
<th>고려사항</th>
<th>경로 오차 정의</th>
</tr>
</thead>
<tbody><tr>
<td>Pure Pursuit</td>
<td>뒷바퀴 중심</td>
<td>사용</td>
<td>경로 오차</td>
<td>전방주시거리와 경로의 교점에서 차량 축방향까지의 수직거리</td>
</tr>
<tr>
<td>Stanley</td>
<td>앞바퀴 중심</td>
<td>사용 안함</td>
<td>경로 오차 + 헤딩 오차</td>
<td>앞바퀴 중심에서 목표경로까지 가장 가까운 거리</td>
</tr>
</tbody></table>
<p>두 방법 모두 기구학 기반 경로제어 방법이므로, 차량의 동역학이 발휘되어 타이어 힘이 발생되었을 때는 사용할 수 없다. 따라서 실제 적용하기 위해서는 동역학적 차량 모델 기반 경로제어방법이 필요하다.</p>
<h3 id="model-predictive-control">Model Predictive Control</h3>
<p>MPC는 차량이 앞으로 어떻게 움질일지 예측한 뒤, 그 예측을 바탕으로 최적의 조향각을 결정하는 방법이다. MPC는 다음 세 가지를 동시에 고려한다.</p>
<ul>
<li>미래의 경로 예측</li>
<li>현재 상황에서 최적의 조향각 선택</li>
<li>차량의 움직임에 대한 제약 조건 고려</li>
</ul>
<p>MPC는 차량의 움직임을 예측하기 위해 차량 모델이 필요하다. 종-횡방향 힘을 모두 고려한 동역학 기반 차량 모델은 다음과 같은 물리 법칙을 포함하고 있다.</p>
<ul>
<li>타이어에 작용하는 힘</li>
<li>차량의 회전과 이동</li>
<li>조향각이 차량의 위치와 방향에 미치는 영향 등</li>
</ul>
<p>하지만, 실제로는 연속적인 시간 흐름이 아니라, 샘플링 타임에 따라 미래를 비선형적으로 나누어서 예측한다. 즉, $t, t+1, t+2, \dots, t+N_p$ 시점까지 조향 각도를 결정한다.
$$
\xi(k+1)=f_\text{dt}(\xi(k),\Delta u(k)), \quad u(k)=u(k-1)+\Delta u(k)
$$</p>
<p>미래 경로를 예측한 후, 그 결과가 얼마나 잘 따라가는지 수치로 평가하는 것을 비용함수라고 한다. 시점 $t$에서 $t+N_p$까지의 추종 오차와 시점 $t$에서 $t+N_c-1$까지의 급격한 제어 입력 변화 방지에 대한 합으로 계산된다.</p>
<p>MPC는 현실적인 상황도 반영할 수 있다. 예를 들어,</p>
<ul>
<li>조향각은 최대 몇 도까지만 돌릴 수 있음</li>
<li>조향 각도 변화 폭은 일정 이상 못 넘김</li>
<li>차량의 속도나 위치도 물리적으로 제한됨</li>
</ul>
<p>이런 조건을 만족시키면서 비용함수를 최소화하는 방향으로 문제를 푼다.</p>
<p>결국 MPC는 아래와 같은 수학 문제(최적화 문제)로 바뀐다.
$$
\min_{\Delta u(k)}J(\xi,\Delta u) \
\Delta u^*(t)=[\Delta u(t|t),\cdots\Delta u(t+N_p-1|t)]
$$
이 문제를 실시간으로 계속 풀어서 그 중 가장 첫번째 요소 $\Delta u(t|t)$만 차량에 인가되고 나머지 $N_p-1$개의 계산된 값들은 사용되지 않는다.</p>
<p>실제로 실험해보면 MPC는 경로를 부드럽고 안정적으로 따라가며 조향각도 부드럽게 변화한다.</p>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>미래를 내다보고 최적화</td>
<td>높은 계산량</td>
</tr>
<tr>
<td>선형, 비선형 모델 모두 적용</td>
<td>제어기 원리가 직관적이지 않음</td>
</tr>
<tr>
<td>다수의 제한조건 동시 고려 가능</td>
<td></td>
</tr>
</tbody></table>
<h2 id="차량-횡방향-제어">차량 횡방향 제어</h2>
<p>자동차가 코너를 돌거나 차선을 유지할 때, 차량이 도로 위에서 안정적으로 움지깅기 위해 횡방향 제어가 필요하다. 특히, 미끄러지거나 언더스티어/오버스티어와 같은 위험한 상황을 방지하기 위해서는 안전 제어가 필수적이다. 하지만 차량이 항상 일정한 주행 조건을 유지하진 않기 때문에, 단순한 조향 튜닝으로는 모든 상황에 대응할 수 없다. 이로 인해 Active Control이 필요해졌으며 현재는 이를 ESC라는 이름으로 상용차에 적용하고 있다.</p>
<h3 id="안정성-제어-시스템의-유형">안정성 제어 시스템의 유형</h3>
<p>안정성 제어 시스템은 크게 다음 세 가지 방식으로 구분된다.</p>
<ol>
<li><strong>Differential Braking</strong>: 가장 보편적인 방식으로, 오른쪽과 왼쪽 바퀴에 서로 다른 브레이크 압력을 가해 차량의 yaw moment를 조절한다. 예를 들어, 왼쪽 바퀴에 브레이크 압력을 더 많이 걸면 차량이 왼쪽으로 회전하게 된다.</li>
<li><strong>Steer-by-Wire</strong>: 운전자의 조향 입력을 전자적으로 감지하고, 보정된 조향각을 바퀴에 전달한다. 기계적인 연결 없이 전기적으로 조향하는 시스템이다.</li>
<li><strong>Active Torque Distribution</strong>: 구동력을 네 바퀴에 개별적으로 분배하여 차량의 선회와 안정성을 확보한다. 이 방식은 사륜구동 차량에 주로 적용되며, 코너링 중 휠마다 다른 구동력을 전달해 차량 자세를 유지한다.</li>
</ol>
<h3 id="제어-시스템-구성도">제어 시스템 구성도</h3>
<p>차량의 횡방향 안정성을 유지하기 위한 제어 시스템은 다양한 센서와 유압/전자 부품으로 구성된다. 예시는 다음과 같다.</p>
<ul>
<li>차륜 속도 센서: 각 바퀴의 속도를 감지</li>
<li>요레이트 센서/가속도 센서: 차량의 회전 속도 및 측면 가속도 감지</li>
<li>압력 센서 &amp; 하이드로닉 유닛: 브레이크 유압 조절</li>
<li>VDC ECU (Vehicle Dynamics Control Electronic Control Unit): 센서 데이터를 기반으로 제어 명령을 판단하여 브레이크나 엔진 토크 등을 조절</li>
</ul>
<p>이 시스템은 ESC가 개입할 시 각 바퀴에 개별적으로 브레이크를 적용하거나 엔진 토크를 줄여 차량을 안정적으로 만든다.</p>
<p>안정성 제어를 위해 차량은 다음과 같은 물리량을 실시간으로 측정한다.</p>
<ul>
<li>Steering angle, Yaw rate, Lateral acceleration, Vehicle speed(휠 센서), Master cylinder pressure</li>
</ul>
<p>그리고 제어 가능한 항목은 다음과 같다.</p>
<ul>
<li>Brake pressure, Engine torque(감속용), Steering angle</li>
</ul>
<p>제어 방식은 크게 두 가지 접근 방식으로 나뉜다.</p>
<ol>
<li>Yaw rate based control: 차량이 회전해야 할 목표 yaw rate와 실제 yaw rate를 비교하여 제어</li>
<li>Side slip angle control: 차량이 실제로 얼마나 미끄러지고 있는지를 측정하여 제어</li>
</ol>
<h3 id="차량-모델">차량 모델</h3>
<p>차량의 운동을 설명하기 위해 일반적으로 사용되는 모델은 6 자유도 모델 또는 7 자유도 모델로, 차량의 직선 및 횡방향 움직임, 회전 운동, 각 바퀴의 회전 등을 모두 고려한다.</p>
<h2 id="esc-using-differential-braking">ESC Using Differential Braking</h2>
<h3 id="esc-시스템과-제어-구조">ESC 시스템과 제어 구조</h3>
<p>Electronic Stability Control은 차량이 미끄러지거나 불안정한 상태에 빠졌을 때, 운전자가 원치 않는 방향으로 차량이 회전하지 않도록 도와주는 제어 시스템이다. 이 시스템의 목표는 <strong>Yaw Stability Control</strong>이다.
상위 제어기는 목표 yaw moment를 계산하고, 하위 제어기는 이를 달성하기 위해 브레이크 제어 입력을 통해 작동한다. 핵심은 빠른 바퀴의 반응을 이용해 느린 차량 동역학을 제어하는 것이다.</p>
<h3 id="yaw-rate-based-control">Yaw rate based control</h3>
<p>목표 yaw rate는 차량의 조향각 $\delta$ 속도 $V$, 휠베이스 $L$, 특성속도 $v_\text{char}$로 계산된다.
$$
\dot\psi_\text{des}=\frac{v_x}{1+(v_x / v_\text{char})^2}\cdot\frac{\delta_f}{L}
$$
계산된 yaw rate와 센서로 측정된 yaw rate의 오차를 줄이는 방향으로 yaw moment를 생성한다.</p>
<ul>
<li>장점<ul>
<li>원하는 yaw rate 계산이 쉽고 명확하다.</li>
<li>양산차 관성측정장치에 요레이트 센서가 부착되어 요레이트를 측정할 수 있다.</li>
</ul>
</li>
<li>단점<ul>
<li>희말 요레이트에 노면에 대한 정보를 포함하지 않아 미끄러운 노면에서 과도한 희망 요레이트를 설정한다.</li>
<li>노면 마찰력에 의해 요가 결정되지만 노면 마찰력은 측정하기 어렵다.</li>
</ul>
</li>
</ul>
<h3 id="side-slip-based-control">Side slip based control</h3>
<p>측면 슬립각 $\beta$는 차량이 실제 진행 방향과 차체 방향 사이의 각도로, 타이어의 한계 마찰력과 밀접한 관련이 있다.</p>
<ul>
<li>$\beta$가 너무 커지면 타이어가 쉽게 미끄러지며 제어력을 잃는다.</li>
<li>따라서 보통 $\beta$를 $\pm5$도 이내로 제한한다.</li>
</ul>
<p>$$
\alpha_f=\beta+\frac{l_f}{v_x}r-\delta_f,\quad\alpha_r=\beta-\frac{l_r}{v_x}r
$$</p>
<ul>
<li>장점<ul>
<li>도로 마찰 조건을 완전히 활용할 수 있어 매우 효율적으로 제어할 수 있다.</li>
</ul>
</li>
<li>단점<ul>
<li>$\beta$는 직접 측정이 불가능하며 추정이 필요하다.</li>
<li>경사로에서는 센서로 측정된 값이 왜곡된다.</li>
<li>IMU 센서를 이용한 정밀한 추정이 필요하다.</li>
</ul>
</li>
</ul>
<h3 id="제어-한계-및-안정성-고려">제어 한계 및 안정성 고려</h3>
<p>차량은 계산된 yaw rate 또는 $\beta$에 항상 도달할 수는 없다. 그 이유는 노면 마찰계수 $\mu$에 따라 제어 가능한 최대 가속도가 제한되기 때문이다.
즉, 차량이 도달 가능한 최대 요레이트 및 횡 미끌림 각은 노면 마찰계수에 의해 제한된다.</p>
<h3 id="상위-제어기와-하위-제어기">상위 제어기와 하위 제어기</h3>
<p>상위 제어기는 목표 yaw rate와 $\beta$ 값에 따라 슬라이딩 모드 제어기를 구성한다.</p>
<ul>
<li>차량 모델을 기반으로 슬라이딩 표면을 따라가도록 제어 입력을 설계한다.</li>
<li>필요한 yaw moment를 계산한다.</li>
</ul>
<p>$$
s=\dot\psi-\dot\psi_\text{target}+\xi(\beta-\beta_\text{target})
$$</p>
<p>하위 제어기에서는 상위 제어기에서 계산한 yaw moment를 실제로 생성하기 위해 좌/우 제동력 차이를 만들어낸다. 그리고 이를 각 바퀴의 브레이크 토크로 변환한다. 바퀴가 감속되며 생성되는 마찰력으로 목표 yaw moment를 유도한다. 마지막으로 패드-디스크 간의 마찰 특성과 거리, 마찰계수 등을 고려하여 토크를 정밀하게 제어한다.</p>
<p>ESC 전체 구조를 요약하자면, 브레이크 토크를 제어하지만 실제 목적은 타이어 마찰력의 제어이다.</p>
<h2 id="고급-횡방향-제어">고급 횡방향 제어</h2>
<h3 id="friction-circle">Friction circle</h3>
<p>타이어의 최대 마찰력은 단순히 앞뒤, 좌우 방향 힘으로 나뉘는 것이 아니라 <strong>마찰 원</strong>이라는 개념으로 표현된다. 이 원은 타이어가 동시에 견딜 수 있는 종방향 힘과 횡방향 힘의 조합 범위를 나타낸다.</p>
<ul>
<li>예를 들어 가속하면서 동시에 급하게 방향을 바꾸면, 어느 한쪽 방향의 마찰 여유가 부족해지며 미끄러지기 쉽다.</li>
<li>이때 차량의 움직임을 보정하는 <strong>요 모멘트</strong>를 최소한의 방해로 만들어내는 것이 핵심이다.</li>
</ul>
<h3 id="oversteer와-understeer에서의-보정-전략">Oversteer와 Understeer에서의 보정 전략</h3>
<ul>
<li>오버스티어 상황: 차량이 너무 많이 꺾여 뒷바퀴가 미끄러지는 경우<ul>
<li>조향보다 차량이 더 돌기 때문에 즉각적인 제어가 필요하다.</li>
<li>후륜 구동 차량은 엔진 토크를 줄여 오버스티어를 완화할 수 있다.</li>
</ul>
</li>
<li>언더스티어 상황: 차량이 원하는 만큼 돌지 못하고 외곽으로 밀려나는 경우<ul>
<li>상대적으로 위험도는 낮고, 제어도 느슨하게 적용된다.</li>
<li>전륜 구동 차량은 엔진 토크를 줄여 앞바퀴의 조향력을 확보한다.</li>
</ul>
</li>
</ul>
<h3 id="실용적인-문제들">실용적인 문제들</h3>
<ul>
<li>제어 모멘트를 만들기 위해 사용되는 제동 토크는 브레이크 압력에 의존하지만, 대부분의 차량은 실제 브레이크 압력을 직접 측정하지 않는다.</li>
<li>대신 밸브 명령값과 공급 압력을 통해 추정하며, 정확도가 떨어질 수 있다.</li>
<li>과도한 제동은 바퀴를 잠그거나, 불안정한 마찰 및 슬립 구간에 진입시켜 제어를 어렵게 만든다.<ul>
<li>슬립 컨트롤러와 병행하여 적절한 슬립 범위 내에서 제어가 필요하다.</li>
</ul>
</li>
</ul>
<p>따라서 실 차량에서는 요 레이트 기반 제어와 사이드 슬립 기반 제어를 혼합하여 사용한다. (실제로는 요 레이트 기반 제어가 흔히 사용된다.)</p>
<p>설계 시 다음의 사항을 고려해야 한다.</p>
<ul>
<li>과도한 브레이크 개입은 매우 위험하기 때문에 약간 느슨한 제어가 오히려 안정적일 수 있다.</li>
<li>조향 입력이 갑자기 발생하는 순간, 앞바퀴 슬립각 $\alpha_f$가 커지며 일시적으로 언더스티어로 오해될 수 있으므로, 실제로는 제어가 필요 없는 상황일 수도 있다.</li>
<li>브레이크나 엔진 토크 제어는 차량 속도를 줄이기 때문에 정말 필요한 상황에서만 사용해야 한다.</li>
</ul>
<h3 id="고급-기능">고급 기능</h3>
<ol>
<li>Active Steering<ul>
<li>BMW가 2003년 개발한 능동 조향 시스템은 차량의 속도에 따라 조향각을 자동 조정해준다.</li>
<li>주차 등 저속 주행 시 민첩한 움직임을 위해 조향각을 더 많이 부여하고 (큰 조향비), 고속 주행 시 차량의 안정성을 확보하기 위해 조향각을 줄인다. (작은 조향비)</li>
</ul>
</li>
<li>Damping<ul>
<li>CDC (Continuous Damping Control): 노면 상태나 차량 움직임에 따라 감쇠력을 능동적으로 조절</li>
<li>Active Roll Control: 롤링 억제를 위해 롤 바를 능동적으로 조작하여 코너링 시 차량 안정성 확보</li>
</ul>
</li>
<li>Torque Distribution<ul>
<li>각 바퀴 또는 앞/뒤 구동축에 정밀하게 토크를 분배하는 시스템으로, 트랙션 확보와 요 안정성 향상에 효과적</li>
<li>단, 매우 고가 시스템이기 때문에 비용 대비 효과 분석이 필요하다.<h3 id="다양한-4wd-시스템">다양한 4WD 시스템</h3>
4륜구동은 단순히 네 바퀴가 굴러가는 것이 아니라, 구동 방식에 따라 다음과 같이 나뉜다.</li>
</ul>
</li>
</ol>
<ul>
<li>Full-time 4WD: 항상 네 바퀴에 구동력 제공</li>
<li>Part-time 4WD: 필요시 2WD와 4WD 모드 전환 가능</li>
<li>Automatic 4WD: 보통은 2WD로 주행하다가 필요시 자동으로 4WD로 전환</li>
</ul>
<p>4WD는 제동력을 증가시키지 않고, 건조한 노면에서는 오히려 제동이 더 어려울 수 있다.</p>
<h2 id="kinematic-model-기반의-차량-횡방향-제어">Kinematic Model 기반의 차량 횡방향 제어</h2>
<h3 id="kinematic-model을-쓰는-이유">Kinematic Model을 쓰는 이유</h3>
<p>기구학적 모델은 차량을 단순화하여 물리적인 힘보다는 기하학적인 관계로만 차량 움직임을 설명하는 모델이다.</p>
<ul>
<li>실제 차량은 복잡한 힘, 마찰, 슬립 등의 동역학이 작용하지만,</li>
<li>저속이거나 정밀한 위치 제어가 필요한 경우에는 이런 복잡한 요소 없이도 기하학적 관계만으로 제어가 가능하다.</li>
</ul>
<p>그래서 저속 후진 주차나 정밀 주행 같은 상황에서는 <strong>Kinematic Model</strong> 기반 제어가 효율적이고 직관적이다.</p>
<h3 id="기본-구성-kinematic-bicycle-model">기본 구성: Kinematic Bicycle Model</h3>
<p>차량을 자전거 형태의 모델로 단순화 한다.</p>
<ul>
<li>차량은 앞바퀴 한 쌍, 뒷바퀴 한 쌍이 있는 것처럼 구성된다.</li>
<li>조향은 앞 바퀴만, 추진력은 뒷바퀴만으로 가정한다.</li>
<li>상태 변수는 다음과 같다.<ul>
<li>$x, y$: 차량의 위치</li>
<li>$\theta$: 차량이 바라보는 방향 (yaw)</li>
<li>$v$: 속도</li>
<li>$\delta$: 조향각<h3 id="궤적-추종-제어">궤적 추종 제어</h3>
차량이 도로 중심선이나 목표 경로를 따라가게 만들기 위해 두 가지 오차를 정의한다.</li>
</ul>
</li>
<li>측방 거리 오차: 차량이 경로에서 얼마나 떨어져 있는지</li>
<li>방향 오차: 차량이 경로 방향에서 얼마나 기울어져 있는지</li>
</ul>
<p>이 두 오차를 최소화하는 방향으로 조향각을 조정한다.</p>
<p>제어 입력 $u$는 조향각 $\delta$에 해당하며, 궤적 오차에 따라 다음과 같이 정의한다.
$$
u=-k_1e_1-k_2e_2
$$
여기에서 $k_1,k_2$는 오차에 대한 민감도를 조절하는 제어 gain이며, 이 값에 따라 차량이 경로에 얼마나 빠르게 복귀할지 결정된다.
또는 Feedback Linearization 기법을 통해 비선형 시스템을 선형처럼 바꿔 제어할 수도 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lateral Dynamics]]></title>
            <link>https://velog.io/@hyeon-ii/Lateral-Dynamics</link>
            <guid>https://velog.io/@hyeon-ii/Lateral-Dynamics</guid>
            <pubDate>Mon, 12 May 2025 11:00:01 GMT</pubDate>
            <description><![CDATA[<h2 id="lateral-dynamics-개요">Lateral Dynamics 개요</h2>
<p>Lateral dynamics란 차량이 좌우로 움직이거나 회전하는 성분을 설명하는 것이다. 단순히 종방향의 전진과 후진만 보는 것이 아니라, 차량이 커브를 돌거나, 슬립하면서 방향이 바뀌는 현상을 해석하는 것이 핵심이다.</p>
<p>자동차가 도로 위에서 안정적으로 선회하고, 조향에 따라 반응하며, 미끄러지지 않고 주행할 수 있도록 만들기 위해 측방 운동에 대한 모델링과 해석은 필수적이다.</p>
<h3 id="kinematics-vs-kinetics">Kinematics vs Kinetics</h3>
<p>차량의 횡방향(측방향) 운동을 이해하려면 먼저 <strong>운동학(Kinematics)</strong>과 <strong>운동역학(Kinetics)</strong>의 차이를 구분해야 한다.</p>
<ul>
<li><strong>Kinematics</strong>: 운동학은 &#39;힘&#39;이라는 개념 없이 물체가 어떻게 움직이는지를 다루는 학문이다. 즉, 위치, 속도, 가속도 등 운동의 기하학적인 관계를 수학적으로 설명할 수 있지만, 그 운동을 하게 된 힘의 원인은 설명하지 않는다.
(예: &quot;이 차량이 이 각도로 조향하면 어느 반경으로 회전한다.&quot;)</li>
<li><strong>Kinetics</strong>: 운동역학은 운동학에서 다룬 결과에 힘, 질량, 가속도 등의 개념을 더한다. 뉴턴의 운동 법칙 $F=ma$를 기반으로 하며, 차량이 움직이거나 회전하게 되는 물리적 원인을 함께 다룬다.
(예: &quot;이렇게 돌기 위해서는 이만큼의 횡력이 필요하다.&quot;)<h3 id="차량-횡방향-운동의-주요-변수">차량 횡방향 운동의 주요 변수</h3>
Lateral dynamics의 주요 상태 변수는 다음과 같다.</li>
<li>$X, Y$: 차량의 글로벌 위치 좌표</li>
<li>$\psi$: 차량의 yaw 각도, 차량이 바라보는 방향</li>
<li>$\beta$: 차량의 슬립각, 즉 차량이 향하는 방향과 실제 진행 방향 사이의 각도</li>
<li>$v$: 차량 속도 (전방 속도 벡터 기준)</li>
<li>$\delta$: 조향각<h2 id="steering-modeling">Steering Modeling</h2>
<h3 id="kinematic-bicycle-model">Kinematic Bicycle Model</h3>
차량의 조향을 단순화된 기하학적 관계만으로 설명하기 위해 Kinematic Bicycle Model을 사용한다. 차량은 두 개의 바퀴로 구성된 자전거 모델로 단순화하고, 전후륜 모두 조향 가능하다고 가정한다. 그리고 타이어 슬립이나 마찰력은 고려하지 않는다.</li>
</ul>
<p>또한, 차량은 2차원 평면에서 움직이며 heading angle을 고려한다. 이 모델은 주차 등 저속 주행 시에만 유의미하다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/a19eeb13-f025-43fc-aa1c-467c04fabf3c/image.png" alt=""></p>
<ul>
<li>차량의 거동은 중심점 $(X,Y)$와 차량이 바라보는 방향 $\psi$로 표현할 수 있다.</li>
<li>차량 중심의 속도 $V$는 차체의 종방향 축 $AB$와 $\beta$의 각을 가진다. 이때 $\beta$는 슬립각이다.</li>
<li>위의 그래프에서 삼각형 $\text{OCA}$에서는 사인법칙에 의해 $\frac{\sin(\delta_f-\beta)}{l_f}=\frac{\sin(\frac{\pi}2-\delta_f)}{R}$가 성립한다.
또한 삼각형 $\text{OCB}$에서는 $\frac{\sin(\beta-\delta_r)}{l_r}=\frac{\sin(\frac{\pi}2+\delta_r)}{R}$이 성립한다.
삼각함수 덧셈 정리에 의하면 두 식을 더했을 때 다음이 성립한다.
$$
\Big(\tan\delta_f-\tan\delta_r\Big)\cos\beta=\frac{l_f+l_r}{R}, \qquad \dot\psi=\frac{V}{R}=\frac{V\cos\beta}{l_f+l_r}\Big(\tan\delta_f-\tan\delta_r\Big)
$$
위 식은 다음을 의미한다.<ul>
<li>느린 차속 $V$로 반경 $R$로 선회할 때 요레이트 $\dot\psi$</li>
<li>조향각이 크거나 속도가 빠르면 회전 속도가 빨라진다.</li>
<li>이 모델은 자율주행차의 저속 궤적 생성 등에 사용되기도 한다.</li>
</ul>
</li>
</ul>
<h3 id="ackermann-steering-geometry">Ackermann Steering Geometry</h3>
<p>차량이 회전할 때, 네 바퀴 모두가 동일한 회전 중심을 공유해야 타이어의 미끄러짐 없이 자연스럽게 선회할 수 있다. Ackerman 조향 구조는 이를 만족시키기 위해 좌우 앞바퀴의 조향을 각각 다르게 설정한다. 차량 선회에 영향을 주는 기본 인자로는 전륜과 후륜 축 사이 거리인 <strong>wheelbase</strong> $L$과 좌우 바퀴 사이 거리인 <strong>track</strong> $l_w$가 있다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/8db902c1-89c7-4f76-abd8-44d6d9da06fa/image.png" alt=""></p>
<p>저속 회전 시 이상적인 선회 조건으로 다음이 있다.</p>
<ul>
<li>전륜의 회전 중심은 후륜 차축의 연장선에 놓여있어야 한다.</li>
<li>모든 바퀴는 하나의 원점을 중심으로 회전할 수 있다.</li>
<li>내륜은 외륜보다 더 많은 조향각이 필요하다.</li>
<li>이를 실현하기 위해 조향계는 사다리꼴 형태를 가진다.</li>
</ul>
<p>Ackermann Angle은 다차량이 선회할 때 내륜($i$)과 외륜($o$) 각도의 평균을 $\delta$로 표현한다.
$$
\delta=\frac{\delta_i+\delta_o}{2}
$$
좌우 바퀴의 조향각 차이는 평균 조향각의 제곱과 비례한다.</p>
<p>$$
\begin{cases} \tan\delta_i=\frac{L}{R-l_w/2}, \quad\delta_i=\tan^{-1}\frac{L}{R-l_w/2}\simeq\frac{L}{R-l_w/2} \
\tan\delta_o=\frac{L}{R+l_w/2}, \quad\delta_i=\tan^{-1}\frac{L}{R+l_w/2}\simeq\frac{L}{R+l_w/2},  \quad l_w\ll R, L\ll R
\end{cases}
$$
$$
\delta_i-\delta_o\approx\frac{L}{R^2}l_w=\delta^2\frac{l_w}{L}, \quad \delta_i&gt;\delta_o
$$</p>
<p>하지만 Ackermann Geometry에는 구현상 한계가 있다.</p>
<ul>
<li>실제 차량은 단일 조향 링크로 연결되어 있기 때문에 완전한 Ackermann 각을 구하기가 어렵다. 그 결과 타이어 슬립이 발생한다.</li>
<li>특히 고속주행 시 좌우 바퀴 조향각의 오차로 인해 앞 타이어 마모가 발생한다.</li>
</ul>
<h3 id="dynamic-bicycle-model">Dynamic Bicycle Model</h3>
<p>Kinematic Bicycle Model은 차량이 저속일 때는 유용하지만, 고속 주행 시에는 차량의 타이어 힘, 슬립 현상, 관성 등을 무시할 수 없다. 따라서 고속 코너링 등 실제 도로 상황을 반영하기 위해서는 힘과 모멘트를 모두 고려하는 동역학 모델이 필요하다.</p>
<p>주요 가정과 개념으로 다음의 것들이 있다.</p>
<ul>
<li>차량 운동은 평면 운동이다.</li>
<li>차량의 구조는 강체이다.</li>
<li>작은 각도는 근사를 사용하여 $\sin\delta\approx\delta,\tan\delta=\\delta,\cos\delta\approx1$가 성립한다.</li>
<li>차량의 속도 $v_x$는 일정하다.</li>
<li>타이어는 앞뒤 타이어 두 개만 있는 Bicycle model 구조를 따른다.</li>
</ul>
<ol>
<li><strong>슬립각과 타이어 횡력</strong><ul>
<li>고속 회전 중 타이어가 향하는 방향과 진행 방향의 각도 차가 생기는데 이것이 슬립각 $\alpha$이다. 전륜 후륜 각각 $\alpha_f, \alpha_r$이다. $\alpha$가 cornering force인 $F_y$를 결정한다.</li>
<li>슬립각이 존재하면 타이어는 횡 방향의 힘을 생성하게 되며, 이 힘이 차량이 회전할 수 있게 한다. 타이어 횡력 $F_y$는 전륜과 후륜을 더한 $F_f\cos\delta_f+F_r$이며, 선형 근사하면 $F_y=C_\alpha\alpha$가 된다. 여기에서 $C_\alpha$는 코너링 강성이다. 하지만 $\delta$가 매우 작다고 가정하였으므로 $F_y\approx F_f+F_r$이다.<ul>
<li>참고로, 타이어 횡력이 있어야 커브를 돌 수 있다. 그리고 차량의 yaw 움직임을 설명하기 위해 타이어 횡력을 구해야 한다.</li>
</ul>
</li>
</ul>
</li>
<li><strong>차량에 작용하는 힘과 모멘트 평형식</strong><ul>
<li>측방향 힘 평형식
차량 중심 $C$에 작용하는 모든 횡방향 힘을 모으면 다음과 같이 정리된다.
$$
m(\dot{v}_y+\omega v_x)=F_f+F_r
$$
여기서 $v_y$는 측방향 속도, $\omega$는 yaw rate이다.</li>
<li>Yaw 모멘트 평형식 (Z축)
차량 중심을 기준으로 회전하려면 yaw 모멘트가 성립해야 한다. Yaw 모멘트는 차량을 좌우로 회전시키는 힘의 합이다. (부호는 시계방향일 때 마이너스이다)
$$
I_z\dot{\omega}=l_fF_f-l_rF_r
$$</li>
</ul>
</li>
<li><strong>슬립각을 바탕으로 한 타이어 힘 표현</strong><ul>
<li>앞바퀴
$$
F_f=-C_{\alpha f}\alpha_f\approx-C_{\alpha f}\tan \alpha_f=-C_{\alpha f}\delta_f-C_{\alpha f}\frac{v_y+\omega l_f}{v_x}
$$</li>
<li>뒷바퀴
$$
F_r=-C_{\alpha r}\alpha_r\approx-C_{\alpha r}\tan \alpha_r=-C_{\alpha r}\frac{v_y-\omega l_r}{v_x}
$$</li>
</ul>
</li>
<li>차량의 상태를 나타내는 상태 공간 표현
$$
\mathbf{x}=\begin{bmatrix} 
y \
v_y \
\psi \
\omega
\end{bmatrix}, \quad u=\delta_f
$$
위의 식에서 $u$는 일반적으로 운전자의 입력 (wheel)과 같다.
최종 선형화된 상태공간 모델은 다음과 같다.
$$
\dot{\mathbf{x}}=A\mathbf{x}+Bu
$$</li>
<li>모델 확장: 경사로 및 비선형 타이어<ul>
<li>노면이 기울어진 경사로 bank가 있는 경우 측방향 힘은 다음 함을 포함하게 된다.
$$
ma=F_f+F_r+F_\text{bank}(=mg\sin\theta)
$$
이는 yaw 동역학에는 영향을 미치지 않는다.</li>
</ul>
</li>
<li>큰 슬립각에서의 타이어 모델<ul>
<li>슬립각이 커질 경우 앞서 살펴본 선형 타이어 모델은 부정확하다.</li>
<li>실제 타이어의 거동은 비선형적이므로 Magic Formula, Brush, Dugoff 같은 모델을 고려해야 한다.</li>
</ul>
</li>
</ol>
<h3 id="좌표게-변환과-가속도-해석">좌표게 변환과 가속도 해석</h3>
<p>차량의 움직임을 해석할 때는 <strong>inertial frame</strong>과 <strong>rotating</strong> 좌표계를 사용한다.</p>
<ul>
<li><strong>Inertial Frame (세계 좌표계)</strong>: 고정된 기준 좌표</li>
<li><strong>Rotating Frame (차체 좌표계)</strong>: 차량에 붙어서 함께 회전하는 좌표계</li>
</ul>
<p>실제 차량 운동은 회전하는 차체 좌표계 기준에서 상대속도와 가속도를 구하고, 이를 다시 세계 기준으로 변환하는 방식으로 진행된다.</p>
<ol>
<li>극좌표계 (Polar Coordinate)<ul>
<li>$P$의 위치 벡터 $\mathbf{r}=r\mathbf{e}_r$</li>
<li>단위 벡터 $\mathbf{e}_r, \mathbf{e}_\theta$의 변화율<ul>
<li>$d\mathbf{e}_r/d\theta=\mathbf{e}_\theta, \quad d\mathbf{e}_\theta/d\theta=-\mathbf{e}_r$</li>
<li>$d\mathbf{e}_r/dt=\dot\theta\mathbf{e}_\theta,\quad d\mathbf{e}_\theta/dt=-\dot\theta\mathbf{e}_r$</li>
<li>회전하는 좌표계에서는 단위 벡터도 시간에 따라 변한다.</li>
</ul>
</li>
<li>속도와 가속도<ul>
<li>$v=\frac{dr\mathbf{e}_r}{dt}=\dot{r}\mathbf{e}_r+r\dot\theta\mathbf{e}_r$</li>
<li>$a=\frac{dv}{dt}=(\ddot{r}-r\dot\theta^2)\mathbf{e}_r+(2\dot{r}\dot{\theta}+r\ddot{\theta})\mathbf{e}_\theta$</li>
<li>여기에서 $-r\dot\theta^2$는 원심 가속도, $2\dot{r}\dot\theta$는 코리올리 가속도이다.</li>
</ul>
</li>
</ul>
</li>
<li>회전 좌표계에서의 가속도 변환
차량 중심 $C$의 운동을 회전하는 차량 좌표계에서 측정한 후, 세계 좌표계 기준으로 변환하는 것이 목표이다.
$$\frac{d^2}{dt^2}\begin{bmatrix}X \ Y \ Z\end{bmatrix}_\text{inertial} = \frac{d^2}{dt^2}\begin{bmatrix}x\y\z\end{bmatrix}_\text{rotating} + \Omega\times(\Omega\times\vec{r})+\dot\Omega\times\vec{r} + 2\Omega\times\dot{\vec{r}}
$$<ul>
<li>$\vec{\Omega}$는 차체의 각속도이다.</li>
<li>해석하면 정지된 좌표계에서 가속도는 회전 좌표계의 가속도에 원심 가속도, 오일러 가속도, 코리올리 가속도를 더한 것과 같다.</li>
</ul>
</li>
<li>차량 운동 해석에 적용
$$
\vec{a}<em>q=\dot\Omega\times r+\Omega\times(\Omega\times r)+2\Omega\times\dot{r}</em>{xyz}+\ddot{r}_{xyz} = a_x+a_y
$$
차량이 회전하면서 전진하고 있는 상황에서 가속도를 나누어 해석할 수 있다. 측방향 가속도는 다음과 같이 표현된다.
$$
a_y=\ddot{y}+\dot\psi\cdot v_x
$$
측방방향 속도 변화율과 구심 가속도를 더한 것과 같다.<h2 id="steady-state-cornering-analysis">Steady-State Cornering Analysis</h2>
앞서 일반적으로 코너링 할 때 가속도를 좌표계별로 해석하였다.</li>
</ol>
<p>차량이 일정한 반경을 따라 속력을 유지하면서 회전하는 것을 <strong>Steady-State Cornering</strong>이라고 한다. 이 경우 시간에 따라 가속도나 속도, 조향각이 변하지 않는 정상 상태가 되어 동역학 해석이 훨씬 간단해지고, 차량의 조향 특성을 분석할 수 있다.
<strong>정지 상태</strong>의 의미는 다음과 같다.</p>
<ul>
<li>측방 속도와 조향각(yaw rate)의 변화율이 0이다.</li>
<li>선회의 중심 ICR은 두 바퀴의 속도 벡터 수직선의 교점으로 구할 수 있다.<h3 id="steady-state-cornering-해석">Steady-State Cornering 해석</h3>
<ol>
<li><strong>조향각과 속도의 관계</strong>
차량이 일정한 반경 $R$을 두고 회전할 때 조향각 $\delta$는 다음과 같이 표현된다.
$$
\delta=\frac{L}{R}+\alpha_f-\alpha_r
$$
이는 정상 상태에서 $R$을 유지하기 위한 조향각으로 해석할 수 있다.</li>
<li><strong>힘과 모멘트 평형</strong></li>
</ol>
</li>
<li>측방향 힘은 $ma_y=F_f+F_r$로 표현할 수 있고, $a_y$는 다음과 같다.
$$
a_y=\dot{v}_y+\dot\psi v_x=\frac{v_x}{R}\times v_x
$$</li>
<li>요우 모멘트 평형은 다음과 같다.
$$
F_fl_f=F_rl_r
$$</li>
<li>이 두가지 조건을 바탕으로 전후륜 힘을 계산하면 다음과 같다.
$$
F_f=m\frac{l_r}{L}\frac{v_x^2}{R}, \quad F_r=m\frac{l_f}{L}\frac{v_x^2}{R}
\quad\rightarrow\quad \delta=\frac{L}{R}+\Big(\frac{ml_r}{C_fL}-\frac{ml_f}{C_rL}\Big)\frac{v_x^2}{R}
$$</li>
</ul>
<ol start="2">
<li><strong>언터스티어 계수 $K_v$</strong>
차량의 질량이 $m$이고 코너링 강성 $C_\alpha$가 있을 때 언터스티어 계수는 다음과 같다.
$$
K_v=\frac{m}{L^2}\Big(\frac{l_r}{C_{\alpha r}}-\frac{l_f}{C_{\alpha f}}\Big)
$$
언더스티어 계수는 차량이 속도에 따라 조향 반응이 얼마나 변하는지 나타낸다. $K_v&gt;0$이면 언더스티어, $K_v&lt;0$이면 오버스티어이다.</li>
<li><strong>선회 반경과 조향</strong>
조향각 $\delta$와 선회 반경 $R$은 반비례 관계에 있다. 즉, 조향각이 커질수록 더 작은 원으로 돌게 된다.
$$
R=\frac{L}{\tan\delta}\approx\frac{L}{\delta(\text{if }\delta\approx0)}
$$</li>
</ol>
<h3 id="조향-특성-분류">조향 특성 분류</h3>
<p>차량의 조향 특성은 크게 세 가지로 분류된다.</p>
<ul>
<li><strong>Understeer</strong>: $K_v&gt;0$이며, 속도가 빨라질수록 더 많이 조향해야 원 반경을 유지할 수 있다. 대부분의 차량은 언더스티어 특성을 나타내도록 설계된다. 현시대 자동차는 다양한 형태의 언더스티어로 설계된다.</li>
<li><strong>Neutral steer</strong>: 속도에 관계없이 조향각이 일정하다. 여러 변수 중 작은 변화가 생기면 오버스티어가 될 수 있기 때문에 바람직하지 않다.</li>
<li><strong>Oversteer</strong>: $K_v&lt;0$이며, 속도가 빨라질수록 조향각을 줄여야 한다. 오버스티어 특성을 나타내도록 설계되는 차량은 없다.</li>
</ul>
<ol>
<li>특성 속도 <strong>Characteristic Speed</strong><ul>
<li>언더스티어 차량에서 조향각을 Ackermann 각의 두 배로 해야할 때의 속도가 characteristic speed이다. 이 속도 이상에서는 조향각이 더 빠르게 증가하며, 차량의 언더스티어 경향이 더욱 강해진다.</li>
<li>속도가 빨라질 때 $\delta_f=\frac{2L}{R}$일 때 $R$을 유지하기 위해서 조향각 $\delta_f$를 더 키워야 한다.</li>
</ul>
</li>
<li><strong>Critical Speed</strong><ul>
<li>오버스티어 차량에서 조향각이 0이 되는 속도를 critical speed라고 한다. 이 속도 이상에서는 차량이 자체적으로 회전하려는 경향을 보여 제어가 어려워지고, 스핀 위험이 있다.
$$
0=\frac{L}{R}+K_v\frac{v_x^2}{R} \quad\rightarrow\quad v_\text{crit}=\sqrt{L/(-K_V)}
$$</li>
</ul>
</li>
</ol>
<h3 id="sideslip-angle-해석">Sideslip Angle 해석</h3>
<p>슬립각 $\beta$란 차량이 바라보는 방향 yaw와 실제 진행 방향 간의 차이이다. 차량 중심에서 뒷차축까지 거리를 $c$, 회전 반경을 $R$이라 할 때 $\beta$는 다음과 같다.
$$
\beta=\frac{c}{R}-\alpha_r
$$
저속 주행 시 후륜이 바라보는 방향과 실제 진행 방향 간의 차이 $\alpha_r$은 0이다. 따라서 저속주행 시 슬립각 $\beta$는 0보다 크므로 뒷바퀴가 안쪽을 따라 움직이며, 고속주행 시에는 0보다 작아서 불안정할 수 있다.</p>
<h2 id="주행-성능-지표-및-조향-튜닝">주행 성능 지표 및 조향 튜닝</h2>
<h3 id="성능-지표">성능 지표</h3>
<p>조향을 하면 차량은 회전하면서 횡가속을 발생시킨다. 이때 조향 입력 대비 차량이 얼마나 민감하게 반응하는지 나타내는 것이 lateral acceleration gain이다.
$$
\frac{a_y}{\delta}=\frac{Lg}{K_VV^2+Lg}
$$</p>
<ul>
<li>언더스티어 차량에서 속도가 증가하면 게인은 일정한 값으로 수렴한다.</li>
<li>뉴트럴 스티어 차량에서는 속도 제곱에 비례하여 게인이 증가한다.</li>
<li>오버스티어 차량에서는 속도가 증가할수록 게인이 폭발적으로 커켜 차량이 불안정해진다.</li>
</ul>
<p>조향은 차량의 회전 (yaw)를 유도한다. 이때 조향에 비례하여 차량이 얼마나 빠르게 방향을 바꾸는지 측정하는 지표가 yaw rate gain이다.
$$
\frac{r}{\delta}=\frac{V/L}{1+\frac{K_VV^2}{Lg}}
$$</p>
<ul>
<li>언더스티어 차량에서는 characteristic speed에서 최대값에 도달 후 감소한다.</li>
<li>뉴트럴 스티어 차량에서는 일정하게 증가한다.</li>
<li>오버스티어 차량 속도 증가 시 불안정해진다.<h3 id="steady-state-조향-tuning">Steady-State 조향 Tuning</h3>
</li>
</ul>
<ol>
<li>하중 반영한 코너링 강성 변화
타이어의 횡방향 강성은 가해지는 수직 하중이 증가할수록 더 커진다. 이로 인해 앞/뒤 타이어의 슬립각 차이가 변하며 조향 특성에 영향을 미친다.</li>
<li>중립조향 조건 유도
수직하중과 타이어 강성이 선형적이라고 가정하면 차량의 질량 주임 위치에 무관하게 항상 앞/뒤 슬립각이 같을 수 있다. </li>
<li>마찰력 분배와 비선형 효과
현실의 타이어는 비선형 거동을 보이기 때문에 하중이 많아질수록 마찰계수가 변한다. 결과적으로 앞 타이어가 더 많이 미끄러져 언더스티어의 경향을 띠게 된다.</li>
</ol>
<h2 id="모델-적용-및-비교">모델 적용 및 비교</h2>
<h3 id="좌표계-변환">좌표계 변환</h3>
<p>차량의 주행 경로를 글로벌 좌표계로 나타내기 위해 변환이 필요하다.
$$
X=X_\text{des}-e_1\sin\psi, \quad Y=Y_\text{des}+e_1\cos\psi
$$
$$
X_\text{des}=\int V\cos\psi_\text{des}dt, \quad Y_\text{des}=\int V\sin\psi_\text{des}dt
$$
$$
\psi=e_2+\psi_\text{des}
$$
이 수식들을 통해 차량이 도로 중심선에서 얼마나 벗어났는지($e_1$), 방향 오차가 얼마인지($e_2$)를 계산할 수 있다.</p>
<h3 id="bicycle-vs-full-nonlinear-model">Bicycle vs Full Nonlinear Model</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>Bicycle Model</th>
<th>Full Vehicle Model</th>
</tr>
</thead>
<tbody><tr>
<td>구성 요소</td>
<td>타이어 2개</td>
<td>실제 타이어 4개</td>
</tr>
<tr>
<td>정확도</td>
<td>저속에서 정밀</td>
<td>고속에서 부정확</td>
</tr>
<tr>
<td>계산량</td>
<td>낮음</td>
<td>높음</td>
</tr>
<tr>
<td>슬립각/요우레이트</td>
<td>대체로 일치</td>
<td>고속에서 차이가 큼</td>
</tr>
</tbody></table>
<p>경로 추종 등 간단한 제어에서 Bicycle Model을, 고속 안정성 제어 시 Full Nonlinear Model을 적용한다.</p>
<ul>
<li>시뮬레이션 비교 결과<ul>
<li>40 km/h 주행 시 두 모델 모두 유사한 결과를 보인다.</li>
<li>80 km/h 주행 시 Full model은 더 큰 슬립각, 더 빠른 yaw rate가 필요하다. 고속에서는 단순한 Bicycle Model의 한계가 명확히 드러난다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Longitudinal Controls]]></title>
            <link>https://velog.io/@hyeon-ii/Longitudinal-Controls</link>
            <guid>https://velog.io/@hyeon-ii/Longitudinal-Controls</guid>
            <pubDate>Thu, 01 May 2025 11:19:09 GMT</pubDate>
            <description><![CDATA[<h2 id="longitudinal-control-overview">Longitudinal Control Overview</h2>
<p>종방향 제어란 차량의 앞뒤 방향 움직임을 제어하는 것으로, 종방향 속도, 가속도, 앞선 차량과의 간격 조절이 이에 해당한다.</p>
<p>Standard Cruise Control은 오늘날 대부분의 자동차에서 이용 가능한 대표적인 종방향 제어 시스템이다. 운전자가 원하는 속도를 설정하면 cruise control system이 자동으로 스로틀을 조절하여 속도를 유지한다.</p>
<p>종방향 ADAS 시스템의 예로 다음과 같은 것들이 있다.</p>
<ul>
<li><strong>Cruise Control</strong>: 일정한 속도를 유지하는 시스템이다.</li>
<li><strong>Adaptive Cruise Control</strong>: 정속으로 주행하다가 속도가 느린 전방 차량과 가까워지면 라이다(radar)로 감지하여 속도를 조절하고, 거리를 유지한다. 전방 차량이 다른 차선으로 옮기면 속도를 조절한다.</li>
<li><strong>Stop &amp; Go</strong>: 정지 후 다시 출발까지 자동으로 수행하는 시스템이다.</li>
<li><strong>Collision Avoidance</strong>: 앞선 차량과의 간격 유지가 어렵다고 판단되면 경고를 울리거나 자동으로 감속한다.</li>
<li><strong>Automated Highway System</strong>: 고속도로에서 차량들이 좁근 간격을 두고 주행할 수 있어 교통 흐름 개선에 도움이 된다.</li>
</ul>
<p>이러한 시스템은 차량의 센서를 기반으로 차량의 상태를 측정하고, 제어기가 속도, 거리, 가속도를 조절해주는 방식으로 작동한다.</p>
<h2 id="cruise-control">Cruise Control</h2>
<h3 id="cruise-control-system-overview">Cruise Control System Overview</h3>
<p>Cruise Control System은 고속도로에서 유용한 기능으로, 버튼으로 켜고 끌 수 있으며, 사용자의 페달 입력이 발생하면 종료된다.</p>
<ul>
<li>측정값: Ego 차량의 현재 속도</li>
<li>조작값: 스로틀(엔진에 들어가는 공기양), 브레이크 패달은 조절하지 않는다.</li>
<li>제어 목표: 설정한 속도를 정상 상태 오차 없이 유지하는 것<ul>
<li>정상상태 오차는 안전과 직결되므로 운전자에 의해 결정된 지정 속도를 정상상태 오차 없이 추종하는 것이 중요하다.<h3 id="controller-구조">Controller 구조</h3>
Cruise Control System은 두 개의 제어기 계층으로 나눌 수 있다.</li>
</ul>
</li>
</ul>
<ol>
<li>Upper Controller<ul>
<li>입력: 설정 속도, 현재 차량 속도</li>
<li>출력: 차량이 따라야 할 목표 가속도</li>
</ul>
</li>
<li>Lower Controller<ul>
<li>입력: 상위 제어기가 만든 목표 가속도</li>
<li>출력: 스로틀 밸브를 조절해서 실제 차량을 가속하거나 감속<h3 id="upper-controller">Upper Controller</h3>
상위 제어기는 설정한 속도와 현재 속도의 차이를 기반으로 하위 제어기에 전달할 가속 신호를 생성한다. 실제 차량은 가속 페달을 밟는다고 해서 즉시 속도가 올라가지 않고 무게 등 여러 요인으로 인해 천천히 변화한다. 이러한 상위 제어기는 간단한 1차 지연 함수로 모델링할 수 있다.
$$
\frac{1}{1+\tau s}
$$</li>
</ul>
</li>
</ol>
<ul>
<li>$\tau$: 시스템이 반응하는 속도(시정수, 보통 0.5~1초로 설정), 지연 정도를 나타내는 상수이다.</li>
<li>$s$: 시간 도메인을 주파수로 바꾸는 변수</li>
</ul>
<p>이 모델은 운전자가 어떤 입력을 주면, 차량은 바로 반응하지 않고 지연되는 것을 수학적으로 표현한 것이다.</p>
<ul>
<li>입력이 1(True)로 바뀌고 시간이 $\tau$일 때 출력은 입력의 약 63%에 도달한다. $\tau$를 1로 결정할 경우 1초 뒤 약 63%의 지연이 발생한다. 시간이 $3\tau$일 때 출력은 입력의 95%에 도달한다. 이걸 지연된 추종이라고 부른다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/02aff553-662e-4332-bfdd-c9e09e7ec7e0/image.png" alt="">
설정한 목표 속도 $V_{des}$에 따라 상위 제어기가 목표 가속도를 계산하면 지연함수에 의해 실제 속도가 변화한다.</p>
<p>실제 가속 값은 다음과 같이 계산된다.
$$
\ddot{x}=\frac{1}{\tau s+1}\ddot{x}_{des}
$$</p>
<p>상위 제어기는 속도 오차 $e(t)$를 보고 차량이 어느 정도 가속해야 하는지 결정한다. 하지만 지연이 발생하게 되면 단순한 비례 제어만으로는 오차가 남을 수 있다. 따라서 PD 제어, PI 제어를 통해 오차를 빠르게 줄여야 한다.</p>
<ul>
<li>PD 제어 $K_P+K_DS$
<strong>Proportional</strong> 제어는 오차가 클수록 더 크게 조절하는 제어, <strong>Derivative</strong> 제어는 오차의 변화량에 반응하여 예측 조절하는 제어이다.<ul>
<li>속도 오차 $e(t)=V_{dex}-V_x$</li>
<li>$\ddot{x}_{des}(t)=k_p\cdot e+k_d\cdot\dot{e}$</li>
<li>오르막, 또는 내리막에서 PD제어는 큰 도움이 되지 않는다. 제어를 통해 안정 상태에 도달하여도 error가 지속되는 경우에는 $k_p$를 키우거나 다른 feedforward term을 추가하여 해결할 수 있다.</li>
</ul>
</li>
<li>PI 제어 $K_P+K_I/S$<ul>
<li><strong>Integral</strong> 제어는 누적된 오차를 없애기 위해 천천히 조절하는 제어이다.</li>
<li>$\ddot{x}_{des}(t)=-k_pe(t)-k_I\int_0^te(t)dt$</li>
<li>$\ddot{x}<em>{des}(t)=-k_p(\dot{x}-\dot{x}</em>{des})-k_I(x-x_{des})$</li>
<li>I term은 오차가 누적되어 시스템이 발산하는 문제로 이어질 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="lower-controller">Lower Controller</h3>
<p>하위 제어기는 상위 제어기로부터 전달받은 목표 가속도를 입력으로 하여, 실제 차량의 가속도가 원하는 값이 되도록 스로틀(엔진 토크)을 조절한다. 하위 제어기에는 다음과 같은 가정이 앞선다.</p>
<ul>
<li>자동 변속할 때 사용하는 장치인 토크 컨버터는 Lock-up 된 상태이다. 순항 제어 기능은 보통 고속 주행 시 사용하기 때문이다.</li>
<li>타이어와 노면에서 생기는 타이어 슬립의 크기는 0이다.</li>
</ul>
<p>하위 제어기는 차량 종방향 운동, 파워트레인 모델을 이용하여 설계된다. 목표 가속도를 받고, 운동 방정식을 바탕으로 필요한 엔진 토크를 계산한 뒤, 그 토크를 만들어내기 위한 스로틀 각도를 계산하여, 액추에이터를 작동시켜 차량을 실제고 가속시킨다.</p>
<ul>
<li>Vehicle Longitudinal Dynamics
$$
m\ddot{x}=F_{xf}-F_{aero}-R_{xf}-R_{xr}-mg\sin\theta
$$</li>
<li>Powertrain Model<ul>
<li>바퀴의 각속도는 엔진의 각속도에 비례하므로 $\omega_w=R\cdot\omega_e$가 성립하고 $\omega_e=\omega_t$로 엔진과 변속기 속도와 동일하다.</li>
<li>유효 바퀴 반지름이 $r_{eff}$일 때 차량의 속도 $\dot{x}=V_x=r_{eff}\cdot\omega_w$</li>
<li>가속도 $\ddot{x}=r_{eff}\cdot R\cdot\dot{\omega}_e$</li>
</ul>
</li>
</ul>
<p>$$
F_{xf}=mr_{eff}R\dot{\omega}<em>e+F</em>{aero}+R_{xf}+R_{xr}+mg\sin\theta
$$</p>
<ul>
<li>Wheel Dynamics<ul>
<li>바퀴의 관성 모멘트가 $I_w$이고 바퀴에 전달된 토크가 $T_\text{wheel}$일 때 $I_w\dot{\omega}<em>w=T_\text{wheel}-r</em>{eff}F_{xf}$가 성립한다. (앞서 구한 $F_{xf}$로 대입 가능)</li>
</ul>
</li>
</ul>
<h2 id="adaptive-cruise-control">Adaptive Cruise Control</h2>
<h3 id="적응형-순항-제어">적응형 순항 제어</h3>
<p>ACC는 크루즈 컨트롤의 발전된 제어 시스템이다. 크루즈 컨트롤은 설정한 속도를 일정하게 유지하고, 앞차가 생겨도 무시하기 때문에 운전자가 브레이크를 수동으로 밟아야 한다. 반면에, 적응형 크루즈 컨트롤은 가속 페달과 브레이크 페달을 사용하지 않고, 운전자가 설정한 속도로 자동 주행을 하다가 차량 전면부의 레이다 센서 등을 사용하여 전방 차량이 감지되면 전방 차량과의 거리를 자동으로 유지할 수 있다.</p>
<h3 id="acc의-시스템">ACC의 시스템</h3>
<p>전방에 차량이 존재하지 않을 경우 지정된 <strong>속력을 제어</strong>하고, 전방에 차량이 존재할 경우 전방 차량과의 <strong>거리를 유지</strong>하며 추종 제어해야 한다.
ACC를 구성하는 시스템은 크게 센서, 액추에이터, 제어기가 있다.</p>
<ul>
<li>센서: 휠 속도 센서, 브레이크 페달 센서, 스로틀 페달 센서, 레이다 등의 센서로 차량 간 상대 거리 및 상대 속도 등 필요한 값을 모두 측정할 수 있다고 가정한다.</li>
<li>액추에이터: 브레이크 및 스로틀 엑추에이터</li>
<li>제어기: 상위 제어기와 하위 제어기</li>
</ul>
<h3 id="acc의-안정성-요구-조건">ACC의 안정성 요구 조건</h3>
<p>ACC의 stability(안정성)으로는 크게 두 가지가 있다. &quot;Ego 차량&quot; 자체의 안정성과 여러 대의 차량이 줄지어 주행하는 &quot;군집 차량들&quot; 안정성.</p>
<h4 id="individual-stability">Individual Stability</h4>
<p>개별 안정성을 나타내며, 자차량 안전 조건을 뜻한다. 한 대 한 대 안정적으로 따라가는 것을 만족하면 individual stability를 만족한다.</p>
<ul>
<li>전방 차량의 가속도가 0일 때 거리 오차가 0이 될 수 있는지에 대한 기능적 여부 $\text{If }\ddot{x}_{i-1}\rightarrow0, \text{THEN }\delta_i\rightarrow0$</li>
<li>거리 오차$(\delta)$는 유지하고 싶은 간격 $L_\text{des}$와 실제 간격의 차이를 의미한다. $\delta_i=L_\text{des}-(x_{i-1}-x_i)$</li>
<li>$\delta_i$를 미분하면 $\ddot{\delta}<em>i=\ddot{x}_i-\ddot{x}</em>{i-1}$<h4 id="string-stability">String Stability</h4>
ACC 기능을 수행하는 여러 대의 차량 대열에서, 각 차량 가나 인지, 제어 등 시간 지연에 따른 차량 간의 거리 오차 증폭을 방지하기 위한 조건을 뜻한다.</li>
<li>오차 값이 증폭될 경우, 뒤따라 주행하는 차량 간의 사고를 유발할 수 있다. 이러한 이유로, Individual stability를 만족하더라도 String stability는 만족하지 않을 수 있다.</li>
<li>거리 오차 전달 함수의 크기는 1보다 작아야 한다. 전달함수의 크기가 1보다 크면 전달함수 간 곱셈에 의해 거리오차가 증폭될 가능성이 있기 때문이다.
$$
\hat{H}(s)=\frac{\delta_i}{\delta_{i-1}}, \quad |\hat{H}(s)|&lt;1\quad\therefore|\delta_i|<em>2\le|\delta</em>{i-1}|_2
$$</li>
<li>Impulse 입력에 대한 거리 오차의 부호는 동일해야 한다.<ul>
<li>예를 들어 $i$번째, $i+1$번째 차량이 $\delta_{i+1}&lt;0$ 상태에서 거리 오차를 줄이기 위해 $i+1$ 차량이 가속하고, $\delta_{i}&gt;0$ 상태에서 가장 앞서가는 $i-1$번째 차량과 간격을 키우기 위해 $i$번째 차량이 감속한다면 $i,i+1$ 차량 간 충돌이 발생한다.</li>
</ul>
</li>
</ul>
<p>ACC 제어 시스템을 통해 운전 주행 안정성을 개선하고 운전으로 인한 피로를 줄일 수 있다. 또한 운전자의 부주의에 의한 사고를 줄일 수 있다.</p>
<h3 id="upper-controller-1">Upper Controller</h3>
<p>전방 차량과 일정 거리를 유지하거나 전방 차량과 상대 속도를 유지하는 방식으로 설계할 수 있다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/a50dccd6-3b56-4301-bf87-ecbded3244d7/image.png" alt=""></p>
<ul>
<li><strong>Constant Spacing Policy</strong>: 전방 차량과 제어 차량의 상대 거리를 항상 일정하게 유지<ul>
<li>전방 차량과 유지해야하는 거리 $L_\text{des}$는 상수이다.</li>
<li>가속도를 PD 제어 입력으로 단순화했을 때 $\ddot{x}_i=-k_p\delta_i-k_d\dot\delta_i$</li>
<li>거리 오차 $\delta$는 현재 전방 차량과의 간격, 그리고 목표 간격의 오차이므로 $x_i-x_{i-1}+L_\text{des}$로 계산된다.
$$
\ddot{\delta}<em>i=\ddot{x}_i-\ddot{x}</em>{i-1}=(-k_p\delta_i-k_d\dot\delta_i)-(-k_p\delta_{i-1}-k_d\dot\delta_{i-1})
$$</li>
<li>라플라스 변환을 거치면 아래의 전달함수가 정의된다.
$$
\frac{\delta_i}{\delta_{i-1}} = \frac{k_ds+k_p}{s^2+k_ds+k_p}=\frac{k_p}{s^2+k_ds+k_p}\cdot\Big(\frac{k_d}{k_p}s+1\Big)=G_1(s)\cdot G_2(s)
$$</li>
<li>String Stability를 만족하기 위해서는 $|H(s)|_\infin&lt;1$을 만족해야 한다. 즉, 어떤 주파수에서도 앞차의 신호가 ego 차량에서 더 커지지 않아야 한다. 전달 함수를 분해하면 $G_1\cdot G_2$로 표현할 수 있다.<ul>
<li>$G_1$은 감쇠 조건으로, $\frac{k_d}{2\sqrt{k_p}}\ge0.707, \quad k_d\ge1.414\sqrt{k_p}$을 만족해야 1보다 작아진다.</li>
<li>$G_2$는 제로 영향 조건으로, $\sqrt{k_p}&gt;k_d$를 만족해야 1보다 작다.</li>
<li>즉, $k_d$는 충분히 커야 하지만 너무 크면 안 되는 모순이 발생한다. 결론적으로 constant spacing policy는 individual stability는 만족할 수 있지만 string stability는 만족할 수 없기 때문에 ACC에 부적합하다.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Constant Time-gap Policy</strong>: 전방 차량과 제어 차량 간의 상대 거리를 시간으로 환산하여 일정 시간 차이를 둘 수 있도록 제어<ul>
<li>희망 유지 거리를 자차량의 속도에 비례하도록 설정한다. 앞 차의 길이가 $l_{i-1}$일 때 유지하고 싶은 거리 $L_\text{des}$는 $l_{i-1}+h\dot{x}_i$로 표현된다. 해석하면, 자차의 속도가 빠를수록 더 멀리 떨어져야 안전하다는 것을 의미한다고 볼 수 있다.</li>
<li>거리 오차 $\delta$는 $L_\text{des}-(x_{i-1}-x_i)$이므로 전개하면 $x_i-x_{i-1}+h\dot{x}_i$로 표현할 수 있다.</li>
<li>제어의 목적은 희망 유지 거리 $L_\text{des}$와 현재 거리의 오차 $\delta$를 0으로 수렴시키는 것이다. 미분 방정식을 이용하여 $\dot{\delta}_i=-\lambda\delta_i$와 같이 표현된다.</li>
<li>CS 정책과 마찬가지로 PD 제어기에서 제어 입력은 $u_i=\ddot{x}_i=-k_p\delta_i-k_d\dot{\delta}_i$이므로 $\dot\delta_i=\dot{\epsilon}_i+h(-k_p\delta_i-k_d\dot\delta_i)$이다. 하지만 앞서 구한 $\dot{\delta}_i=-\lambda\delta_i$와는 등식이 성립하지 않으므로 단순 PD 제어기는 CTG ACC 전략에 적합하지 않다. CTG는 속도에 따라 오차 정의가 달라지고, 이것이 다시 오차 미분에 영향을 주기 때문에 오차를 제대로 0으로 수렴시키기 어렵다. 따라서 제어 목적을 달성하기 위해 설계한 제어기는 거리 오차와 상대 거리 두 항을 동시에 이용한다.
 $$
 u_i=\ddot{x}_i=-\frac{1}{h}(\epsilon_i+\lambda\delta_i)
 $$<ul>
<li>위 식은 상대 속도 $\dot\epsilon_i$ 항을 소거하기 위해 $k_d=\frac{1}{h}$로 설정하여 유도한 것이다.</li>
<li>시간 지연 함수에 따라 계산하면 전달함수가 도출된다.
$$
\hat{H}(s)=\frac{\delta_i(s)}{\delta_{i-1}(s)}=\frac{s+\lambda}{h\tau s^3+hs^2+(1+\lambda h)s+\lambda}
$$</li>
<li>이 전달함수가 모든 주파수 영역에서 1보다 작으려면 $h\ge2\tau$를 만족해야 한다.<h3 id="range-range-rate-기반-제어기-설계">Range-Range Rate 기반 제어기 설계</h3>
ACC 주행 중에 상황이 급변할 때 속도 제어에서 거리 제어 모드로 전환하는 <strong>Transitional Control</strong>이 필요하다. 전환 제어 설계에서 중요한 것은 승차감과 안전성이 중요하다. 앞차가 갑자기 생겼을 때 속도로 제어할 것인지, 거리 제어로 전환할 것인지, 충돌 회피를 위해 급제동할 것인지 결정해야 한다. 이 판단을 <strong>거리와 상대 속도 다이어그램</strong>을 기반으로 결정한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>앞차와의 거리 $R$, 상대 속도 $\dot{R}=v_p-v$일 때 상대 감속이 일정하다고 한다면 다음이 성립한다.
$$
\ddot{R}=\frac{\dot{R}-\dot{R}_0}{t}=C
$$
이때 $C$는 감속량으로, 상수이다. 시간에 대해 적분하면 $\dot{R}(t)=\dot{R}_0+Ct, \R(t)=R_0+\dot{R}_0t+\frac{1}{2}Ct^2$이고 여기서 시간 $t$를 제거하면 다음 식이 유도된다.
$$
R=R_0+\frac{\dot{R}_0}{C}(\dot{R}-\dot{R}_0)+\frac{1}{2C}(\dot{R}-\dot{R}_0)^2
$$
$R$과 $\dot{R}$ 사이에 제곱 관계가 존재하고, 이를 통해 $R-\dot{R}$ 다이어그램을 구성할 수 있다.</p>
<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/a4bd88d4-b831-4b32-8407-88bd8c98c707/image.png" alt=""></li>
<li>앞 차와 거리가 길거나 앞에서 빠르게 가서 상대 속도가 크다면 속도 제어를 유지하고, 이에 비해 가깝거나 앞에서 천천히 간다면 거리로 제어한다.<ul>
<li>지나치게 가깝거나 앞에서 느리게 간다면 충돌이 발생할 가능성이 크기 때문에 즉시 제동이 필요하다.</li>
</ul>
</li>
</ul>
<h2 id="car-following-model">Car-Following Model</h2>
<h3 id="car-following-theory">Car Following Theory</h3>
<p>동일 차로 주행 시 뒷 차가 앞차의 주행 상태에 따라 적절하게 추종하는지에 대해 설명하는 이론이 차량 추종 이론이다. 일반적으로 ACC, 교통 흐름 시뮬레이션 등에 쓰이는데, 차량 간 간격을 유지하거나 string stability 평가 등에 필요하다.</p>
<p>(현실 반영도가 높아 자율주행에서도 자주 쓰인다.)</p>
<h3 id="intelligent-driver-model">Intelligent Driver Model</h3>
<p>안정적인 가감속으로 최소 안전 거리를 유지하면서 설정된 거리를 유지하고 주행할 수 있도록 고안된 차량 추종 모델로, 연속적이고 정확하면서 간단하기 때문에 차량추종 모형에 오랫동안 사용되었다.</p>
<h2 id="anti-lock-brake-system">Anti-lock Brake System</h2>
<p>ABS란 급제동 시 바퀴가 멈추는 걸 방지해서 차량이 미끄러지지 않고, 제동 중에도 조향할 수 있게 해주는 시스템이다. 바퀴가 잠기면 다음과 같은 문제가 발생할 수 있다.</p>
<ul>
<li>바퀴가 굴러가야 핸들이 돌아갈 수 있다. 바퀴가 잠기면 조향이 불가능해진다.</li>
<li>바퀴가 미끄러지면 제동 거리가 증가한다.</li>
<li>차가 직선으로만 밀리고, 앞의 장애물을 회피할 수 없어 안전성이 떨어진다.</li>
</ul>
<p>ABS는 바퀴가 잠기기 직전 상태를 유지하게 한다. ABS의 목표는 다음과 같다.</p>
<ul>
<li>타이어가 지면과 접촉할 때, 적절한 슬립율 <strong>Slip ratio</strong>를 유지하면</li>
<li>종방향 마찰력(제동력)도 최대로 유지되고</li>
<li>횡방향 마찰력(조향력)도 유지할 수 있다.
이때, 슬립율은 0.1~0.2 사이의 값이 이상적이다.</li>
</ul>
<p>하지만, 노면마다 서로 다른 최적의 slip을 찾아야 하고 노면 형태를 예측하기 어렵기 때문에 ABS는 고난이도의 시스템이다. 또한 휠의 속도는 측정할 수 있지만 차량의 속도는 파악할 수 없고 브레이크 압력을 측정할 수 없기 때문에 slip을 측정하기 어렵고, 최적의 slip을 찾는 것은 더욱 어렵다. </p>
<h3 id="abs-구성-요소">ABS 구성 요소</h3>
<p>하드웨어 구성은 다음과 같다.</p>
<ul>
<li><strong>Wheel speed sensor</strong>: 각 바퀴의 회전 속도를 측정한다.</li>
<li><strong>Hydraulic actuator</strong>: 브레이크 압력을 조절하는 디지털 밸브</li>
<li><strong>Control unit</strong>: 제어 로직을 실행한다.</li>
</ul>
<h3 id="abs-동작">ABS 동작</h3>
<p>ABS는 바퀴가 잠기려고 하면 브레이크 압력을 줄이고, 다시 굴러가기 시작하면 브레이크 압력을 다시 높이는 걸 수 밀리초 단위로 반복한다. 브레이크 압력은 3가지 밸브 동작으로 조절할 수 있다.</p>
<ul>
<li><strong>Apply</strong>: 압력을 유지한다. 평상시에는 열려 있는 밸브이다.</li>
<li><strong>Dump</strong>: 압력을 해제한다.</li>
<li><strong>Hold</strong>: 압력을 유지한다.</li>
</ul>
<p>바퀴가 잠길 것 같을 때 Apply 밸브를 닫고, 과도하게 전달된 압력은 accumulator에 저장된다.</p>
<h3 id="conventional-abs">Conventional ABS</h3>
<p><strong>Conventional ABS</strong>는 규칙 기반 제어 방식으로, 다음과 같이 특징이 있다.</p>
<ul>
<li>바퀴 회전 속도, 감속도, 슬립율 등을 지속적으로 감지하고 슬립율이나 감속도가 기준치를 넘으면 밸브를 조절한다.<ul>
<li>브레이크 압력을 줄이고, 바퀴 회전이 다시 시작되면 압력을 높인다. 이처럼 <strong>apply, dump, hold</strong>를 디지털 밸브로 짧은 시간 안에 빠르게 반복하면서 바퀴가 잠기지 않도록 한다.</li>
</ul>
</li>
<li><strong>if / then</strong> 방식의 단순한 로직으로, 경제적이고 안정적이지만, 최적의 성능은 아니다.</li>
<li>바퀴 회전 속도, 감속도, 밸브 열림 유무 정보를 기반으로 <strong>&quot;바퀴가 급하게 느려지면 압력을 줄이고, 바퀴가 다시 굴러가면 압력을 다시 올린다.&quot;</strong></li>
</ul>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/2cdb6763-0854-4e1b-964f-2318ac2368ce/image.png" alt="">
Conventional ABS가 잘 작동하려면 노면 마찰력 $\mu$에 따라 슬립율을 맞추어야 한다. 하지만 현실에서는 노면이 매우 다양하다. (마른 도로, 눈길, 자갈길, 빙판길, 왼쪽 바퀴만 미끄러운 상황 등) 그래서 정확한 마찰 계수나 최적 슬립율을 알기 어렵다. 결국 규칙 기반 방식은 보수적으로 설계될 수밖에 없다.</p>
<p>전통적인 방식의 ABS는 정확한 차량 속도를 측정하기 어렵고, 노면 상태를 알 수 없고, 반복된 apply/dump로 과도하게 유압이 소모되는 문제점이 있다.</p>
<h2 id="traction-control-system">Traction Control System</h2>
<p>미끄러운 노면에서 바퀴가 헛돌지 않도록 제어해서 안정적인 가속과 주행이 가능하도록 하는 시스템을 TCS라고 한다. 가속 중에 바퀴가 헛돌아 엔진 토크가 과도해지는 것이 감지되면 TCS는 브레이크 압력을 조절한다. 바퀴 속도를 줄이는 이 과정은 다시 힘을 얻게 되어 구동력과 안정성이 높아진다.</p>
<p>바퀴가 헛돌면 다음과 같은 문제가 발생할 수 있다.</p>
<ul>
<li><strong>RWD</strong> 차량은 뒷바퀴가 미끄러져서 차량이 돌게 된다.</li>
<li><strong>FWD</strong> 차량은 앞바퀴가 헛돌게 되면 핸들 조향이 불가능해진다.</li>
<li><strong>4WD</strong> 차량은 뒷바퀴가 미끄러지고, 앞바퀴가 헛돌아서 전체적으로 불안정해진다.</li>
</ul>
<p>구동력이 지면에 전달되지 않으면 가속도 안 되고 조향도 안 된다.</p>
<h3 id="동작-원리">동작 원리</h3>
<p>바퀴가 헛돌면 그 바퀴에 브레이크를 살짝 작동한다. 그러면, 반대편 바퀴에 더 많은 토크가 분배되어 전체 차량이 안정적으로 움직이게 된다. 바퀴가 헛돌지 않도록 하기 위해 크게 두 가지 방식으로 제어한다.</p>
<ol>
<li><strong>Engine torque reduction</strong>
바퀴가 헛도는 원인은 엔진이 바퀴에 너무 큰 힘을 전달하기 때문이다. 이럴 때 TCS는 엔진이 바퀴에 주는 힘을 줄여서 바퀴가 헛돌지 않도록 조절한다. 이를 위해 사용하는 대표적인 방법은 다음과 같다.<ul>
<li>스로틀 각도 제어: 가속 페달을 밟아도, 전자식 스로틀을 이용해 엔진에 들어가는 공기량을 줄여서 엔진 출력을 줄이고 바퀴에 더 적은 힘을 전달한다.</li>
<li>점화 타이밍 조절: 연료에 불꽃을 점화하는 시점을 늦추어 엔진 출력을 줄이고 엔진 반응을 빠르게 줄인다.</li>
<li>연료 컷: 연료 공급을 일시적으로 차단하여 엔진 토크를 거의 없애버린다. 다만, 이 방식은 배출가스 문제가 생기기 쉽게 때문에 자주 쓰이지는 않는다.
이 방식은 브레이크 제어보다 느리다. 또한 PD 제어에서 $K_P$보다 $K_D$ 성분이 안정성에 더 도움이 된다.</li>
</ul>
</li>
<li><strong>Brake control</strong>
가속할 때 한쪽 바퀴만 헛도는 경우가 많은데, 이럴 때에는 해당 바퀴에만 브레이크를 살짝 걸어 헛도는 바퀴를 늦추고, 정상적인 바퀴로 토크를 보내주는 방식이다. 이런 브레이크 제어는 노면 마찰 계수가 좌우 바퀴마다 다른 <strong>split-$\mu$</strong> 상황에서 효과적이다. 예를 들어 한쪽 바퀴가 눈밭에 빠졌을 때 TCS는 그 바퀴에 브레이크를 걸고, 접지력이 좋은 쪽 바퀴로 토크를 옮겨 안정적인 주행을 유도한다.
이 방식은 Advanced ABS와 유사하게 연속 슬립 제어를 사용한다.</li>
</ol>
<p>이러한 작동 방식은 ABS와 유사한 점이 있다.</p>
<ul>
<li>제어 목적: 마찰력을 최대로 활용한다.</li>
<li>속도 측정: 차량 속도는 모르고 바퀴의 속도만 측정한다.</li>
<li>제어 방식: apply/dump 방식을 공유한다. 유압 밸브를 적용한다.</li>
<li>사용 센서: 4WD의 경우 가속도 센서로 휠 속도를 측정한다.</li>
</ul>
<p>반면, 다음과 같은 차이점이 있다.</p>
<ul>
<li>압력 생성: 펌프로 직접 제어</li>
<li>속도 인식: 2WD는 차량 속도를 알 수 있다.</li>
<li>제어 입력: 엔진 토크와 브레이크</li>
<li>요구 성능: 저속에서도 민감한 제어를 요구한다. (언덕길 정지 후 출발 등)</li>
<li>기타: TCS는 수동으로 해제할 수 있고, 마찰이 작은 노면에 특화되어 있다.</li>
</ul>
<h3 id="제어-시-고려-사항">제어 시 고려 사항</h3>
<ul>
<li>부드러움과 최대 접지력 모두 만족해야 한다.</li>
<li>정지 상태에서 출발하거나, 도로 마찰 $\mu$가 변화하는 상황, 언덕 주행 상황에서 즉각적인 반응이 필요하다.</li>
<li>바퀴가 뒤로 돌면 감지하기 어렵다.</li>
<li>주차하거나 저속으로 회전할 때에는 바퀴의 속도가 모둗 달라 오작동 가능성이 있다.<h3 id="tcs-정리">TCS 정리</h3>
좋은 Traction Control은 부드럽지만 가속이 충분하고, 반응이 빠르고, split $\mu$ 언덕에서도 밀리지 않고 올라간다.</li>
</ul>
<p>4WD 차량은 다음과 같은 어려움이 있다.</p>
<ul>
<li>차량 절대 속도를 측정할 수 없다.</li>
<li>가속도계 등 추가 장치를 사용하여 센서 보정이 필요하다.</li>
<li>다양한 상황에서 튜닝이 필요하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Convolution Neural Network]]></title>
            <link>https://velog.io/@hyeon-ii/Convolution-Neural-Network-Architectures</link>
            <guid>https://velog.io/@hyeon-ii/Convolution-Neural-Network-Architectures</guid>
            <pubDate>Tue, 22 Apr 2025 08:11:43 GMT</pubDate>
            <description><![CDATA[<h2 id="cnn의-등장">CNN의 등장</h2>
<p>Neural Network 이전에 이미지를 처리하기 위해 <strong>Histogram of Oriented Gradients (HoG), Bag of Words</strong> 활용하여 직접 feature를 추출하여 처리했다. Feature extraction 방법은 최적의 성능이 보장되지 않는 문제가 있다.</p>
<h3 id="cnn-history">CNN: History</h3>
<ol>
<li>LeNet<ul>
<li>최초의 Convolutional Neural Network인 LeNet은 깊이가 얕고 크기가 작아서, 작은 데이터를 처리하기에 유용하다.</li>
</ul>
</li>
<li>AlexNet<ul>
<li>ILSVRC 2012에서 우승한 AlexNet은 LeNet과 유사하지만 더 깊고 크기가 크며, 유의미한 정규화 (Drop out) 과정이 포함되어 있다.</li>
<li>사람이 직접 특징을 추출하는 hand craft feature 시대에서 <strong>End-to-End</strong>로 처리하여 최적의 파라미터를 구할 수 있는 시대가 열렸다.</li>
<li>적었던 데이터는 ImageNet이라는 큰 데이터셋의 등장으로 해결되었고, 과적합과 기울기 소실 문제는 ReLU와 Drop out의 사용으로 해결할 수 있었다. 또한 시간 복잡도 문제는 GPU 사용으로 해결하였다. 이를 통해 CNN의 사용이 활발해졌다.<h3 id="convolution-layer">Convolution Layer</h3>
CNN을 구성하는 것으로는 <strong>Convolutional layers, Pooling layers, Fully-connected layers, Activation function, Normalization</strong>이 있다.</li>
</ul>
</li>
</ol>
<ul>
<li>$[32\times32\times3]$ 이미지가 있을 때 필터의 채널 또한 $3$이어야 한다. 예) $[5\times5\times3]$<ul>
<li>필터와 동일한 크기의 이미지 일부와 필터를 곱하고 bias를 더한다. 예) $[32\times32\times3] \rightarrow [28\times28\times1]$ 크기의 activation map</li>
<li>필터의 개수에 따라 최종적으로 생성되는 activation map의 개수가 결정된다. 예) 필터 개수가 6개이면 $[6\times28\times28]$ 크기의 activation maps</li>
<li>필터 하나 당 scalar인 bias가 하나씩 포함된다.</li>
<li>입력한 이미지의 개수에 따라 출력되는 activation maps 즉, output의 개수가 결정된다. 이는 Batch of images라고 부른다. 예) $2\times3\times32\times32 \rightarrow [2\times6\times28\times28]$</li>
<li>요약하면 $[N\times C_{in}\times H\times W]$ 입력 이미지는 $[C_{out}\times C_{in}\times K_w\times K_h]$ 필터를 거쳐 $[N\times C_{out}\times H&#39;\times W&#39;]$ outputs을 생성한다.</li>
</ul>
</li>
</ul>
<h3 id="structure-of-cnns">Structure of CNNs</h3>
<p>$[32\times32\times3]$ 크기의 이미지는 6개의 $[5\times5\times3]$ 필터 연산을 한 후 활성화 함수를 거쳐 $[28\times28\times6]$ 출력을 생성한다. 활성화 함수는 일반적으로 ReLU 함수가 사용되며, linear layer 여러 개로 구성된 Neural Network와 마찬가지로 Conv, Nonlinear와 같이 비선형 함수가 반드시 포함되어야 한다.</p>
<h3 id="spatial-dimensions">Spatial Dimensions</h3>
<p>보통 가로와 세로 $H, W$가 동일하므로 $N$으로 표기한다.
필터의 크기가 $F$, stride가 $S$, padding이 $P$일 때 출력의 폭, 높이는 다음과 같다.
$$
N&#39;=\frac{N-F+2P}{S}+1
$$</p>
<ul>
<li>Stride가 1일 때 크기 정보를 유지하기 위해서는 다음이 성립해야 한다. $N=N-F+2P+1\rightarrow P=\frac{F-1}{2}$<ul>
<li>필터 크기가 3이면 패딩은 1, 5이면 패딩은 2, 7이면 패딩은 3이어야 크기가 유지된다.</li>
</ul>
</li>
</ul>
<p>이미지가 입력되고 다음 map으로 넘어가면서 한 픽셀을 결정하는 이전 픽셀 크기는 <strong>Receptive Fields</strong>라고 한다. 이 영역이 넓을수록 <strong>한 픽셀을 결정하는 데 더 많은 정보를 활용한 것</strong>이므로 더 효율적이다. $L$개의 레이어에서 $K$ 크기의 필터를 사용하였다면 receptive field size는 $1+L\times(K-1)$이다.</p>
<p>일반적으로 필터의 개수는 2의 자승으로 설정하며, (필터 사이즈, stride, padding)은 다음과 같은 값이 주로 사용된다. $(3,1,1), (5,1,2), (5,2,\cdot), (1,1,0)$</p>
<ul>
<li>$[1\times1]$ 필터는 각 픽셀에서 Fully-connected layer 연산을 하는 것과 같다. 이때, 공간 정보는 유지되고 채널 크기만 변경된다. 대표적으로 GoogLeNet에서 사용되었다.</li>
</ul>
<h3 id="뇌의-관점에서-convolution-layer">뇌의 관점에서 Convolution Layer</h3>
<ul>
<li>입력 이미지가 $[32\times32]$인데 출력은 $[28\times28]$인 건, 각 뉴런이 입력의 전체를 보는 것이 아니라, $[5\times5]$ 같은 작은 영역(receptive field)만 본다는 것을 의미한다.</li>
<li>이 뉴런은 그 작은 입력에 대해 weight와 bias를 적용한 후 활성화 함수를 통해 출력을 만들며, 모든 뉴런이 동일한 weight, 즉 필터를 공유한다. 다시 말해 convolution은 지역적이고 파라미터를 공유한다.</li>
<li>필터가 여러 개일 때는, 같은 위치를 여러 시각에서 본다는 것을 의미한다. 예를 들어 필터가 5개이면 출력은 $[28\times28\times5]$의 3차원 형태가 된다. 같은 입력 위치라도 서로 다른 필터들이 독립적인 시각으로 처리하므로 같은 위치에 대해 5개의 서로 다른 뉴런이 존재하는 것이다. 결국, 여러 필터는 한 영역을 각기 다른 방식으로 인식한다.</li>
</ul>
<p>이런 방식은 시각 피질의 동작 원리와도 유사하며, CNN이 이미지를 효과적으로 처리할 수 있는 이유이다.</p>
<h3 id="pooling-layer">Pooling Layer</h3>
<p>Pooling layer는 파라미터가 없고, 채널과는 무관한 레이어로, Receptive field를 늘리는 가장 쉬운 방법이다.</p>
<ul>
<li>대표적인 방법으로 Max Pooling이 있다. $[2\times2]$ 크기의 레이어를 stride 2로 설정한다면 앞서 본 필터 연산과 동일하게 사이즈를 구할 수 있다. 출력은 $\frac{N-2}{2}+1=\frac{N}{2}$가 된다.</li>
</ul>
<h2 id="batch-normalization">Batch Normalization</h2>
<p>배치 정규화는 모델을 단순하게 만드는 regularization 기법이다. 입력 이미지들의 평균을 0, 분산을 1로 변형해서 분포를 고르게 한 뒤 학습을 진행하는 것이다. 변형된 이미지들은 가우시안 분포를 따르게 된다.
$$
\hat{x}^{(k)}=\frac{x^{(k)}-E[x^{(k)}]}{\sqrt{Var[x^{(k)}]}}
$$</p>
<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/c681943a-8ae6-4f9c-b186-b068ff4ea595/image.png" alt=""></li>
<li>이미지가 $N$개 있을 때 차원별로 평균과 분산을 계산하여 정규화할 때 시각화한 그림이다.</li>
<li>보통 정규화 다음으로는 학습 가능한 파라미터 $\gamma, \beta$를 정해두고 최종적으로 $y_{i.j}=\gamma_j\hat{x}_{i,j}+\beta_j$를 계산한다. 이는, 출력 분포가 항상 고정되어 모델 표현력이 제한되는 것을 방지하는 수단이다.<ul>
<li>$\gamma=\sigma, \beta=\mu$가 되게 학습하면 입력 $x$가 그대로 나오는 항등 함수가 된다. 이는 BatchNorm의 유연성과 강력함을 보여주는 예시이다. 처음에 분포를 표준화하고, $\gamma, \beta$를 통해 원하는 분포로 재조정할 수 있으므로, 모델이 필요하다면 정규화하지 않은 원래 값으로도 되돌릴 수 있다는 뜻이다. 즉, BatchNorm은 모델의 표현력을 해치지 않으면서도 학습을 안정화할 수 있는 안전한 연산이다.</li>
<li>$N(\mu, \sigma^2) \rightarrow N(0,1) \rightarrow N(\beta, \gamma^2)$</li>
</ul>
</li>
<li>보통 FC layer나 Convolutional layer 다음 단계, 비선형 함수 전 단계에 적용된다.</li>
<li>장점은 다음과 같다.<ul>
<li>Deep networks 학습을 더 쉽게 한다.</li>
<li>Gradient flow를 향상시킨다.</li>
<li>학습률을 높여도 되며, 더 빠르게 수렴한다.</li>
<li>초기화 시 networks가 더 견고해진다.</li>
<li>학습 중에 정규화, 단순화가 진행된다.<h3 id="layer-normalization">Layer Normalization</h3>
Batch Normalization | Layer Normalization</li>
</ul>
</li>
<li>|-
$x:N\times D$ | $x:N\times D$
$\mu,\sigma: 1\times D$ | $\mu, \sigma: N\times1$
$\gamma, \beta: 1\times D$ | $\gamma,\beta:1\times D$
$y=\gamma(x-\mu)/\sigma+\beta$ | $y=\gamma(x-\mu)/\sigma+\beta$</li>
</ul>
<h3 id="instance-normalization">Instance Normalization</h3>
<table>
<thead>
<tr>
<th>Batch Normalization</th>
<th>Instance Normalization</th>
</tr>
</thead>
<tbody><tr>
<td>$x:N\times C\times H\times W$</td>
<td>$x:N\times C\times H\times W$</td>
</tr>
<tr>
<td>$\mu, \sigma: 1\times C\times1\times1$</td>
<td>$\mu, \sigma: N\times C\times1\times1$</td>
</tr>
<tr>
<td>$\gamma, \beta: 1\times C\times1\times1$</td>
<td>$\gamma,\beta: 1\times C\times1\times1$</td>
</tr>
<tr>
<td>$y=\gamma(x-\mu)/\sigma+\beta$</td>
<td>$y=\gamma(x-\mu)/\sigma+\beta$</td>
</tr>
</tbody></table>
<h2 id="imagenet-winners">ImageNet winners</h2>
<h3 id="alexnet-8-layers">AlexNet (8 layers)</h3>
<p>Conv, Max pool, Norm →  Conv, Max pool, Norm → Conv 3 → Conv 4 → Conv 5, Max pool → FC 1 → FC 2 → FC 3</p>
<ul>
<li>Input: $[227\times227\times3]$</li>
<li>First conv layer: $[96\times11\times11]$ 필터, stride는 4<ul>
<li>Output: $[55\times55\times96]$</li>
<li>Parameter 개수: $(11\times11\times3+1)\times96$</li>
</ul>
</li>
<li>First max pool layer: $[3\times3]$ 필터, stride는 2<ul>
<li>Output: $[27\times27\times96]$</li>
<li>Parameter 개수: $0$</li>
</ul>
</li>
<li>활성화 함수는 ReLU, dropout은 0.5 등<h3 id="zfnet-8-layers">ZFNet (8 layers)</h3>
AlexNet 일부 미세 조정한 network이다.<h3 id="vggnet-19-layers">VGGNet (19 layers)</h3>
VGGNet의 핵심 아이디어는 <strong>작은 필터를 여러 층 쌓아 깊은 네트워크를 학습하는 것</strong>이다. 오로지 $[3\times3]$ 필터를 사용하고, stride는1, padding은 1이며, $[2\times2]$ Max pool 레이어의 stride는 2이다.
$[3\times3]$ 처럼 작은 필터를 여러 개 쌓으면 receptive field가 늘어난다. 세 개의 $[3\times3]$ 필터를 사용하는 것은 $[7\times7]$ 필터를 사용하는 것과 동일한 효과를 가진다. 정확히 말하면, 파라미터 수도 절감되고 비선형성이 더 추가되어 $[7\times7]$ 필터를 사용하는 것보다 더 효율적이다.</li>
</ul>
<p>하지만 VGGNet에는 크게 두 가지 단점이 있다.</p>
<ul>
<li>특히 첫번째 feature size가 너무 크다.</li>
<li>최종 flatten size가 너무 커서 FC 레이어에서 많은 파라미터가 필요하다.<h3 id="googlenet-22-layers">GoogLeNet (22 layers)</h3>
GoogLeNet의 핵심 아이디어는 <strong>연산 효율성을 챙기면서 네트워크를 깊게 쌓는 것</strong>이다. 마지막에 FC layer는 없고 Single linear classification 과정만 있다.</li>
<li><strong>Inception Module</strong><ul>
<li>한 층 안에서 다양한 필터 크기와 max pooling을 병렬로 적용하는 것을 <strong>Network in network</strong>라고 한다. 각 필터는 입력의 서로 다른 receptive field를 바라보고, 그 결과들을 channel-wise로 concat해서 하나의 출력으로 만든다. 이와 같이 한 층에서 여러 시야를 병렬로 학습하는 것이 inception module의 핵심이다.</li>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/ad838812-a834-4e3e-ac9a-c9b6b9e37ede/image.png" alt=""></li>
<li>위 그림에서 서로 다른 필터 연산을 거치면 출력 사이즈가 다음과 같이 계산된다.<ul>
<li>입력 크기 $[28\times28\times256]$</li>
<li>$1\times1$ conv → $[28\times28\times128]$</li>
<li>$3\times3$ conv → $[28\times28\times192]$</li>
<li>$5\times5$ conv → $[28\times28\times96]$</li>
<li>$[3\times3]$ max pool → $[28\times28\times256]$</li>
<li>Output은 $[28\times28\times672]$</li>
</ul>
</li>
<li>Feature map 채널 수가 너무 많아지고, 연산량이 너무 많아서 네트워크가 점점 무거워지는 문제가 있다. 또한 pooling 레이어도 공간 크기를 줄이기 위한 연산이지만 concatenation 이후 depth가 유지되는 문제가 있다.</li>
<li>이 문제를 해결하기 위해 $[3\times3], [5\times5]$ 처럼 큰 커널에 들어가기 전에 $[1\times1]$ convolution을 먼저 적용하여 채널 수를 줄일 수 있다. 예를 들어 $[1\times1]$ conv로 256차원을 64로 줄인 뒤 $[3\times3]$ conv를 적용하면 연산량을 줄일 수 있다. 이를 <strong>Bottleneck Layer</strong>라고 한다.</li>
<li><strong>Bottleneck layer</strong>: 계산량은 줄이고, 정보 표현은 유지할 수 있다.</li>
</ul>
</li>
<li>$[1\times1]$ Convolution<ul>
<li>입력 이미지가 $[56\times56\times64]$이고 필터의 개수가 32개라면 출력 크기는 $[56\times56\times32]$이다. 이 과정은 각 픽셀 위치마다 64차원 벡터에 Fully Connected Layer를 적용하는 것과 같다.</li>
<li>공간 정보는 유지하고 채널 수를 줄이는 것은 연산량과 파라미터 수를 줄이면서도 표현력을 유지하는 것이다.</li>
<li>여러 feature map을 조합하여 의미 있는 새로운 feature를 만들 수 있다.</li>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/c07ea538-84bc-4f72-8542-c50577513813/image.png" alt=""></li>
<li>위 그림에서는 입력의 채널 수를 줄인 후 복잡한 연산을 수행하여 전체적인 계산량을 줄인다. 가장 오른쪽의 pooling layer에서도 $[1\times1]$ convolution을 붙여서 정보 손실을 줄이고 채널 수를 정돈한다.</li>
</ul>
</li>
<li>GoogLeNet에서 첫번째 단계에서 $[7\times7]$ 필터를 사용하여 feature size를 대폭 줄인다. 이후 Inception Modules 여러개를 사용하여 계산량을 줄이면서도 다양한 수준의 특징을 동시에 학습한다. 마지막 Convolutional 레이어 이후에 FC layer를 사용하지 않고 global average pooling 레이어를 사용하여 공간 정보를 유지한다. 이후 FC layer를 한 층 사용하여 전체적인 파라미터 수를 절감한다.</li>
<li>하지만 Network가 깊어질수록 기울기가 소실되는 문제가 있다. 이를 해결하기 위해 중간에 softmax를 추가한다.<h3 id="resnet-152-layers">ResNet (152 layers)</h3>
ResNet은 <strong>residual connections</strong>를 활용한 deep networks이다. 단순 convolutional neural network를 여러 층 쌓게 되면 성능이 나빠진다. 하지만 training 단계에서도 성능이 낮아지므로 과적합은 아니다. 따라서 다음과 같은 가설을 세울 수 있다.</li>
<li>모델이 깊어질수록 파라미터가 많아지고 더 강력한 표현력을 가지게 된다.</li>
<li>그렇다면, 모델이 깊어질수록 최적화가 어려운 것은 아닐까?</li>
</ul>
<p>깊은 모델을 최소한 shallow model의 성능만큼 보장할 수는 없을까? 이에 대한 답변이 바로 shallower model의 출력을 copy하는 것 즉, residual connection이다. 수식으로 표현하면 $H(x)=F(x)+x$이다. 이때 $x$를 shallower model의 출력이라고 보면 된다.
ResNet이 효율적인 이유를 요약하면 다음과 같다.</p>
<ul>
<li>최종 성능을 shallow Network의 성능만큼 보장할 수 있다.</li>
<li>$F(x)$는 입력된 feature $x$가 어떻게 바뀌는지, 얼마나 바뀌어야 하는지 설명한다. $F(x)=H(x)-x$</li>
<li>이전 기울기가 흐르게 되어 기울이 소실 문제를 해결한다.</li>
</ul>
<p>FC 레이어는 가장 마지막에 클래스를 예측하는 단계에만 있다. 이론적으로 ResNet은 다양한 크기의 입력을 처리할 수 있다.</p>
<p>Networks가 더욱 깊어지면 <strong>bottleneck 레이어</strong>를 사용하여 효율성을 높일 수 있다. 입력이 들어오면 $[1\times1]$ conv filter를 사용하여 채널 수를 줄이고, $[3\times3]$ conv filter를 거친 후 다시 $[1\times1]$ filter를 사용하여 원래 채널로 되돌리는 방식으로 사용한다.</p>
<ul>
<li>ResNet 요약 및 실험 설정<ul>
<li>성능 저하 없이 네트워크를 키울 수 있다.</li>
<li>매 conv layer를 거친 후 batch normalization을 적용한다.</li>
<li>Xavier 초기화 사용</li>
<li>SGD + Momentum (0.9)</li>
<li>Learning rate: 0.1, 학습 속도가 낮아지면 단계적으로 10으로 나누어준다.</li>
<li>배치 크기 256</li>
<li>Weight decay $10^{-5}$</li>
<li>No dropout</li>
</ul>
</li>
</ul>
<h3 id="comparing-complexity">Comparing complexity</h3>
<table>
<thead>
<tr>
<th>AlexNet</th>
<th>VGGNet</th>
<th>GoogLeNet</th>
<th>ResNet</th>
</tr>
</thead>
<tbody><tr>
<td>적은 연산</td>
<td>가장 많은 연산</td>
<td>적은 연산</td>
<td>꽤 적은 연산</td>
</tr>
<tr>
<td>낮은 정확도</td>
<td>꽤 높은 정확도</td>
<td>꽤 높은 정확도</td>
<td>높은 정확도</td>
</tr>
</tbody></table>
<h2 id="training-neural-networks">Training Neural Networks</h2>
<h3 id="activation-functions">Activation Functions</h3>
<p><strong>Sigmoid</strong> function $\sigma(x)=\frac{1}{1+e^{-x}}$은 $x$가 0에 가까울수록 기울기가 크지만 $-\infin$ 또는 $\infin$으로 갈수록 기울기가 0으로 수렴한다. 이러한 이유로, 대부분의 경우 weight가 업데이트되지 않는다.</p>
<p>$\tanh(x)$ 함수는 함수값의 범위가 $[-1,1]$로 정렬되었지만 마찬가지로 대부분의 경우 gradient가 0이 된다.</p>
<p>반면 <strong>ReLU</strong> function은 $x&gt;0$ 영역에서 기울기가 0으로 수렴하지 않아 수렴이 빠르고 연산이 효율적이지만, 반대 영역에서는 여전히 gradient가 0인 문제가 있다. 그리고 $x=0$일 때에는 기울기가 없다.</p>
<p>이런 ReLU의 문제를 해결하고자, 0보다 작을 때에는 작은 기울기를 넣어주는 방법이 <strong>LeakyReLU</strong>이다. ReLU의 장점은 모두 가져가면서, 단점은 모두 해결한 함수이다. 음수 영역에서 기울기 $\alpha$는 학습 가능한 파라미터이다.</p>
<p>이와 같이 사용되는 방법이 <strong>Exponential Linear Units(ELU)</strong>이다. ReLU의 모든 장점은 그대로 가져가지만 음수일 때에는 $\alpha(\exp(x)-1)$을 계산해야 해서 연산량이 조금 더 높다.</p>
<ul>
<li>ReLU에 Dropout 방식을 더한 <strong>Gaussian Error Linear Units(GELU)</strong> 방식도 있다.</li>
</ul>
<h2 id="weight-initialization">Weight Initialization</h2>
<p>모델을 학습할 때 가장 처음 가중치 값을 0으로 설정하면, 기울기가 항상 0이기 때문에 학습이 진행되지 않는다.</p>
<h3 id="small-random-numbers">Small random numbers</h3>
<p>$$
W=0.01\times\text{np.random.randn}(D,H)
$$
이 방식은 작은 모델에서는 효율적이지만, 네트워크가 깊어질수록 문제가 된다. 네트워크가 깊다면 뒤의 레이어로 갈수록 활성 함수에 입력되는 값이 0에 수렴하게 된다. 기울기 또한 0에 수렴하여 학습할 수 없는 상태에 도달하게 된다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/50df2dfd-bc65-48ea-9e3d-421591f4d19b/image.png" alt=""></p>
<p>$0.01$을 $0.05$로 키우더라도 local gradients는 0이기 때문에 더이상 학습할 수 없는 상태에 도달하게 된다.</p>
<h3 id="xavier-initialization">Xavier Initialization</h3>
<p>$$
\frac{\text{np.random.randn(D,H)}}{\sqrt{D}}
$$
표준정규분포 $N(0,1)$를 따르는 값을 입력 차원의 제곱근으로 나누는 방법이다. 활성화 함수를 거치면 모든 레이어에서 적절하게 값이 분포된다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/880d056d-3530-4dcd-b047-1152d1ba8258/image.png" alt=""></p>
<p>$w_i$의 분산이 $\frac{1}{D}$가 되고, 입력 값 $x_i$의 분산과 $y$의 분포는 같아진다.</p>
<ul>
<li>활성화 함수가 ReLU 함수라면 분포는 다음과 같이 변한다.<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/c760e00c-323e-4d09-82ad-911736929086/image.png" alt=""></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linear Regression]]></title>
            <link>https://velog.io/@hyeon-ii/Linear-Regression</link>
            <guid>https://velog.io/@hyeon-ii/Linear-Regression</guid>
            <pubDate>Mon, 21 Apr 2025 03:56:50 GMT</pubDate>
            <description><![CDATA[<h2 id="introduction">Introduction</h2>
<p>반응 변수 (response variable, 종속 변수) $y$는 설명 변수 (predictor variables, 독립 변수) $x_1, x_2, \cdots, x_p$의 함수로 모형화, 모델링한다. 다중 선형회귀 모델은 다음과 같이 표현된다.
$$
y_i=\beta_0+\beta_1x_{1i}+\cdots+\beta_px_{pi}+\varepsilon_i, \quad i=1,2,\cdots,n.
$$
이때, 관츨할 수 없는 오차항 $\varepsilon_i$는 $N(0,\sigma^2)$인 정규분포를 따른다고 가정한다.</p>
<ul>
<li>오차항 $\varepsilon$의 제곱의 합 $Q$는 다음과 같이 표현할 수 있다.
$$
Q=\sum_{i=1}^N\varepsilon_i^2=\sum_{i=1}^{N}(y_i-(\beta_0+\beta_1x_{1i}+\cdots+\beta_px_{pi}))^2
$$</li>
<li>독립 변수와 종속 변수의 관계를 잘 설명하기 위해서는 $Q$ 값을 최소화해야 한다. 관측값과 모델이 예측한 값의 차이(잔차) 제곱합을 가장 작게 만드는 파라미터를 선택하여, 그 파라미터로 모형을 추정하는 방법을 <strong>최소제곱추정(Least Square Estimation)</strong>이라고 한다. $p+1$개의 정규 방정식을 풀어야 한다.
$$
\frac{\partial Q}{\partial\beta_0}=-\sum_{i=1}^n2\varepsilon_i=0
$$
$$
\frac{\partial Q}{\partial\beta_j}=-\sum_{i=1}^n2x_{ji}\varepsilon_i=0, \quad\text{for }j=1,2,\dots,p.
$$<h3 id="matrix-notation-of-multiple-linear-regression">Matrix Notation of Multiple Linear Regression</h3>
데이터 포인트(관측치)가 아래와 같다고 할 때, 행렬로 표기할 수 있다.
$$
y_1=\beta_0+\beta_1x_{11}+\cdots+\beta_px_{p1}+\varepsilon_1 \
y_2=\beta_0+\beta_1x_{12}+\cdots+\beta_px_{p2}+\varepsilon_2 \
y_n=\beta_0+\beta_1x_{1n}+\cdots+\beta_px_{pn}+\varepsilon_n
$$</li>
</ul>
<p>$$
y=\begin{bmatrix} 
   y_1 \ y_2 \ y_3 \ \vdots \ y_n
   \end{bmatrix},
\mathbf{X}=\begin{bmatrix}
   1 &amp; x_{11} &amp; x_{21} &amp; \cdots &amp; x_{p1} \
   1 &amp; x_{12} &amp; x_{22} &amp; \cdots &amp; x_{p2} \
   1 &amp; x_{13} &amp; x_{23} &amp; \cdots &amp; x_{p3} \
   \vdots &amp; &amp; &amp; \ddots &amp; \
   1 &amp; x_{1n} &amp; x_{2n} &amp; \cdots &amp; x_{pn}
   \end{bmatrix},
\beta=\begin{bmatrix} 
   \beta_0 \ \beta_1 \ \beta_2 \ \vdots \ \beta_p
   \end{bmatrix},
\varepsilon=\begin{bmatrix} 
   \varepsilon_1 \ \varepsilon_2 \ \varepsilon_3 \ \vdots \ \varepsilon_n
   \end{bmatrix}
$$
$\varepsilon$이 정규분포 $N(0,\sigma^2I_n)$을 따를 때 다음과 같이 표현할 수 있다.
$$
y=\mathbf{X}\beta+\epsilon
$$</p>
<ul>
<li>$\beta$의 최소제곱 추정값이 $\hat\beta$일 때 $\hat{y}=\mathbf{X}\hat\beta$이다.</li>
<li>행렬 표기에 따라 오차항의 제곱합은 $Q=\sum(y_i-\mathbf{x}<em>i^T\beta)^2$으로 나타낼 수 있으며 $\mathbf{x}_i^T=(1,x</em>{1i},x_{2i},\dots,x_{pi})$이다.<ul>
<li>$Q=(y-\mathbf{X}\beta)^T(y-\mathbf{X}\beta)=y^Ty-2\beta^T\mathbf{X}^Ty+\beta^T\mathbf{X}^T\mathbf{X}\beta$</li>
<li>$Q$를 미분하면 $\beta$의 최소제곱 추정치가 유도된다.
$$
\hat\beta=(\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^Ty
$$<h3 id="the-statistical-properties-of-lse">The statistical properties of LSE</h3>
앞서 유도된 $\beta$의 최소제곱추정치에서 $y$에 $\mathbf{X}\beta+\epsilon$을 대입하면 아래 식이 유도된다.
$$
\hat\beta=\beta+(\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^T\epsilon
$$
이때 $\epsilon$은 정규분포를 따르므로 다음이 성립한다.</li>
</ul>
</li>
<li>$E[\hat\beta]=\beta+E[(\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^T\epsilon]=\beta$</li>
<li>$Var(\hat\beta)=(\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^TVar(\epsilon)((\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^T)^T=\sigma^2(\mathbf{X}^T\mathbf{X})^{-1}$<ul>
<li>$\hat\beta$의 분산은 모델의 독립 변수 $\mathbf{X}$에 의해 결정되며, $y$와는 무관하다.</li>
</ul>
</li>
<li>$\hat\beta\sim N(\beta, \sigma^2(\mathbf{X}^T\mathbf{X})^{-1})$<h3 id="deriving-parameters-for-simple-linear-regression">Deriving parameters for Simple Linear Regression</h3>
$y_i=\beta_0+\beta_1x_i+\varepsilon_i$인 단순한 선형회귀 문제에서 다음을 가정하고 $\hat\beta_0, \hat\beta_1$을 유도한다.
$$
\hat\beta=\begin{pmatrix}<pre><code>    \hat\beta_0 \\
    \hat\beta_1 
    \end{pmatrix},</code></pre>\mathbf{X}^T=\begin{pmatrix}<pre><code>       1 &amp; 1 &amp; \cdots &amp; 1 \\
       x_1 &amp; x_2 &amp; \cdots &amp; x_n,
       \end{pmatrix},</code></pre>y=\begin{pmatrix}
y_1 &amp; y_2 &amp; \cdots &amp; y_n
\end{pmatrix}
$$</li>
<li>$\mathbf{X}^Ty=\begin{pmatrix} \sum y_i \ \sum x_iy_i \end{pmatrix}$</li>
<li>$\hat\beta_1=\frac{\sum(x_i-\bar{x})(y_i-\bar{y})}{\sum(x_i-\bar{x})^2}$, 즉 $x, y$의 공분산을 $x$의 분산으로 나눈 것</li>
<li>$\hat\beta_0=\bar{y}-\hat\beta_1\bar{x}$<h3 id="variance-of-the-residual">Variance of the Residual</h3>
$\hat{y}=\mathbf{X}(\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^Ty=\mathbf{H}Y$로 표현해보자.</li>
</ul>
<p>이때, $\mathbf{H}$는 <strong>hat matrix</strong>이다.
잔차 행렬 $\mathbf{e}=y-\hat{y}$로 표현했을 때 $e=(\mathbf{I}-\mathbf{H})y$이다. $\mathbf{H}$와 $1-\mathbf{H}$는 대칭이며 $\mathbf{H}^2=\mathbf{H}$인 <strong>idempotent matrix</strong>이다.</p>
<p>이를 활용하여 잔차 행렬의 분산을 구할 수 있다.
$$
Var(\mathbf{e})=Var((\mathbf{I}-\mathbf{H})-y)=\sigma^2(\mathbf{I}-\mathbf{H})
$$</p>
<p>또한 잔차제곱합의 기댓값 $E(\mathbf{e}^T\mathbf{e})$는 다음과 같이 계산된다.
$$
\hat\sigma^2=\frac{\mathbf{e}^T\mathbf{e}}{n-2}=\text{MSE}
$$</p>
<ul>
<li>단순선형회귀 모델에서는 기울기 하나 ($p=1$), 절편 하나까지 포함하여 모수가 2개이므로 자유도는 $n-2$이다.</li>
<li>idempotent 성질 덕분에 식이 단순해지고 자유도 $n-2$가 자연스럽게 도출된다.</li>
</ul>
<h2 id="fitted-values-and-residuals">Fitted Values and Residuals</h2>
<p>$$
\hat\mathbf{Y}=\begin{bmatrix}
               \hat{Y}_1 \ \hat{Y}_2 \ \vdots \ \hat{Y}_n
               \end{bmatrix}, \quad
\mathbf{e}=\begin{bmatrix}
           Y_1-\hat{Y}_1 \ Y_2-\hat{Y}_2 \ \vdots \ Y_n-\hat{Y}_n
           \end{bmatrix}
          =\begin{bmatrix}
           e_1 \ e_2 \ \vdots \ e_n
           \end{bmatrix}
$$</p>
<p>선형회귀 모델은 다음과 같이 표현된다.
$$
\hat\mathbf{Y}=\mathbf{X}\hat\beta=\mathbf{HY}, \quad \mathbf{e}=(\mathbf{I-H})\mathbf{Y}
$$
$$
Var(\mathbf{e})=\sigma^2\cdot(\mathbf{I-H}), \quad \hat{Var(\mathbf{e})}=\text{MSE}\cdot(\mathbf{I-H})
$$</p>
<h3 id="analysis-of-variance-results">Analysis of Variance Results</h3>
<ol>
<li><strong>Sum of Squares Total</strong>: 관측값에서 관측값의 평균을 뺀 것<ul>
<li>$\sum(y_i-\bar{y})^2$</li>
</ul>
</li>
<li><strong>Sum of Squares Error</strong>: 잔차 제곱합<ul>
<li>$\sum(y_i-\hat{y}_i)^2$</li>
</ul>
</li>
<li><strong>Sum of Squares due to Regression</strong>: 예측값에서 관측값의 평균을 뺀 것<ul>
<li>$\sum(\hat{y}_i-\bar{y})^2$</li>
</ul>
</li>
</ol>
<ul>
<li><strong>Analysis of Variance(ANOVA) Table</strong><table>
<thead>
<tr>
<th>- Source</th>
<th>SS</th>
<th>Degree of Freedom</th>
<th>Mean Square</th>
</tr>
</thead>
<tbody><tr>
<td>Regression</td>
<td>SSR</td>
<td>$p$</td>
<td>MSR=$\frac{SSR}{p}$</td>
</tr>
<tr>
<td>Error</td>
<td>SSE</td>
<td>$n-p-1$</td>
<td>MSE=$\frac{SSE}{n-p-1}$</td>
</tr>
<tr>
<td>Total</td>
<td>SST</td>
<td>$n-1$</td>
<td></td>
</tr>
</tbody></table>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Neural Networks]]></title>
            <link>https://velog.io/@hyeon-ii/Neural-Networks</link>
            <guid>https://velog.io/@hyeon-ii/Neural-Networks</guid>
            <pubDate>Sun, 20 Apr 2025 12:30:53 GMT</pubDate>
            <description><![CDATA[<h2 id="architectures">Architectures</h2>
<h3 id="linear-classifier의-한계">Linear Classifier의 한계</h3>
<p>XOR 문제는 단순한 linear classifier로 풀이할 수 없다. 이외에도 선형 hyperplane으로 분류할 수 없는 복잡한 문제가 있다.</p>
<ul>
<li><code>1 if 1 &lt;= L2 norm &lt;= 2 else 0</code></li>
<li><code>1 if odd else 0</code></li>
</ul>
<h3 id="neural-networks의-구조">Neural Networks의 구조</h3>
<p>Neural Networks는 선형 레이어가 여러 층으로 쌓인 구조이다. <strong>3-layer Nerual Net</strong> 또는 <strong>2-hidden-layer Nerual Net</strong>이라고 표현한다.</p>
<p>이때 모든 레이어는 모두 연결되어 있는 <strong>Fully-connected</strong> 관계이다.</p>
<p>선형 레이어를 여러 층 쌓은 것을 <strong>Deep Networks</strong>라고 한다. Deep Networks 분류기의 복잡도는 단순한 선형 분류기보다 훨씬 높지만, 그만큼 복잡한 문제를 풀기 위해 흔히 사용된다. 여러 층으로 쌓은 레이어를 사용하는 이유는 크게 두 가지가 있다.</p>
<ul>
<li>입력 Feature의 분포를 완전히 바꾸어서 분류할 수 없는 값을 <strong>분류가 가능하게</strong> 변형한다. 즉, 입력 데이터의 분포를 더 유의미한 공간으로 변환한다.</li>
<li>비선형적이고 더 정교한 decision boundary를 만들 수 있다. 즉, 더 다양한 입력 패턴을 인식할 수 있고 고차원 문제에서 잘 작동할 수 있다.</li>
</ul>
<h2 id="feedforward">Feedforward</h2>
<pre><code class="language-python">class Neuron:
    def neuron_tick(inputs):
        # 입력과 가중치는 1차원 np 배열이고 bias는 숫자이다
        cell_body_sum = np.sum(inputs * self.weights) + self.bias
        # Sigmoid activation function
        firing_rate = 1.0 / (1.0 + math.exp(-cell_body_sum))

        return firing_rate</code></pre>
<h3 id="3-layer-neural-network에서-feedforward">3-layer Neural Network에서 Feedforward</h3>
<pre><code class="language-python"># 활성화 함수 f 정의
f = lambda x : 1.0(1.0 + np.exp(-x))

# 임의의 입력값 x
x = np.random.randn(3, 1)

h1 = f(np.dot(W1, x) + b1)   # First layer
h2 = f(np.dot(W2, h1) + b2)  # Second layer

out = f(np.dot(W3, h2) + b3) # Third layer</code></pre>
<h3 id="activation">Activation</h3>
<p>코드에서 <code>f</code> 함수로 확인할 수 있듯이 선형 연산 이후에는 비선형 연산이 진행된다. 비선형 연산이 없다면, <code>W1, W2, W3</code>을 곱한 하나의 다른 선형 연산이 될 뿐이다. 이러한 이유로 비선형, 활성화 함수가 있어야 한다. 흔히 사용하는 활성화 함수로는 다음과 같은 함수가 있다.</p>
<ul>
<li>Sigmoid: $\sigma(x)=1/(1+e^{-x})$</li>
<li>Tanh: $\tanh(x)$</li>
<li>ReLU: $\max(0,x)$</li>
<li>LeakyReLU: $\max(0.1x, x)$</li>
<li>ELU: $\begin{cases}x &amp; \text{if }x&gt;0 \
\alpha(\exp(x)-1) &amp; \text{if }x\le0\end{cases}$</li>
</ul>
<h3 id="num-of-layers">Num of Layers</h3>
<p>레이어의 개수가 늘어날수록 복잡도는 더 늘어나게 된다. 그만큼 과적합의 가능성도 높아진다. 하지만 과적합을 막기 위해 모델의 사이즈를 줄이는 것은 좋은 방법이 아니다. 차라리, 모델의 사이즈를 키우고 더 강력한 정규화 기법을 적용하면 classifier의 일반화 성능을 더 높일 수 있다.</p>
<h2 id="gradients">Gradients</h2>
<p>손실 함수 $L(W)$는 다음과 같다.
$$
L(W)=\frac{1}{N}\sum_{i=1}^{N}L_i(x_i,y_i,W)+\lambda R(W)
$$
손실 함수의 기울기 $\nabla_WL(W)$를 직접 구하는 것은 매우 복잡하다. 모델이 복잡해질수록 기울기 계산이 어렵다.</p>
<h3 id="backpropagation">Backpropagation</h3>
<p>Backpropagation은 <strong>chain rule</strong>을 이용해, 출력층의 기울기를 입력층까지 효율적으로 전달함으로써 이 문제를 해결하기 위해 등장했다.</p>
<p>Backpropagation은 출력층에서 계산된 손실의 기울기를 각 노드에서의 local gradient와 upstream gradient의 곱으로 전달하여, 최종적으로 모든 가중치의 기울기를 계산하는 과정이다.</p>
<p>각 노드는 자시에게 들어오는 <strong>upstrean gradient</strong>와 자신의 <strong>local gradient</strong>를 곱해 <strong>downstrean</strong> 노드로 전달하며, 이 연쇄 법칙을 따라 기울기가 역방향으로 흘러간다.</p>
<h3 id="patterns-in-gradient-flow">Patterns in Gradient Flow</h3>
<ol>
<li><strong>Add gate</strong>: gradient distributor<ul>
<li><code>f = x+y</code></li>
<li>$\frac{df}{dx}=\frac{df}{dy}=1$</li>
</ul>
</li>
<li><strong>Mul gate</strong>: swap multiplier<ul>
<li><code>f = x*y</code></li>
<li>$\frac{df}{dx}=y, \frac{df}{dy}=x$</li>
</ul>
</li>
<li><strong>Copy gate</strong>: gradient adder<ul>
<li>계산된 기울기 값 두 개가 더해져서 전달된다.</li>
</ul>
</li>
<li><strong>Max gate</strong>: gradient router<ul>
<li><code>f = max(x, y)</code></li>
<li><code>max</code>는 기울기가 전달되고, <code>max</code>가 아닌 값은 기울기가 0이다.</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Optimization]]></title>
            <link>https://velog.io/@hyeon-ii/Optimization</link>
            <guid>https://velog.io/@hyeon-ii/Optimization</guid>
            <pubDate>Thu, 17 Apr 2025 11:16:25 GMT</pubDate>
            <description><![CDATA[<p>Linear Classifier의 경우 파라미터에 따른 손실 함수 $L(W)$는 다음과 같이 정의된다.
$$
L(W)=\frac{1}{N}\sum{L_i}+\lambda R(W)
$$</p>
<p>$L$이 정의되었을 때 $L$을 최소화하는 최적의 파라미터 $W$는 어떻게 구할 수 있을까.</p>
<h2 id="gradient">Gradient</h2>
<p>직접 $L$을 미분하여 기울기를 계산하는 과정은 연산이 매우 오래 걸리는 문제가 있다. 반면, analytic gradient를 계산하면 정확하고 빠르게 진행할 수 있다.</p>
<h3 id="gradient-descent">Gradient Descent</h3>
<pre><code class="language-python">while True:
    weights_grad = evaluate_gradient(loss_fn, data, weights)
    weights += - step_size * weights_grad</code></pre>
<p>현재 $L$ 값을 weight에 대하여 미분하고 계산된 기울기 반대 방향, 즉 손실 값이 작아지는 방향으로 weight가 업데이트 되는 과정이다.
하나의 gradient를 계산하기 위해 모든 데이터를 읽어야 하는 단점이 있다.</p>
<h3 id="mini-batch-gradient-descent">Mini-batch Gradient Descent</h3>
<p>앞선 단점을 해결하기 위해 학습 데이터의 일부분을 사용하여 weight를 업데이트 하는 방법이다.</p>
<pre><code class="language-python">while True:
    data_batch = sample_training_data(data, 256)
    weights_grad = evaluate_Gradient(loss_fn, data_batch, weights)
    weights += - step_size * weights_Grad</code></pre>
<p>위의 예시에서 하나의 배치에 포함된 데이터의 개수는 256개이다. Mini-batch의 데이터 $D_B$는 전체 데이터 $D$에서 임의로 샘플링한 집합이다. $D_B$의 분포는 $D$의 분포와 동일하다고 가정하며, 배치의 크기는 클수록 유리하다.</p>
<h2 id="stochastic-gradient-descent의-문제점">Stochastic Gradient Descent의 문제점</h2>
<p>데이터의 개수 $N$이 커질수록 전체 데이터셋에 대한 평균 손실을 계산량 또한 많아진다. SGD는 이 문제를 해결하기 위해 전체 데이터셋을 사용하는 대신 일부 샘플만 사용해서 gradient를 계산하는 방식이다. (Mini-batch Gradient Descent 혼용)
하지만 SGD 방식에는 크게 세 가지 문제가 있다.</p>
<ol>
<li>Loss의 변화율이  방향(차원)마다 다를 때 (<strong>Poor Conditioning</strong>)</li>
<li>Local minima 혹은 saddle point에 빠졌을 때</li>
<li>Minibatch가 균일하지 않을 때</li>
</ol>
<h3 id="loss의-변화율이-방향마다-다를-때">Loss의 변화율이 방향마다 다를 때</h3>
<p>손실 함수가 한 방향으로는 빠르게 변하고, 다른 방향으로는 완만하게 변하는 경우가 발생할 수 있다.</p>
<ul>
<li>이러한 경우 가파른 축에서는 gradient가 커서 weight가 심하게 흔들리는 jitter 현상이 발생한다.</li>
<li>완만한 축에서는 gradient가 작아서 업데이트가 매우 느리다.</li>
</ul>
<h3 id="local-minima--saddle-point에-빠졌을-때">Local minima | Saddle point에 빠졌을 때</h3>
<p>Saddle point(안장점): 어느 점에서 보면 극댓값이고 다른 곳에서 보면 극솟값인 지점으로, 극값을 가지지 않는 점이다.</p>
<p>Local minima 혹은 Saddle point 지점에서 gradient가 0이 되기 때문에 SGD가 멈추거나 느려질 수 있다. 다시 말해, <strong>Zero gradient는 Gradient descent의 stuck을 유발한다.</strong> 특히 고차원 공간에서 saddle point가 흔하게 나타난다.</p>
<h3 id="minibatch-noise-문제">Minibatch noise 문제</h3>
<p>SGD는 매 스텝마다 미니배치의 gradient를 계산한다. 따라서 gradient에 noise가 있을 수 있다.
이로 인해 weight 업데이트 경로가 불안정하고 진동하거나 최적점 근처에서 정확한 수렴이 어려울 수 있다.</p>
<h2 id="momentum-기법">Momentum 기법</h2>
<p>Momentum 기법은 기존 SGD의 문제점을 완화하기 위한 방법이다. Momentum은 관성을 이용해 앞서 본 세 가지 문제를 완화한다. 기본 SGD에서 weight가 업데이트될 때 느리고 흔들림이 많은 반면, momentum은 이에 비해 매끄럽고 빠르게 최적점에 수렴한다.</p>
<h3 id="sgd--momentum">SGD + Momentum</h3>
<p>과거 gradients의 누적 평균을 사용하여 부드럽게 업데이트한다.</p>
<pre><code class="language-python"># 기본 SGD
while True:
    dx = compute_gradient(x)
    x -= learning_rate * dx

# SGD + Momentum
vx = 0
while True:
    dx = compute_gradient(x)
    vs = rho * vs + dx
    x -= learning_rate * vx</code></pre>
<ul>
<li>Velocity <code>vx</code>는 gradients의 평균을 의미한다.</li>
<li>이전 값을 얼마나 반영할지 결정하는 rho는 관성 계수로, 보통 0.9~0.99 사이의 값을 사용한다.</li>
</ul>
<h3 id="nesterov-momentum">Nesterov Momentum</h3>
<p>Momentum 기법은 현재 위치의 gradient를 이용하지만, Nesterov Momentum은 예측된 미래 위치에서의 gradient를 사용한다.
$$
\begin{cases}
\nabla f(x_t) &amp; \text{Momentum}\
\nabla f(x_t+\rho v_t &amp; \text{Nesterov}
\end{cases}
$$</p>
<ul>
<li>$v_{t+1}=\rho v_t-\alpha\nabla f(x_t+\rho v_t)$</li>
<li>$x_{t+1}=x_T+v_{t+1}$</li>
</ul>
<p>먼저 다음 step에 가본 후 gradient를 측정하기 때문에 방향이 더 정확하고, 빠르게 수렴할 수 있다.</p>
<h2 id="adagrad">AdaGrad</h2>
<p>AdaGrad 기법은 각 weight마다 학습률을 자동으로 조절하는 기법이다. 많이 변화하는 파라미터는 학습률을 줄이고, 덜 변화하는 파라미터는 학습률을 유지한다. Gradient의 크기는 다음과 같이 계산된다.
$$
G_t=G_{t-1}+(\nabla_\theta J(\theta_t))^2
$$</p>
<ul>
<li>Weight는 기존 SGD 방법에, gradient 각 원소별 scaling 연산을 거쳐 업데이트 된다.<ul>
<li>$\theta_{t+1}=\theta_t-\frac{\eta}{\sqrt{G_t+\epsilon}}$</li>
<li>이 과정을 거쳐 크기가 큰 gradient를 줄일 수 있다.</li>
</ul>
</li>
</ul>
<p>그동안의 gradient 크기에 따라 업데이트 크기를 조절함으로써, 자주 변화하는 방향은 작게, 덜 변화하는 방향은 크게 업데이트하여 방향마다 다른 속도로 수렴하게 된다.</p>
<p>하지만 $G_t$는 gradient의 크기를 누적한 값이기 때문에 매 반복마다 증가한다. 이로 인해 learning rate가 대폭 감소하게 된다. 학습률이 점점 0에 가까워지면 학습이 일찍 멈추는 현상이 발생할 수 있다.</p>
<h3 id="rmsprop-leaky-adagrad">RMSProp: Leaky AdaGrad</h3>
<p>AdaGrad 방식의 문제점을 해결하기 위해 gradient의 누적합을 완전히 유지하지 않고, 적당히 잊어버리는 방식으로 조절하는 것이 Leaky AdaGrad 방식이다. 파라미터 $\theta$의 업데이트 방식은 동일하지만 $G$의 업데이트 방식은 다음과 같다.
$$
G=\gamma G+(1-\gamma)(\nabla_\theta J(\theta_t))^2
$$</p>
<p>오래된 gradient의 영향력을 $\gamma$로 조절하여 $G$가 너무 커지지 않게 하는 방식이다. 이를 통해 학습률이 급격이 줄어는 현상을 방지할 수 있다.</p>
<h3 id="adam">Adam</h3>
<p>Adam (Adaptive Moment Estimation)은 Momentum 기법과 Adaptive Gradient 기법의 결합이다. 최근 gradients의 평균인 momentum과 최근 gradients의 제곱의 평균을 조합해서 각 파라미터마다 다르게 조절된 학습률을 적용한다.</p>
<h3 id="adamw">AdamW</h3>
<p>Adam은 정규화 항까지 포함해서 gradient를 처리한다. 이로 인해 gradient scale에 의해 정규화 효과가 왜곡되고, weight decay가 제대로 작동하지 않는다. 이 문제를 해결하기 위해 등장한 것이 AdamW이다.</p>
<ul>
<li>Weight decay 항은 gradient에 포함하지 않고, 매 step마다 직접 파라미터에 따로 적용한다.</li>
</ul>
<h2 id="learning-rate-schedules">Learning Rate Schedules</h2>
<p>Learning rate는 하이퍼파라미터로, 최적점에 도달하기 위해 적절한 learning rate를 찾아야 한다. 아래 그래프처럼 learning rate에 따라 loss의 변화는 매우 다양해진다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/b4265950-2688-478f-a20f-263f0ebbd2b6/image.png" alt="">
참고로, 위 그래프에서 low learning rate는 최솟값에 도달하는 것처럼 보이지만 local minimum에 빠질 수 있다.</p>
<p>적절한 learning rate를 찾기 위해 다양한 learning rate scheduling 전략이 있다.</p>
<ol>
<li>학습 도중 학습률을 점차 감소시키는 방식 (Step, Cosine, Linear, Inverse square root)</li>
<li>초반에 학습률을 천천히 키워주는 방식</li>
</ol>
<h3 id="step-decay">Step Decay</h3>
<p>정해진 시점에 학습률을 급격히 줄인다.
예) 30, 60, 90 epoch마다 LR을 0.1배로 감소시킨다.</p>
<h3 id="cosine-decay">Cosine Decay</h3>
<p>학습률을 코사인 형태로 부드럽게 줄여나간다.
$$
\alpha_t=\frac{1}{2}\alpha_0\Big(1+\cos(\frac{t\pi}{T})\Big)
$$</p>
<ul>
<li>$\alpha_0$: 초기 LR</li>
<li>$\alpha_t$ $t$ 시점에서 LR</li>
<li>$T$: 전체 반복 횟수 (epoch)</li>
</ul>
<h3 id="linear-decay">Linear Decay</h3>
<p>학습률을 직선적으로 감소시킨다.
$$
\alpha_t=\alpha_0(1-\frac{t}{T})
$$</p>
<h3 id="inverse-square-root-decay">Inverse Square Root Decay</h3>
<p>Epoch 수의 제곱근에 반비례하여 학습률을 줄인다.
$$
\alpha_t=\frac{\alpha_0}{\sqrt{t}}
$$
이 경우 초기에는 빠르게 감소하다가 점점 느리게 감소한다. (굴 생존곡선 형태)</p>
<h3 id="linear-warmup">Linear Warmup</h3>
<p>학습 초기에 너무 큰 학습률을 사용하면 loss가 폭발할 수 있다. 이를 막기 위해 초반 학습에는 학습률을 천천히 키워주는 전략이 필요하다. 보통 초기 5000 반복 동안 학습률을 0에서 선형적으로 증가시키고, 이후 decay 스케줄에 따라 감소시킨다.</p>
<ul>
<li>Batch size를 $N$만큼 늘리면 초기 학습률도 $N$배, $\sqrt{N}$배 늘리는 것이 일반적이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Normal Distribution]]></title>
            <link>https://velog.io/@hyeon-ii/Normal-Distribution</link>
            <guid>https://velog.io/@hyeon-ii/Normal-Distribution</guid>
            <pubDate>Mon, 14 Apr 2025 10:40:23 GMT</pubDate>
            <description><![CDATA[<h2 id="normal-distribution">Normal Distribution</h2>
<p>정규분포는 이항분포의 극한분포로, 중심극한정리를 유도하면서 발견되었다.
<strong>중심극한정리</strong>: $n$개의 서로 독립인 관측오차는 $n$이 크면 클수록 오차의 평균은 0이고 어떤 표준편차를 갖는 정규분포를 따른다.</p>
<ul>
<li>정규분포가 다양한 분야에서 폭넓게 사용되는 이유<ol>
<li>모집단으로부터 추출된 표본이 정규분포를 따를 때 표본의 수학적 성질과 표본으로 계산되는 함수들이 간결하고 편리하다.</li>
<li>다양한 물리적 현상을 관찰하는 실험으로부터 얻어지는 데이터가 실제로 정규분포를 따르는 경우가 많다.</li>
<li>중심극한정리에 의해 직접 정규분포를 따르거나, 간단한 변환을 통해 쉽게 정규분포를 따르는 경우가 많다. 이러한 이유로 수많은 통계적 추론의 기반이 된다.<h3 id="normal-distribution의-기본적-성질">Normal Distribution의 기본적 성질</h3>
확률변수 $X$가 다음의 확률밀도함수를 가질 때, <strong>평균이 $\mu$, 분산이 $\sigma^2$인 정규분포를 따른다</strong>고 한다. $\Big(X\sim N(\mu,\sigma^2)\Big)$ 정규분포의 모수는 기댓값, 분산과 동일하다.
$$
f(x|\mu,\sigma^2)=\frac{1}{\sqrt{2\pi}\cdot\sigma}\exp\Big(-\frac{(x-\mu)^2}{2\sigma^2}\Big), \quad \text{if }-\infin&lt;x&lt;\infin
$$</li>
</ol>
</li>
<li>정규분포의 PDF는 중심이 $\mu$이고 좌우대칭인 종 모양의 형태를 가진다.<ul>
<li>평균과 중앙값이 동일하다.</li>
</ul>
</li>
<li>$\sigma^2$는 분포의 넓고 좁은 정도(산포)를 결정하는 모수로, 분산이 크면 위아래가 짧고 좌우로 넓게 퍼진 형태이다. 분산이 작으면 위아래가 높고 좌우로 좁은 뾰족한 형태이다.</li>
<li>정규분포의 PDF를 존재구간$(-\infin&lt;x&lt;\infin)$에 대해 적분하면 그 넓이는 1이다.</li>
<li>정규분포의 CDF는 닫힌 형태로 얻어지지 않는다. 따라서, 정규분포를 이용한 확률계산을 할 때는 표준정규분포로 변환하여 표준화시킨 후에 확률분포표를 이용해서 구해야 한다.</li>
<li>확률변수 $Z=(X-\mu)/\sigma$라고 한다면 $E[Z]=0, Var[Z]=1$이 성립한다. 이 $Z$를 표준정규분포라고 하며 다음과 같이 나타낼 수 있다.
$$
Z\sim N(0,1)
$$
$$
\begin{cases}\text{PDF} &amp; \phi(z)=f(x|0,1)=\frac{1}{\sqrt{2\pi}}\exp(-\frac{z^2}{2})\<pre><code>         \text{CDF} &amp; \Phi(z)=F(z)=\int_{-\infin}^zf(t)dt\end{cases}</code></pre>$$</li>
<li>정규분포의 적률생성함수(MGF)는 다음과 같다.
$$
M_X(t)=\exp(\mu t+\frac{\sigma^2t^2}{2})
$$</li>
<li>정규분포의 누적분포함수는 다음과 같다.
$$
P(a\le X\le b)=P(\frac{a-\mu}{\sigma}\le Z \le \frac{b-\mu}{\sigma})=F(b)-F(a)
$$</li>
</ul>
<h2 id="정규확률변수의-선형결합">정규확률변수의 선형결합</h2>
<ul>
<li>만약 $X\sim N(\mu, \sigma^2)$이고 $a$와 $b$가 연속적이면 $Y=aX+b\sim N(a\mu+b, a^2\sigma^2)$<ul>
<li>$X$가 정규분포를 따른다면 선형함수 $Y$ 역시 정규분포를 따른다.</li>
</ul>
</li>
<li>만약 $X_1\sim N(\mu_1,\sigma_1^2)$과 $X_2\sim N(\mu_2,\sigma_2^2)$의 확률변수들이 서로 독립이면 $Y=X_1+X_2\sim N(\mu_1+\mu_2,\sigma_1^2+\sigma_2^2)$</li>
<li>만약 $X_i\sim N(\mu,\sigma^2), 1\le i\le n$의 확률변수들이 서로 독립이면 이들의 표본 평균 $\bar{X}=\sum X_i/n$은 $\bar{X}\sim N(\mu, \frac{\sigma^2}{n})$와 같은 분포를 따른다.
$n$이 무한대에 가까워질수록 분산은 0에 수렴하여 모평균에 수렴한다. 다시 말해 실제 값과 거의 차이가 없어진다.<ul>
<li>정규분포를 따르는 확률변수들의 합은 역시 정규분포를 따른다.<h2 id="정규분포를-활용한-분포의-근사화">정규분포를 활용한 분포의 근사화</h2>
<h3 id="중심극한정리">중심극한정리</h3>
상호 독립이며 동일한 분포를 따르는 확률변수 $X_1, X_2, \dots,X_n$의 평균이 $\mu$, 분산이 $\sigma^2$일 때 $n$개의 표본으로부터 얻어진 평균의 분포는 평균 $\mu$, 분산 $\frac{\sigma^2}{n}$인 정규분포를 따른다.
$$
\bar{X}=\frac{1}{n}(X_1+X_2+\dots+X_n)
$$</li>
</ul>
</li>
</ul>
<p>$$
Z_n=\frac{\bar{X}-\mu}{\sigma/\sqrt{n}}\sim N(0,1) \qquad\text{as } n\rightarrow\infin
$$</p>
<ul>
<li>중심극한정리는 확률변수들의 평균에 대한 확률값을 추정하는데 편리한 방법을 제공한다.</li>
<li>한 표본의 평균은 각각의 측정치의 실제 분포를 대신해서 정규분포를 따른다고 가정한다.</li>
<li>$n$개의 표본이 추출되는 데이터의 분포가 정규분포가 아닌 다른 임의의 분포로 가정하여도 그 표본평균의 분포는 정규분포를 따른다. 즉, $n$이 충분이 크다면 표본평균의 분포는 표본이 추출된 분포에 상관 없이(iid를 따르기만 한다면) 근사적으로 정규분포를 따른다.<h3 id="이항분포의-정규근사">이항분포의 정규근사</h3>
이항분포의 모수 $n$이 매우 클 때는 이항분포의 누적분포함수를 계산하는 것이 거의 불가능하다. 하지만, 중심극한정리를 활용하면 이항분포의 정규근사를 통해 해결할 수 있다.</li>
<li>이항분포를 따르는 확률변수는 베르누이 확률변수의 합으로 표현할 수 있다. $X_1,X_2,\dots,X_n$을 평균 $\mu=p$, 분산 $\sigma^2=p(1-p)$인 베르누이 분포로부터 뽑은 확률표본이라고 할 때, 이 확률변수들의 합 $Y\sim B(np,np(1-p))$이 된다. 이를 표준화하였을 때 $n\rightarrow\infin$이 되면 $N(0,1)$로 수렴한다.
$$
Z=\frac{Y-np}{\sqrt{np(1-p)}}=\frac{\bar{X}-p}{\sqrt{p(1-p)/n}}\rightarrow N(0,1)
$$</li>
<li>이항분포 $B(n,p)$를 동일한 기댓값과 분산을 갖는 정규분포로 근사할 수 있다.
$$
X\sim B(n,p)\rightarrow N(np,np(1-p))
$$</li>
<li>이때, 정규분포를 이용해 이항분포의 확률값을 계산할 때, 이산형 확률변수 구간의 계산을 연속형으로 하면 오차가 발생한다. 따라서, 이 오차를 보정하는 식을 <strong>연속화 보정</strong>이라고 한다.
$$
P(a\le X\le b)\approx\int_{a-0.5}^{b+0.5}g(x)dx
$$<h2 id="정규분포와-연관된-분포">정규분포와 연관된 분포</h2>
<h3 id="대수정규분포-the-lognormal-distribution">대수정규분포 (The Lognormal Distribution)</h3>
확률변수 $Y=\ln(X)\rightarrow X=e^Y$가 평균이 $\mu$, 분산이 $\sigma$인 정규분포를 따른다면 확률변수 $X$는 모수 $\mu$와 $\sigma^2$를 가지는 대수정규분포를 따른다.
$$
X=e^Y\sim LN(\mu, \sigma^2)
$$</li>
<li>$F(x)=P(X\le x)=P(e^Y\le x)=P(Y\le\ln(x))=\Phi\Big(\frac{\ln(x)-\mu}{\sigma}\Big)$</li>
<li>$f(x)=\frac{d}{dx}F(x)=\frac{1}{\sigma x}\phi\Big(\frac{\ln(x)-\mu}{\sigma}\Big)=\frac{1}{\sigma x}\phi(z)$</li>
<li>이때 $\phi(z)=\frac{1}{\sqrt{2\pi}}e^{-\frac{z^2}{2}}$</li>
<li>모수의 평균과 분산은 대수정규분포의 평균, 분산과 같지 않다.</li>
<li>$E[X]=e^{\mu+\sigma^2/2}$</li>
<li>$Var[X]=e^{2\mu+\sigma^2}(e^{\sigma^2}-1)$<h3 id="카이제곱분포">카이제곱분포</h3>
자유도가 1인 표준정규 확률변수의 제곱의 분포는 $\chi^2(1)$이고 다음을 따른다.
$$
X\sim N(\mu, \sigma^2)
$$
$$
Z^2=\Big(\frac{X-\mu}{\sigma}\Big)^2\sim\chi^2(1)
$$</li>
<li>$Y=Z^2$인 카이제곱분포의 확률밀도함수: $f(y)=\frac{1}{2^{\nu/2}\Gamma(\nu/2)}y^{\nu/2-1}e^{-y/2}, \quad y\ge0$</li>
<li>자유도 $\nu$인 $\mathcal{X}^2$인 확률변수 $Y$는 다음과 같다.
$$
Y=Z_1^2+Z_2^2+\cdots+Z_\nu^2\sim\chi^2(n)
$$
이때 $Z_i$는 독립인 표준정규 확률변수이다.</li>
<li>카이제곱분포는 감마분포의 특수한 형태로서 통계적 검정 및 추론에서 매우 중요하게 사용된다.
$X\sim \chi^2(\nu)=\Gamma(\alpha=\frac{\nu}{2}, \lambda=\frac{1}{2})$</li>
<li>$E[X]=\nu$</li>
<li>$Var[X]=2\nu$</li>
<li>$M_x(t)=(\frac{1}{1-2t})^{\nu/2}\quad\text{for }t&lt;1/2$</li>
<li>확률변수 $X_1, X_2, \dots, X_k$가 서로 독립이고 자유도가 $\nu_i$인 카이제곱 분포를 따를 때, 확률변수의 합 $X_1+X_2+\dots+X_k$은 자유도가 $\nu_1+\dots+\nu_k$인 카이제곱 분포를 따른다.<h3 id="t-분포">T 분포</h3>
표준정규분포를 따르는 확률변수를 독립인 $\chi^2_\nu/\nu$의 제곱근으로 나눈 확률변수는 자유도 $\nu$를 가지는 t-분포를 따른다.
$$
T=\frac{W}{\sqrt{V/\nu}}=\frac{N(0,1)}{\sqrt{\chi^2(\nu)/\nu}}\sim t_v
$$</li>
<li>자유도 $\nu$가 증가함에 따라 t-분포는 점점 더 표준정규분포에 가깝게 되어 $\nu\rightarrow\infin$일 때 표준정규분포는 t-분포의 극한 분포가 된다.<h3 id="f-분포">F 분포</h3>
두 개의 $\chi^2$ 확률변수 $(U\sim\chi^2(\nu_1),\quad V\sim\chi^2(\nu_2))$가 서로 독립일 때 다음과 같다.
$$
F=\frac{\chi^2(\nu_1)/\nu_1}{\chi^2(\nu_2)/\nu_2}\sim F_{\nu_1,\nu_2}
$$</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linear Classification]]></title>
            <link>https://velog.io/@hyeon-ii/Linear-Classification</link>
            <guid>https://velog.io/@hyeon-ii/Linear-Classification</guid>
            <pubDate>Mon, 14 Apr 2025 06:41:22 GMT</pubDate>
            <description><![CDATA[<h2 id="image-classification">Image Classification</h2>
<p>Image classification은 visual 관련 task 중 가장 단순한 task로, 주어진 이미지가 강아지 사진인지, 고양이 사진인지 label을 예측하는 것이다. 하지만 컴퓨터는 이미지를 <strong>숫자</strong>로 다루기 때문에 challenge가 존재한다.</p>
<h3 id="semantic-gap의-문제">Semantic Gap의 문제</h3>
<p>일반적으로 이미지는 $[W,H,C]$ 크기의 3차원 tensor이며, 각 픽셀은 $[0,255]$ 사이의 정수로 표현된다. $2^8$가지의 정수와 고차원 의미 간의 간극이 존재한다.
동일한 개체에 대한 사진이더라도 각도, 조명, 배경에 따라 픽셀은 완전히 다르게 나타난다.</p>
<h3 id="data-driven-approach">Data-Driven Approach</h3>
<p>분류기를 학습할 때 다음과 같은 pipeline을 따라 진행된다.</p>
<ol>
<li>(Image, Labels) 데이터셋을 수집한다.</li>
<li>분류기를 학습하기 위해 머신러닝을 사용한다.</li>
<li>테스트 이미지를 이용하여 분류기를 평가한다.</li>
</ol>
<p>가장 흔히 사용되는 분류기로는 <strong>Nearest Neighbor Classifier, Linear Classifier</strong>가 있다.</p>
<h2 id="nearest-neighbor-classifier">Nearest Neighbor Classifier</h2>
<ul>
<li>Train &amp; Test<ul>
<li><strong>Train</strong>: 학습을 위한 이미지를 저장한다. 이외의 별도의 학습 과정은 없다.
학습의 복잡도는 $O(1)$로, 매우 효율적이다. 하지만 분류기에서 중요한 것은 test의 속도이므로 훈련 시간이 긴 것은 문제되지 않는다.</li>
<li><strong>Test</strong>: Train set에서 가장 유사한 image의 label로 예측한다.
모든 test sample과 전부 비교해야 하므로 복잡도는 $O(N)$이며 훈련 과정에 비해 매우 오래 걸리며 비효율적이다.</li>
<li>NN 방식은 <strong>훈련 데이터를 저장하고, 가장 가까운 예시를 기반으로 예측하는 분류기이다.</strong></li>
</ul>
</li>
<li>거리 측정 방식
유사도 측정 방식 L1 distance, L2 distance 두 가지를 가장 흔히 사용한다. 유사도 측정 방식은 정확도에 큰 영향을 주는 hyper-parameter이다. Hyper-parameter는 학습해야 하는 것이 아닌 찾아야 하는 알고리즘과 관련된 것을 의미한다.<ul>
<li><strong>L1(Manhattan) Distance</strong>: $d_1(I_1,I_2)=\sum_p|I_1^p-I_2^p|$
같은 위치에 있는 픽셀 값의 차이를 합하여 유사도로 사용한다. 다를수록 차이가 커지므로 $d_1$ 값이 작을수록 두 이미지 $I_1$과 $I_2$는 유사하다.</li>
<li><strong>L2(Euclidean) Distance</strong>: $d_2(I_1,I_2)=\sum_p\sqrt{\sum_p(I_1^p-I_2^2)^2}$</li>
</ul>
</li>
</ul>
<h3 id="k-nearest-neighbor-classifier">k-Nearest Neighbor Classifier</h3>
<p>k-Nearest Neighbor 알고리즘은 데이터 포인트 주변의 $k$개 이웃을 기준으로 다수결 투표를 통해 label을 예측하는 방식이다. 이때 $k$ 값의 선택에 따라 분류기의 성능과 decision boundary가 크게 달라질 수 있다.</p>
<ul>
<li>Decision Boundary의 변화: NN vs k-NN
$k=1$인 NN일 경우에는 decision boundary가 매우 불규칙하며, 훈련 데이터 하나하나에 매우 민감하게 반응하는 overffing 상태<strong>(unstable decision boundary)</strong>와 같다. 반면, $k=5$일 경우에는 보다 부드러운 경계<strong>(smooth decision boundary)</strong>가 형성되어 노이즈에도 더 안정적으로 대응할 수 있다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/d82618b4-7e02-4248-9ac7-d5027407ec02/image.png" alt=""></li>
<li>훈련 데이터에 대한 정확도
$k=1$인 NN-Classifier는 각 train sample을 분류할 때, 자기 자신을 가장 가까운 이웃으로 선택하게 된다. 따라서 training accuracy는 100%이다. 반면, test accuracy는 매우 저조하다. 이는 훈련 데이터에 대해 overfitting이 발생한다는 의미이기도 한다.
$k=5$인 경우에 training accuracy는 낮은 반면 test accuracy는 높다. <strong>최적의 $k$는 validation set을 통해 찾는 것이 중요하다.</strong><h3 id="finding-hyper-parameters">Finding Hyper-parameters</h3>
k-NN 알고리즘에서 $k$ 값이나 거리 측정 방식은 모델이 직접 학습하는 값이 아니라, 사용자가 미리 정해줘야 하는 값, 즉 <strong>Hyper-parameter</strong>이다. $k$ 값을 결정하기 위해 검증용 데이터를 활용해서 실험적으로 찾아야 한다.</li>
<li>단순히 데이터를 훈련/검증/테스트로 나누는 것도 좋지만, 데이터가 적을 경우 이렇게 나누면 검증용 데이터가 부족해질 수 있다. 이럴 때 사용하는 것이 <strong>k-Fold Cross Validation</strong>이다.<ul>
<li>가지고 있는 데이터를 5개의 동일한 크기의 조각(fold)으로 나눈다고 가정해보면, 1개는 검증용, 나머지는 학습용으로 사용한다. 이 과정을 총 5번 반복하면서, 매번 다른 fold를 검증용으로 설정한다.</li>
<li>각 반복에서 얻은 정확도를 평균 내서 하이퍼파라미터별 평가 점수로 사용한다.</li>
<li>이 과정을 거치면 최적의 $k$를 선택할 수 있게 된다.<h3 id="curse-of-dimensionality">Curse of Dimensionality</h3>
k-NN 분류기를 사용할 때, 이미지 간의 거리를 계산할 기준으로 픽셀 값 자체를 쓰지는 않는다. 같은 개체여도 픽셀 단위에서 약간씩만 달라도, 실제로는 전혀 다른 이미지이고, 이런 작은 차이가 거리 계산에서 큰 영향을 미치기 때문이다. 즉, 픽셀 거리만으로는 유의미한 유사도를 측정하기 어렵다.
1차원 데이터의 경우 필요한 포인트 수가 $5$라면, 2차원의 경우 $[5,5]\rightarrow25$, 3차원이면 $[5,5,5]\rightarrow125$ 개의 포인트가 필요하다. 이처럼 차원이 높아질수록 불필요한 정보도 포함되어 유의미한 정보를 찾는 게 더 어려워진다.
이러한 이유로, 대부분의 이미지 분류 문제에서는 feature extraction을 먼저 수행한 다음에 k-NN을 적용하거나, 아예 딥러닝 기반의 분류 모델을 사용하게 된다.</li>
</ul>
</li>
</ul>
<h2 id="linear-classifier">Linear Classifier</h2>
<p>Linear Layer는 보통 Deep Neural Networks의 가장 마지막에 MLP head, Fully Connected Layer와 같은 이름으로 존재한다.</p>
<h3 id="parametric-approach">Parametric Approach</h3>
<p>입력된 이미지 $x$의 크기가 $[32\times32\times3]$일 때, 3072개의 픽셀 값들은 $[0,1]$ 사이의 실수로 표현된다.
분류기의 parameter가 $W$로 표현된다면, 분류기는 다음과 같이 표현할 수 있다.
$$
f(x,W)=Wx+b
$$</p>
<ul>
<li>$\begin{cases} f(x,W): &amp; [10\times1] \
W: &amp; [10\times3072] \
x: &amp; [3072\times1] \
b: &amp; [10\times1]
\end{cases}$</li>
<li>학습해야 하는 parameters: $W[10\times3072], b[10\times1]$ 총 30730개<h3 id="linear-classifier의-기하학적-해석">Linear Classifier의 기하학적 해석</h3>
이미지는 단순 픽셀 배열처럼 보일 수 있지만, 컴퓨터는 이를 하나의 코차원 벡터로 이해한다. 예를 들어 $[32\times32\times3]$ 크기의 컬러 이미지는 총 3072 차원의 벡터 공간에 존재하게 된다.
이런 고차원 공간에서, Linear Classifier는 각 클래스를 hyperplane을 기준으로 나누어 분류한다. 이 평면의 방향과 위치는 학습된 가중치 $W$에 의해 결정된다.
Linear Classifier는 각 클래스마다 decision boundary를 가진다. 각 선은 클래스의 분류기이며, 이 선을 기준으로 어느 쪽에 위치하는지에 따라 해당 클래스인지 판별한다.</li>
<li>Linear Classifier는 복잡한 비선형 경계를 표현하지 못하므로, 모든 경우에 효과적이지는 않다. 하지만 빠르고 해석이 쉽다는 장점이 있다.<h3 id="loss-function">Loss Function</h3>
Loss Function은 현재 분류기가 얼마나 낮은 성능을 보이는지 숫자로 표현하는 함수이다.
세 가지 클래스, 세 가지 샘플이 있을 때 손실 함수를 계산하는 과정은 다음과 같다.</li>
<li><strong>Multiclass SVM loss</strong><ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/237e2b36-ebae-4a75-9750-9caaea02f629/image.png" alt=""></li>
<li>정답 클래스는 최댓값으로 예측해야 한다. 고양이 이미지의 경우 cat에 해당하는 점수가, 자동차 이미지의 경우 car에 해당하는 점수가 가장 커야 한다. 고양이 이미지이면 car, frog에 대한 점수는 낮을수록 좋다.</li>
<li>$L_i=\sum_{j\neq y_i}\max(0, s_j-s_{y_i}+1)$<ul>
<li>고양이 이미지: $L_\text{cat}=(5.1-3.2+1)+0=2.9$</li>
<li>자동차 이미지: $L_\text{car}=0+0=0$</li>
<li>개구리 이미지: $L_\text{frog}=(2.2+3.1+1)+(2.5+3.1+1)=12.9$</li>
</ul>
</li>
<li>$L_i=\sum_{j\neq y_i}\begin{cases} 0 &amp; \text{if }s_{y_i}\ge s_j+1 \<pre><code>                               s_j-s_{y_j}+1 &amp; \text{otherwise}
                 \end{cases}$</code></pre><ul>
<li>정답 클래스의 점수가 다른 클래스의 점수보다 1 이상 크면 손실은 0이다.</li>
<li>반대로, 정답 클래스의 점수가 다른 클래스의 점수보다 낮다면 두 점수의 차이에 1을 더한 값이 손실이 된다.</li>
<li>즉, 손실이 없기 위해서는 GT 값이 다른 클래스의 점수보다 1 이상 커야한다.</li>
</ul>
</li>
<li>손실함수 해석<ol>
<li>$j=y_i$를 포함하게 되면 $L_i$ 값은 무조건 1이 된다. 상수로 고정된 값은 무의미하므로 summation 계산 시 $j=y_i$인 경우는 제외한다.</li>
<li>자동차 이미지에서 car 예측 점수가 0.5만큼 감소했을 때 $L_i=\max(0, 1.3-4.4+1)+\max(0, 2.0-4.9+1)=0$으로 동일하다. 자동차 이미지에서 car 예측 점수가 0.5로 감소했을 때 $L_i=(1.3-0.5+1)+(2.0-0.5+1)=4.3$으로 증가한다.</li>
<li>SVM loss의 최솟값은 0, 최댓값은 $\infin$이다.<ul>
<li>$s_j\rightarrow\infin, \max\rightarrow\infin$</li>
</ul>
</li>
<li>$N$개의 샘플과 $C$개의 클래스가 있을 때 Parameter $W$가 0에 매우 가깝게 초기화 되었다면, 모든 예측값들은 0에 수렴한다. $L_i=\sum_j\max(0,1)=C-1$</li>
</ol>
</li>
</ul>
</li>
<li><strong>Softmax Classifier</strong>(Multinomial Logistic Regression)<ul>
<li>계산된 점수들은 각 클래스에 대해 probabilities를 의미한다. (모든 확률의 합은 1, 모든 확률값은 Non-negative)</li>
<li>주어진 이미지 $x_i$에 대해 클래스 $k$일 확률은
$$
P(Y=k|X=x_i)=\frac{e^{s_k}}{\sum_je^{s_j}} \quad \text{where } s=f(x_i;W)
$$</li>
<li>Log likelihood 최대화를 거쳐 정답인 클래스에 대해 확률값이 가장 커지게 학습해야 한다.
$$
L_i=-\log P(Y=y_i|X=x_i)=-\log\Big(\frac{e^{s_k}}{\sum_je^{s_j}}\Big)
$$</li>
<li>KL Divergence는 두 확률 분포 간의 차이를 수치적으로 나타내는 방법이다. 실제 정답 분포(정답 라벨의 one-hot 벡터)가 $P(x)$이고 모델이 예측한 분포(softmax 값)가 $Q(x)$일 때 다음과 같이 표현된다.
$$
D_\text{KL}(P|Q)=\sum_{x\in X}P(x)\log\Big(\frac{P(x)}{Q(x)}\Big)
$$
이 값이 작을수록 모델의 예측이 실제 분포에 가깝다는 뜻이다.
전개하면 entropy(상수)에서 cross entropy를 뺄셈하는 것과 같다. 따라서 $D_\text{KL}$을 최소화하기 위해서 CE 값을 최소화하면 된다.
$$
=-\sum_{x\in X}P(x)\log Q(x)+\sum_{x\in X}P(x)\log P(x)
$$</li>
<li>고양이 이미지에 대해 Loss 계산 과정은 다음과 같다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/7f35aae7-dc35-4dcb-8c80-37aec9eb7b38/image.png" alt="">
계산된 probabilities는 $[\text{cat, car, frog}]=[0.13,0.87,0.00]$이고 cat 클래스에 대해 loss를 계산하면 $L_i=-\log(0.13)=0.89$이다.</li>
<li>손실함수 해석<ol>
<li>Softmax loss의 최솟값은 0, 최댓값은 $\infin$이다.<ul>
<li>$P_\text{GT}\rightarrow0, -\log P_\text{GT}\rightarrow\infin$</li>
</ul>
</li>
<li>$C$개의 클래스가 있을 때 Parameter가 모두 비슷하게 초기화되어 있다면, 모든 예측값 $P=\frac{z}{cz}=\frac{1}{c}$이므로 $L_i=-\log C$이다.</li>
</ol>
</li>
</ul>
</li>
<li>동일한 linear classifier에서 <strong>SVM</strong> vs <strong>Softmax</strong>
SVM은 Softmax에서 $\exp$를 적용하기 전 logit 값을 이용해서 loss를 계산한다.<h2 id="weight-regularization">Weight Regularization</h2>
Overfitting을 막기 위해서 regularization을 해주어야 한다.
$$
L(W)=\frac{1}{N}\sum_{i=1}^NL_i(f(x_i,W),y_i)+\lambda R(W)
$$
Loss function은 <strong>Data loss</strong>와 <strong>Regularization term</strong>으로 구성된다.<h3 id="overfitting">Overfitting</h3>
Train accuracy에 지나치게 과적합되어 train accuracy는 매우 높지만, test accuracy가 낮은 현상을 말한다. Overfitting 현상은 모델을 단순하게 만들어서 해결할 수 있다.
가장 흔히 사용되는 정규화 기법으로는 L1 regularization, L2 regularization, Elastic net이 있다.</li>
<li><strong>L1 regularization</strong>
$R(W)=\sum_k\sum_l|W_{k,l}|$<ul>
<li>L1은 가중치를 희소하게 만드는 성질이 있다. 많은 가중치를 0으로 만들게 된다.</li>
</ul>
</li>
<li><strong>L2 regularization</strong>
$R(W)=\sum_k\sum_lW_{k,l}^2$<ul>
<li>모든 가중치 요소들의 제곱 합이 작을수록 정규화 손실도 작아진다. 다시 말해, L2는 가중치를 여러 항목에 고르게 분산시키는 역할을 한다. 하나의 가중치 값만 지나치게 커지는 것을 방지하고 더 안정적인 학습을 유도한다. Outlier를 완화하고 싶다면 L2 regularization이 적절하다.</li>
</ul>
</li>
<li><strong>Elastic net</strong>
$R(W)=\sum_k\sum_l\beta W_{k,l}^2+|W_{k,l}|$<h3 id="more-complex">More complex</h3>
Dropout, Betch normalization, Stochastic depth 등의 방법을 통해 정규화를 적용할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[연속형 확률분포]]></title>
            <link>https://velog.io/@hyeon-ii/continuous-probability-distribution</link>
            <guid>https://velog.io/@hyeon-ii/continuous-probability-distribution</guid>
            <pubDate>Mon, 14 Apr 2025 02:12:15 GMT</pubDate>
            <description><![CDATA[<h2 id="균일분포uniform-distribution">균일분포(Uniform Distribution)</h2>
<p>$X$에 대한 확률밀도함수(PDF)가 다음과 같이 주어진 경우, 구간 $(a,b)$에서의 균일확률변수라고 한다.
$$
f(x)=\begin{cases}\frac{1}{b-a} &amp; \text{if } a&lt;x&lt;b \
0\end{cases}
$$</p>
<ul>
<li>누적분포함수(CDF): $F(x)=\frac{x-a}{b-a}, \quad a\le x\le b$</li>
<li>$E[X]=\int_a^bx\cdot\frac{1}{b-a}dx=\frac{a+b}{2}, \quad Var[X]=\frac{(b-a)^2}{12}$</li>
<li>균일분포의 $p$번째 분위수 $x_p$는 다음과 같다.
$F(x_p)=\frac{x_p-a}{b-a}=p, \quad x_p=(1-p)a+pb$<ul>
<li>Median의 경우 $p=\frac{1}{2}$, upper quartile의 경우  $p=\frac{3}{4}$이다.<h2 id="지수분포exponential-distribution">지수분포(Exponential Distribution)</h2>
일정 시간 동안 발생하는 사건의 횟수가 포아송 분포를 따른다면, 다음 사건이 일어날 때까지 대기 시간은 지수분포를 따른다. (기하분포의 연속형 version)
$X$가 빈도를 나타내는 모수 $\lambda$를 갖는 지수확률변수라고 할 때 확률밀도함수는 다음과 같다.
$$
f(x)=\begin{cases}\lambda e^{-\lambda x} &amp; \text{if }x\ge0 \
0 &amp; \text{if } x&lt;0\end{cases}
$$</li>
</ul>
</li>
<li>누적분포함수(CDF): $F(x)=\int_0^x\lambda e^{-\lambda u}du=1-e^{-\lambda x}, \quad x\ge0$</li>
<li>$P(X&gt;s+t|X&gt;s)=\frac{e^{-\lambda(t+s)}}{e^{-\lambda s}}=e^{-\lambda t}=P(X&gt;t)$<ul>
<li>이 수식을 만족하는 성질을 <strong>무기억성</strong>이라고 한다. 이전까지 시행된 결과가 다음 시행에 영향을 주지 않는 것을 말하며, 기하분포와 유사하다.</li>
</ul>
</li>
<li>적률생성함수
$$
M_X(t)=E[e^{tx}]=\int_0^\infin e^{tx} \lambda e^{-\lambda x}dx=\frac{\lambda}{t-\lambda}
$$</li>
<li>$E[X]=\int_0^{\infin}x\lambda e^{-\lambda x}dx=\frac{1}{\lambda}$</li>
<li>$Var[X]=\frac{1}{\lambda^2}$</li>
<li>변동계수 (Coefficient of Variation): $CV(X)=\frac{\sqrt{Var(X)}}{E[X]}=1$<ul>
<li>측정 단위가 다른 자료를 비교할 때 사용한다. 표준 편차가 같더라도 측정 단위(평균 등)가 다를 수 있으므로 사용한다.</li>
</ul>
</li>
<li>P-th quantile: $F(x_p)=1-e^{-\lambda x_p}=p$, $x_p=-\frac{\ln(1-p)}{\lambda}$<h2 id="감마분포gamma-distribution">감마분포(Gamma Distribution)</h2>
사건이 발생하는 시간 사이 간격은 서로 독립적이고 모수가 $\lambda$인 지수분포를 각각 따른다고 할 때, $\alpha$번째 사건이 발생할 때까지 걸리는 시간은 감마분포를 따른다.
$X$가 모수 $\lambda&gt;0, \quad \alpha&gt;0$을 갖는 감마확률변수라고 할 때$(X\sim\Gamma(\alpha,\lambda))$, 다음을 만족한다.
$$
f(x)=\begin{cases}\frac{\lambda e^{-\lambda x}(\lambda x)^{\alpha -1}}{\Gamma(\alpha)} &amp; \text{if }x\ge0 \<pre><code>            0 &amp; \text{if }x&lt;0</code></pre>   \end{cases}
$$
$$
M_X(t)=(1-\frac{t}{\lambda})^{-\alpha}, \quad t&lt;\lambda
$$</li>
<li>감마 함수는 다음과 같이 정의한다.
$$
\Gamma(\alpha)=\int_0^{\infin}e^{-x}x^{\alpha-1}dx=(\alpha-1)!
$$
Factorial의 복소수 확장이라고 볼 수 있다.</li>
<li>$E[X]=\frac{\alpha}{\lambda}$</li>
<li>$Var[X]=\frac{\alpha}{\lambda^2}$</li>
<li>$CV(X)=\frac{\sqrt{\alpha/\lambda^2}}{\alpha/\lambda}=\frac{1}{\sqrt{\alpha}}&lt;1$<h3 id="지수-포아송분포-감마분포-간의-관계">지수, 포아송분포, 감마분포 간의 관계</h3>
처음 사건이 발생할 때까지의 대기시간은 지수분포를 따른다. 즉, 지수분포는 $\alpha=1$인 감마분포이다.
$\alpha$번째 도착까지의 대기시간은 감마분포를 따른다.
길이가 $x$인 구간에서의 도착 횟수 $Y$는 평균 $\mu=\lambda x$인 포아송분포를 따른다.<h2 id="와이블분포weibull-distribution">와이블분포(Weibull Distribution)</h2>
와이블 분포는 고장 및 대기시간을 모형화하는 데 자주 사용된다. 척도 모수 $\alpha&gt;0$와 형태 모수 $\beta&gt;0$을 가지는 와이블 확률밀도함수는 다음과 같다.
$$
f(x)=\beta\alpha^\beta x^{\beta-1}e^{-(\alpha x)^\beta}
$$</li>
<li>누적밀도함수: $F(x)=1-e^{-(\alpha x)^\beta}$</li>
<li>형태 모수 $\beta=1$인 경우, 와이블 분포는 지수분포와 동일하다.</li>
<li>$E[X]=\frac{1}{\alpha}\Gamma(1+\frac{1}{\beta})$</li>
<li>$Var[X]=\frac{1}{\alpha^2}\Big(\Gamma(1+\frac{2}\beta)-\Gamma(1+\frac{1}{\beta})^2\Big)$</li>
<li>$x_p=\frac{(-\ln(1-p))^{1/\beta}}{\alpha}$<h2 id="베타분포beta-distribution">베타분포(Beta Distribution)</h2>
확률변수값 자체가 확률인 경우에 이에 대한 확률분포를 베타분포라고 한다. 베타분포는 형상 모수(성공 횟수) $\alpha$와, 또다른 형상 모수(실패 횟수) $\beta$로 정의된다.
베타함수는 다음과 같다.
$$
Beta(\alpha,\beta)=\int_0^1x^{\alpha-1}(1-x)^{\beta-1}dx=\frac{\Gamma(\alpha+\beta)}{\Gamma(\alpha)\cdot\Gamma(\beta)}\quad a&gt;0,\beta&gt;0
$$
$0\le x\le1$ 상태 공간을 가지고 있으며, 비율을 모형화할 때 사용된다. 베타분포의 확률밀도함수는 다음과 같다.
$$
f(x)=\frac{\Gamma(\alpha+\beta)}{\Gamma(\alpha)\cdot\Gamma(\beta)}x^{\alpha-1}(1-x)^{\beta-1} \quad \text{for } 0\le x\le1
$$</li>
<li>$E[X]=\frac{\alpha}{\alpha+\beta}$</li>
<li>$Var[X]=\frac{\alpha\beta}{(\alpha+\beta)^2(\alpha+\beta+1)}$</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Longitudinal Dynamics]]></title>
            <link>https://velog.io/@hyeon-ii/Longitudinal-Dynamics</link>
            <guid>https://velog.io/@hyeon-ii/Longitudinal-Dynamics</guid>
            <pubDate>Tue, 08 Apr 2025 07:47:13 GMT</pubDate>
            <description><![CDATA[<p>교통사고를 줄이기 위해 차량의 안정성을 높이는 기술 개발이 매우 중요하다.</p>
<p>사고가 발생하기 전에 미리 위험을 감지하고 사고를 예방하거나 피해를 최소화하는 <strong>능동 안전 시스템(Active Safety Systems)</strong>이 필요하다. ABS(잠김 방지 브레이크), 차선 유지 보조 시스템, 자동 긴급 제동 시스템 등이 Active Safety Systems에 해당한다.
Active Safety Systems는 초기(1980년대) ABS, ETC, EBD와 같이 안전을 위한 시스템 위주로 개발되었으나, 2000년대부터 현재에 이르기까지 Automonous driving와 같이 운전자 편의를 위주로 개발되고 있다.</p>
<p>이러한 제어 장치는 기존에는 단순한 구조의 기계식 장치로 개발되었으나, 정밀한 제어가 어려운 문제가 있다. 따라서 센서와 컴퓨터를 활용하여 정밀한 제어가 가능한 전자 기계식으로 개발되고 있다. 전자 제어 시스템은 안정성과 연비 효율 측면에서 이점이 있다.</p>
<h2 id="vehicle-dynamics">Vehicle Dynamics</h2>
<p>차량 동역학이란, 차량이 움직이는 원리와 움직임에 영향을 주는 힘을 분석하는 분야를 의미한다. 여기에서 <strong>&#39;힘&#39;</strong>은 크게 앞뒤(직선 운동), 좌우(횡방향 운동), 회전(roll, pitch, yaw)로 나뉜다.</p>
<h3 id="automobile-control-주요-요소">Automobile Control 주요 요소</h3>
<p>자동차 제어 시스템은 크게 파워트레인 제어, 차량 제어, 바디 제어로 나눌 수 있다.</p>
<ul>
<li><strong>Powertrain Control</strong>: 차량을 움직이는 동력을 만들어내고 전달하는 시스템으로, 엔진과 변속기를 효율적으로 관리하여 연비와 성능을 최적화한다.<ul>
<li>파워트레인은 엔진에서 나온 에너지를 바퀴로 전달하는 장치이다. 동력을 도로 표면에 전달하는 엔진, 변속기, 구동축 등으로 구성된다.</li>
<li>엔진 제어: 연료 분사량 조절, 점화 시기 조절, 배기가스 재순환</li>
<li>변속기 제어: 속도와 페달 각도에 따른 변속 시점 결정 등</li>
<li>EGR(배기가스 재순환): 배기가스를 다시 엔진으로 보내 유해물질 배출량을 줄인다.</li>
</ul>
</li>
<li><strong>Vehicle Control</strong>: 차량의 주행 안정성과 승차감을 향상시키기 위한 시스템<ul>
<li>서스펜션 제어: 노면에서 전달되는 충격 완화 및 승차감 향상</li>
<li>조향 제어: 차량의 방향 조종 안정성 향상</li>
<li>크루즈 컨트롤: 원하는 차량 속도를 일정하게 유지</li>
<li>브레이크 제어(ABS): 미끄러짐 방지 및 제동 거리 단축</li>
<li>트랙션 컨트롤: 미끄러운 노면에서 타이어 접지력 유지</li>
</ul>
</li>
<li><strong>Body Control</strong>: 운전자의 편의성과 안전과 관련된 시스템<ul>
<li>자동 공기질 관리, 전자식 계기판 및 디스플레이, 보안 시스템 등 운전자 및 탑승자의 편의 기능<h3 id="feedback-control-system">Feedback Control System</h3>
피드백 제어란 목표 상태와 실제 상태 간 차이를 줄이는 방식으로 작동하는 방식으로, 네 가지 요소로 구성된다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/de830fc8-c838-4e4f-b165-8f4e198e3509/image.png" alt=""></li>
</ul>
</li>
</ul>
<p>이 네 가지 요소가 결합하여 위와 같은 피드백 제어 Loop를 형성한다. 즉, 센서로 현재 상태를 측정하면 제어기가 목표 상태와 비교하여 명령을 생성하고 액추에이터가 시스템을 제어한다.</p>
<ul>
<li><strong>Controller(제어기)</strong>: 원하는 상태로 만들기 위해 명령 신호를 생성한다.<ul>
<li>ABS 제어기, 엔진 ECU 등이 이에 해당한다.</li>
</ul>
</li>
<li><strong>Actuator</strong>: 컨트롤러 신호를 실제 동작으로 바꾸는 기계장치<ul>
<li>대표적인 액추에이터로 모터가 있으며 유압식 브레이크, 전자식 스로틀 벨브 등도 이에 해당한다.</li>
</ul>
</li>
<li><strong>Controlled System(제어 대상 시스템)</strong>: 실제 차량 또는 차량의 서스펜션, 타이어와 같은 시스템으로 액추에이터가 작동시키는 대상이다.</li>
<li><strong>Sensor</strong>: 제어된 대상이 출력한 값(상태)을 측정해서 제어기에 전달한다.<ul>
<li>속도 센서, 가속도 센서, 각도 센서 등이 있다.</li>
</ul>
</li>
</ul>
<p>시스템이 입력받는 값과 출력하는 값의 개수에 따라 시스템은 SISO system(Single-Input/Single-Output), MIMO(Multi-Input/Multi-Output)으로 나뉜다.</p>
<ul>
<li>SISO: 입력과 출력이 각각 하나뿐인 단순한 시스템으로, 차량 속도 하나만 제어하는 크루즈 컨트롤이 해당된다.</li>
<li>MIMO: 입력과 출력이 여러 개인 복잡한 시스템으로, 차량의 조향과 속도와 서스펜션을 통시에 제어하는 통합 제어 시스템이 해당된다.</li>
</ul>
<h3 id="vehicle-motion">Vehicle Motion</h3>
<p>자유도는 간단히 말해 차량이 움직일 수 있는 방향과 방법의 개수를 의미한다. 차량 운동의 자유도(DOF)는 6이다.</p>
<ul>
<li><strong>6-DOF Vehicle Body</strong>: $X, Y, Z$ 방향으로 병진 운동(직선 운성), 회전 운동(Roll: 좌우 기울기, Pitch: 앞뒤 기울기, Yaw: 코너링)</li>
<li>서스펜션과 타이어의 추가 자유도<ul>
<li><strong>4-DOF Suspension</strong>: 네 개의 타이어로 전달되는 unsprung mass의 수직 운동<ul>
<li>서스펜션은 차량과 차체를 연결하는 장치로, 노면으로부터 들어오는 진동을 흡수하고 타이어의 접지력을 확보하는 역할을 한다.</li>
<li>현가장치(서스펜션) 아래에 걸려 있는 물체들의 총 질량을 현가하질량(unsprung mass)라고 한다. 현자하질량에 해당되는 부위로 휠과 타이어, 브레이크, 너클 및 허브 등이 있다.</li>
</ul>
</li>
<li><strong>4-DOF Wheel</strong>: 네 개의 바퀴의 위아래 움직임</li>
<li><strong>Tire</strong>: 각 바퀴의 회전 운동</li>
</ul>
</li>
</ul>
<p>이러한 자유도를 고려한 전체 모델은 복잡하지만, 실질적인 제어 시스템 설계나 분석을 할 때는 간략화된 모델을 주로 사용하게 된다.</p>
<h2 id="longitudinal-dynamics">Longitudinal Dynamics</h2>
<p>승용차에 사용되는 종방향 제어 시스템에는 cruise control(지정된 속도로 주행), anti-lock brake system(브레이크 잠김 방지), traction control system(가속 상황용 ABS)이 있다. 이외에도 다양한 첨단 종방향 제어 시스템이 연구되고 있다.</p>
<p>자동차 종방향($x$축) 운동의 주요 요소로는 차량 동역학, 파워트레인 동역학이 있다.</p>
<h3 id="종방향-운동-방정식">종방향 운동 방정식</h3>
<p>경사진 도로에서 pure 종방향 운동으로, 횡방향 운동은 없다고 가정한다.</p>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/050ebbd8-f5c2-4942-b49f-c1b9fc79c27f/image.png" alt=""></p>
<p>차량이 앞뒤 방향으로 움직일 때 작용하는 힘들의 관계를 나타내는 기본적인 방정식은 다음과 같다.
$$
\sum{F}=ma \
\text{}\
m\ddot{x}=-F_\text{aero}+F_\text{xf}+F_\text{xr}-(R_\text{xf}+R_\text{xr})-mg\sin{\theta}
$$</p>
<p>질량이 $m$인 자동차의 position이 $x$일 때 두번 미분한 $\ddot{x}$은 가속도를 의미한다. $F_\text{aero}$는 자동차의 반대 방향으로 작용하는 힘이므로 negative로 계산한다. 전륜, 또는 후륜일 때 타이어의 종방향 힘을 $F_\text{xf}, F_\text{xr}$로 두며 파워트레인 타입에 따라 둘 중 하나의 값은 0일 수도 있다. Rolling resistance(구름 저항)을 나타내는 $R_\text{xf}, R_\text{xr}$는 타이어가 도로 위를 굴러갈 때 발생하는 저항이므로 negative로 계산한다. 또한 아래로 끌어당기는 중력은 자동차의 종방향 운동에서 $g\sin\theta$ 방향으로 작용하므로 $mg\sin{\theta}$를 negative로 계산한다.</p>
<p><strong>차량의 가속도는 타이어의 추진력에서 구름 저항, 공기 저항, 경사로 인한 저항을 뺀 값에 의해 결정된다.</strong></p>
<h3 id="aerodynamic-drag-force">Aerodynamic Drag Force</h3>
<p>공기역학적 힘(Aerodynamic Forces)는 차량이 공기와 상호작용할 때 발생하는 다양한 힘을 의미하며, 대표적으로는 공기 저항력, 측방향 힘, 양력, 모멘트가 있다.</p>
<ul>
<li><p><strong>공기역학적 항력, 공기 저항(Aerodynamic Drag Force)</strong>
자동차가 움직일 때 공기와의 마찰로 인해 저항력이 발생하며 이를 공기저항력이라고 한다.
$$
F_\text{aero}=\frac{1}{2}\rho C_dA_F(V_x+V_\text{wind})^2
$$</p>
<ul>
<li>$\rho$는 공기저항력을 의미하며 일반적으로 지상에서 $1.225\text{kg/m}^3$로 가정된다.
항력 계수 $C_d$는 차량 디자인에 따라 다르며 공기저항을 최소화할수록 낮은 값을 가진다. 매끄러운 표면과 둥근 모서리를 가진 유선형 디자인의 차량은 공기의 흐름을 방해하지 않아 항력 계수를 낮출 수 있다. 일반적인 승용차의 공기 저항 계수는 약 $0.3$ 내외이다. (콘셉트 카의 경우 0.27 정도)</li>
<li>$A_F$는 차량의 앞쪽에서 본 면적이다. 차체의 폭과 높이를 곱한 값이며, 차량의 크기에 따라 달라진다. 차량 바닥 아래 공간도 포함되며 일반적으로 폭과 높이를 곱한 값의 79~84%를 차지한다. 서스펜션이 낮으면 차량 전면부 면적이 작아지므로 공기저항을 낮출 수 있어 속도가 빨라진다.</li>
<li>$V_x$는 자동차가 도로 위에서 움직이는 속도, $V_\text{wind}$는 주행 방향에 따른 바람의 영향을 나타낸다. 자동차 진행 방향과 반대 방향으로 부는 맞바람의 경우 $V_\text{wind}$는 증가하고 자동차와 같은 방향으로 부는 뒷바람의 경우 감소한다. 공기저향력은 속도의 제곱에 비례한다. 자동차의 속도가 두배가 되면 공기저향력은 네배 증가한다. 속도가 빠를수록 연료의 소모가 많아지는 이유가 바로 공기저항력 때문이다.</li>
</ul>
<p>차량이 공기저항을 극복하려면 일정한 힘을 가해야 하며, 이를 위해 엔진이 출력을 만들어야 한다. 출력(Power)는 다음과 같이 표현된다
$$
\text{Power}=\text{Force}\times\text{Velocity}\propto{V_x^3}
$$</p>
<ul>
<li>여기에서 Force, $F_\text{aero}$를 고려하면 필요한 출력은 속도의 세제곱에 비례한다. 따라서 속도가 두배가 되면 차량이 공기저항을 극복하기 위해 필요한 출력은 8배 증가한다.</li>
</ul>
</li>
<li><p>Side force (측방향 힘)
자동차가 움직일 때 옆 방향에서 바람이 물어 발생하는 힘이다.
$$
S_A=\frac{1}{2}\rho C_sAV^2
$$</p>
<ul>
<li>측방향 힘 계수 $C_s$는 차량의 형태나 바람 각도에 따라 달라진다.</li>
<li>$A$는 차량 전면 면적을 의미한다.</li>
<li>$V$는 전차 바람 속도를 의미한다.</li>
<li>측방향 힘이 크면 차량의 직진 안전성을 해친다.</li>
<li>측방향 힘은 보통 차량 무게 중심보다 뒤에 위치한 압력 중심에 작용하여 차량을 회전시키려는 경향이 있다. 차량의 진행방향에서 무게중심 뒤쪽으로 측방향 힘이 작용하면 앞쪽에서 작용하는 것보다 더 안정적이다.</li>
</ul>
</li>
<li><p>Lift force (양력)
차량 위쪽과 아래쪽 압력 차이로 인해 차량이 위로 뜨려고 하는 힘이다.
$$
L_A=\frac{1}{2}\rho C_LAV^2
$$</p>
<ul>
<li>양력 계수 $C_L$은 일반적인 승용차의 경우 $0.3\sim0.5$ 수준이다.</li>
<li>양력이 커지면 타이어의 접지력이 떨어져 고속 주행 안정성이 떨어진다.</li>
<li>양력을 줄이기 위해 차량 앞부분을 낮추거나 spoiler를 사용한다.</li>
</ul>
</li>
<li><p>모멘트 (Pitching, Yawing, Rolling Moment)</p>
<ul>
<li>모멘트는 차량에 회전을 일으키는 힘이며, pitch, yaw, roll로 구분된다.
$$
M=\frac{1}{2}\rho C_MALV^2
$$</li>
<li>모멘트 계수 $C_M$은 별도로 정의된다.</li>
<li>$L$은 차량 휠베이스 즉, 앞바퀴와 뒷바퀴 간의 거리를 의미한다.<h4 id="coast-down-test">Coast-down Test</h4>
차량의 공기저항력과 구름저항력을 실험적으로 측정하기 위해 Coast-down test를 진행한다.</li>
</ul>
</li>
<li><p>이 테스트는 차량을 일정 속도로 주행한 후 중립 기어 상태로 전환하여 차량이 자연스럽게 감속할 때의 속도 변화를 측정하여 <strong>공기저항력 계수</strong>($C_d$)와 <strong>구름저항력 계수</strong>을 추정하는 방식이다.</p>
</li>
<li><p>Coast-down Test의 수행 조건 및 가정</p>
<ul>
<li>차량은 평탄한 도로에서 진행한다.</li>
<li>차량의 변속기는 중립에 두고, 가속이나 브레이크 사용 없이 차량이 자연히 멈추게 둔다.</li>
<li>이때 차량의 속도 감소는 공기 저항력과 구름 저항력 때문이라고 가정한다.</li>
<li>차량과 타이어의 slip은 매우 작다고 가정하며, 바람 속도는 0으로 가정한다.
$$
m\ddot{x}=-F_\text{aero}+F_\text{xf}+F_\text{xr}-(R_\text{xf}+R_\text{xr})-mg\sin{\theta} \
=-F_\text{aero}-(R_x)\
\qquad =-\frac{1}{2}\rho C_dA_FV_x^2-R_x
$$<ul>
<li>이때 미지수: $C_d, R_x$<h4 id="reducing-air-drag">Reducing air drag</h4>
공기 저항력을 감소시키는 방법은 차량의 연비와 성능 향상에 필수적이다. 대표적인 방법은 다음과 같다.</li>
</ul>
</li>
</ul>
</li>
<li><p>전면 면적 최소화</p>
<ul>
<li><strong>Tandem seats</strong>: 좌석을 앞뒤로 배치하여 폭을 좁게 만든다. (일반적으로 두 사람이 앞뒤로 위치하는 것)</li>
<li>폭 좁은 타이어 사용</li>
<li>작은 사이드 미러 사용</li>
</ul>
</li>
<li><p>고속 주행 시 차량 높이를 낮춘다.</p>
<ul>
<li><strong>Ground effect (지면 효과)</strong>: 차량 하부로 흐르는 공기 흐름을 감소시켜 공기 저항을 줄인다.</li>
</ul>
</li>
<li><p>차량 형태 개선</p>
<ul>
<li>곡선 차량 모서리</li>
<li>부드러운 차량 하부</li>
<li>차량의 앞뒤 너비를 줄인 디자인</li>
<li>예시: 기존 24 mpg 차량을 공기역학적 설계를 개선하여 32 mpg로 개선할 수 있다.<h3 id="타이어의-logitudinal-force">타이어의 Logitudinal Force</h3>
차량의 가속 또는 감속을 결정하는 가장 중요한 힘은 타이어가 지면에 가하는 종방향 힘이다. 타이어의 종방향 힘은 세 가지 주요 요소(슬립 비율, 수직 하중, 마찰 계수)에 의해 결정된다.</li>
</ul>
</li>
<li><p>Slip ratio
 슬립 비율은 타이어가 회전하여 지면을 밀고 나가는 속도와 실제 차량이 진행하는 속도 간의 차이를 나타낸 비율이다. 슬립 비율의 정의는 다음과 같다.
 $$
 \sigma_x=\frac{r_{eff}\omega_w-V_x}{\max(r_{eff}\omega_w,V_x)}
 $$</p>
<ul>
<li>타이어의 유효 회전 반경을 $r_{eff}$로 나타낸다. 타이어의 각속도를 $\omega_w(\text{rad/s})$로 나타낸다. $V_x(\text{m/s})$는 차량의 실제 진행 속도이다.</li>
<li>슬립 비율이 0이면 타이어의 회전 속도와 차량의 이동 속도가 정확히 일치함을 의미한다. 슬립 비율이 양수이면 타이어가 실제 이동속도보다 빠르게 회전하며 추진력을 생성하는 가속 상태임을 의미한다. 슬립 비율이 음수이면 타이어 회전 속도가 차량의 이동 속도보다 느려 제동력을 생성하는 상태이다.<ul>
<li>웅덩이에서는 차량은 움직이지 못하고 바퀴만 빠르게 움직이므로 슬립 비율은 양수이다. 분모는 $r_{eff}$이다.</li>
<li>제동 시에는 차량은 움직이고 있지만 바퀴는 느리게 움직이는 제동 상태이다. 분모는 $V_x$이다.</li>
<li>슬립 비율에 따른 타이어 종방향 힘의 특성은 다음과 같다.</li>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/ea5aa4b5-b962-4858-942b-422aecd8c2a5/image.png" alt=""></li>
<li><strong>선형 영역</strong> (small slip, $|s|&lt;0.1$): 슬립 비율이 작을 때 타이어 힘은 슬립 비율과 거의 선형 비례한다.
$F_{xf}=C_{\sigma f}\sigma_{xf}$ 즉, 타이어 앞바퀴의 종방향 힘은 앞 타이어의 슬립 비율에 비례한다. ($C_{\sigma f}$는 타이어의 특성을 나타내는 상수인 슬립 강성)</li>
<li><strong>비선형 영역</strong> (large slip, $|s|&gt;0.1$): 일정 슬립을 초과하면 타이어 힘이 최대치에 도달하고, 이후 더 이상 증가하지 않고 감소하거나 일정하게 유지된다. 이 영역은 불안정 영역으로서, 미끄러짐이 발생할 수 있다. 가속 구간, 제동 구간이 이 영역에 해당한다.</li>
<li>안정적인 주행을 위해서는 슬립 비율을 적절히 제어하여, 일반 주행 시 타이어가 비선형 영역에 진입하지 않도록 해야 한다.</li>
</ul>
</li>
</ul>
</li>
<li><p>Normal load on the tire
타이어가 지면을 수직으로 누르는 힘을 노말 하중($F_2$)이라 한다. 이상적인 조건에서 타이어 종방향 힘은 노말 하중에 대해 다음과 같은 형태로 표현된다.
$$
F_x=\mu\cdot{F_z}, \quad(\text{Coulomb friction 가정)}
$$</p>
<ul>
<li>타이어가 낼 수 있는 최대 종방향 힘 $F_x$는 노말 하중 $F_z$과 타이어-도로 마찰계수 $\mu$의 곱과 같다. 다만, 실제 타이어 힘은 슬립 비율과 하중의 복잡한 함수로 결정된다$(F_x=f(F_z,\mu,\sigma))$. 위 수식은 최대 힘의 이상적 한계를 의미한다.</li>
</ul>
</li>
<li><p>Friction coefficient of the tire-road interface</p>
<ul>
<li>마찰계수 $\mu$는 타이어와 노면 간의 접촉 특성에 따라 결정된다.<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/f56e199f-5df9-4a15-9d9e-6a1e4b03547b/image.png" alt=""></li>
<li>건조한 아스팔트: 높은 마찰계수 (약 0.7~1.0)</li>
<li>젖은 노면: 낮은 마찰계수 (약 0.3~0.6)</li>
<li>빙판길: 매우 낮은 마찰계수 (약 0.1~0.2)</li>
</ul>
</li>
<li>최대 트랙션 또는 제동력은 타이어와 노면의 최대 정지 마찰 계수에 의해 결정된다.</li>
<li>최대 마찰력을 완벽히 활용하기 위해서는 노면 조건에 따라 슬립 비율을 최적으로 제어하는 것이 매우 중요하다.<ul>
<li>ABS나 TCS은 모두 최적 슬립 제어의 대표적 예시이다.</li>
<li>최적 슬립 비율 영역에서 타이어 힘이 최대가 되도록 제어해야 한다.<h3 id="tire-contact-patch">Tire Contact Patch</h3>
타이어 접촉면이란 타이어가 지면과 직접 맞닿는 면적을 의미한다. 타이어 힘 발생의 핵심 영역이다.</li>
</ul>
</li>
</ul>
</li>
<li><p>타이어 tread는 개별적인 독립된 스프링처럼 모델링된다. - 접촉면은 정지 영역과 미끄러짐 영역으로 나뉘며, 이 영역들의 비율이 슬립 비율과 힘의 특성을 결정한다.</p>
<ul>
<li><strong>정지 영역</strong>:  트레드가 변형되지 않고 움직임 없이 접촉하는 영역</li>
<li><strong>슬라이딩 영역</strong>: 타이어 트레드 요소들이 변형되고, 이 변형으로 인해 스프링 힘이 발생하여 타이어 힘을 형성하는 영역</li>
<li>슬립 비율이 클수록 슬라이딩 영역이 넓어지며, 이에 따라 타이어의 힘과 마찰 특성도 달라지게 된다.<h3 id="rolling-resistance">Rolling Resistance</h3>
타이어가 도로를 굴러갈 때, 타이어와 노면 사이에서 발생하는 저항력을 구름 저항이라고 한다. 구름 저항은 다음과 같은 수식으로 표현된다.
$$
R_{xf}+R_{xr}=f_r(F_{zf}+F_{zr})
$$</li>
</ul>
</li>
<li><p>앞뒤 타이어에서 발생하는 구름 저항력의 합 $R_x$는 구름저항계수 $f_r$과 타이어가 받는 전체 노말 하중 $F_z$의 곱으로 나타낼 수 있다.</p>
<ul>
<li>구름저항계수 $f_r$은 0.01~0.04 사이의 값으로, 일반 승용차의 값은 약 0.015이다.</li>
<li>실제 타이어 반경보다 타이어가 굴러가는 구름 반경이 더 작아지는 현상이 발생하면 구름 저항이 발생한다.<ul>
<li>rolling radius: 타이어가 노면에서 실제로 굴러갈 때의 유효 반경</li>
<li>타이어가 지면과 접촉하면서 눌리고 변형되기 때문에 기하학적 반경보다 작은 유효 반경으로 굴러간다. 이로 인해 타이어 내부의 에너지 손실이 발생하여 마찰 손실(friction loss)이 생긴다.</li>
</ul>
</li>
<li>고체 바퀴는 변형이 없으므로 이론적으로 구름 저항이 0에 가깝다.</li>
<li>구름 저항의 moment balance<ul>
<li>타이어가 노면과 접촉할 때 접촉점을 기준으로 모멘트 평형을 세운다.</li>
<li>타이어의 중심이 앞으로 살짝($\Delta x$) 이동하게 되며 이로 인해 타이어가 받는 수직 하중 $F_z$와 구름 저항 $R_x$ 사이에 다음과 같은 관계가 형성된다.
$$
R_x\approx\frac{F_z\Delta x}{r_{stat}}
$$</li>
<li>구름 반경을 $r_{stat}$이라 정의한다.</li>
</ul>
</li>
</ul>
</li>
<li><p>구름 저항에 영향을 미치는 요소</p>
<ul>
<li><strong>타이어 온도</strong>: 온도가 낮으면 구름 저항 증가한다. 주행 초반엔 타이어 온도가 낮아 구름 저항이 높고, 주행 후 타이어가 뜨거워지면서 저항이 감소하여 연비가 향상된다.</li>
<li><strong>타이어 공기압</strong>: 포장 도로에서는 공기압이 높을수록 타이어 변형이 줄어 저항이 감소하고 연비가 증가한다. 부드러운 지면에서는 공기압이 낮아야 저항이 감소한다.</li>
<li><strong>차량 속도</strong>: 고속일수록 타이어가 더 많이 변형되고 진동이 증가하여 구름 저항도 증가한다.</li>
<li>타이어 재질과 설계: 재질 및 두께, 재질에 따라 저항이 달라진다.</li>
<li><strong>타이어 슬립</strong>: 급가속/감속 또는 코너링 시 미끄러짐이 발생하며 마찰로 인해 구름 저항이 증가한다.<h3 id="dynamic-weight-shifting">Dynamic Weight Shifting</h3>
차량이 종방향으로 가속 또는 감속하면, 타이어에 가해지는 하중이 앞뒤로 이동하게 된다. 이 현상을 동적 무게 이동이라고 한다.<h4 id="동적-무게-이동-현상">동적 무게 이동 현상</h4>
가속할 때 차량은 뒤로 기울어지며(pitch-up), 앞바퀴에서 뒷바퀴로 하중이 이동한다. 감속할 때는 반대로 차량이 앞으로 기울어지며(pitch-down), 뒷바퀴에서 앞바퀴로 하중이 이동한다. 이 현상이 중요한 이유는 다음과 같다.</li>
</ul>
</li>
<li><p>타이어 하중의 변화는 타이어가 만들어낼 수 있는 종방향 힘에 영향을 준다.</p>
</li>
<li><p>동적 무게 이동 현상은 차량의 가속/제동 성능과 안정성에 직결된다.</p>
<h4 id="차량-동적-무게-이동에-대한-운동-방정식">차량 동적 무게 이동에 대한 운동 방정식</h4>
</li>
</ul>
<ol>
<li>뒷바퀴 접촉점을 기준으로 모멘트 평형
다음 수식은 차량 뒷바퀴 접촉점을 기준으로 한 힘의 평형을 나타낸다.
$$
F_{zf}(l_f+l_r)=mgl_r\cos\theta+mgh\sin\theta-mh\ddot{x}-hF_{aero}
$$
이 수식을 정리하면 앞바퀴의 수직 하중 $F_{zf}$는
$$
F_{zf}=\frac{mgl_r\cos\theta+mgh\sin\theta-mh\ddot{x}-hF_{aero}}{l_f+l_r}
$$<ul>
<li>$l_r,l_f$는 차량의 무게 중심에서 앞/뒷바퀴까지의 거리를 의미한다. $h$는 차량의 무게 중심 높이, $\theta$는 도로의 경사각, $\ddot{x}$는 차량의 가속도를 의미한다.</li>
<li>차량이 가속($\ddot{x}&gt;0$)하면 앞바퀴 하중이 감소하고, 뒷바퀴롤 하중이 이동한다. 반대로 차량이 감속($\ddot{x}&lt;0$)하면 앞바퀴 하중이 증가한다.</li>
</ul>
</li>
<li>앞바퀴 접촉점을 기준으로 모멘트 평형
똑같은 방법으로 차량 앞바퀴 접촉점에서 힘의 평형을 고려하면, 뒷바퀴 수직 하중에 대한 방정식은 다음과 같다.
$$
F_{zr}(l_f+l_r)=mgl_f\cos\theta+mgh\sin\theta-mh\ddot{x}-hF_{aero}
$$</li>
</ol>
<ul>
<li>수식의 물리적 의미<ul>
<li>차량이 가속할 때 뒷바퀴 하중은 증가하고 앞바퀴 하중은 감소한다. 반대로 차량 감속할 때 앞바퀴 하중은 증가, 뒷바퀴 하중은 감소한다.</li>
<li>무게 중심이 높을수록 하중 이동의 효과가 더 커진다.</li>
<li>경사로 각도가 존재하면, 경사로에 의한 중력 성분이 추가로 하중 이동을 일으킨다.</li>
<li>공기 저항력은 차량의 하중 분포에도 영향을 미치며, 주로 고속 주행 시 유의미하다.</li>
</ul>
</li>
<li>차량 동적 무게 이동 현상의 실제 영향
차량의 무게 이동 현상은 실제 차량 제어에 매우 중요한 역할을 한다.<ul>
<li>제동 시 앞바퀴 하중 증가로 앞바퀴 제동력이 커지지만, 뒷바퀴 하중이 너무 감소하면 뒷바퀴가 쉽게 미끄러질 수 있다.</li>
<li>가속 시 뒷바퀴 하중 증가로 추진력을 확보할 수 있으나, 앞바퀴 하중 감소는 차량 조향 안정성을 감소시킨다.</li>
<li>따라서 차량 설계나 제어 시스템 설계 시 하중 이동 효과를 반드시 고려해야 한다.<h2 id="powertrain-dynamics">Powertrain Dynamics</h2>
파워트레인이란, 엔진에서 발생한 동력을 차량 바퀴까지 전달하는 전체 시스템을 의미한다.<h3 id="engine-특성과-모델링">Engine 특성과 모델링</h3>
엔진의 핵심 특성은 엔진 회전속도(RPM)에 따라 발생하는 토크와 출력의 관계이다.</li>
</ul>
</li>
<li>엔진은 회전 속도 $\omega_e$와 엔진 토크 $T_e$의 관계로 특성이 결정된다. 이를 나타내는 것이 <strong>Engine Map</strong>이며, 복잡한 수학적 모델링 없이, 실험을 통해 얻은 데이터를 이용하여 Map을 작성한다. 스로틀 각도가 $\alpha$일 때, 엔진 토크는 다음과 같다.
$$
T_e=f(\omega_e,\alpha)
$$
 주의: 엔진 회전 속도 $\omega_e$, 타이어 회전 속도 $\omega_w$</li>
<li>엔진 맵은 엔진의 현재 회전 속도와 가속 페달의 위치(스로틀 각도)를 입력으로 하여, 엔진에서 생성되는 토크를 실험 데이터 기반으로 예측한다.</li>
<li>Engine Rotational Speed Dynamics
$$
I_e\dot{\omega}_e=T_i-T_f-T_a-T_p
$$<ul>
<li>$I_e$: 엔진이 회전할 때 필요한 관성</li>
<li>$T_i$: 엔진에서 연료의 연소에 의해 발생하는 토크</li>
<li>$T_f$: 엔진 내부의 마찰로 인해 소모되는 토크</li>
<li>$T_a$: 발전기, 에어컨 등 엔진에 부착된 부가장치에서 소모되는 토크</li>
<li>$T_p$: 엔진에서 작동하는 유체 펌프에 의해 소모되는 토크</li>
<li>엔진의 회전 속도 변화는 엔진에서 발생하는 총 토크와 마찰, 부가 장치, 펌프에 의해 소모되는 토크의 차이에 의해 결정된다. 즉, 엔진이 생성하는 토크 $T_i$에서 마찰 손실, 부가 장치 토크, 펌프 토크를 빼면 엔진의 회전 속도를 증가시키는 데 기여하는 순(pure) 토크가 된다. 이 순 토크가 엔진의 관성 모멘트 $I_e$와 곱해져서 엔진의 회전 속도 변화율에 영향을 미친다.</li>
<li>Net Engine Torque After Loss<ul>
<li>엔진이 생성하는 토크 $T_e$에서 손실 토크를 빼서 실제로 엔진이 출력하는 토크를 구할 수 있다.</li>
<li>$T_e=T_i-T_f-T_a$</li>
<li>$T_p$는 외부에서 작용하는 부하 토크 즉, 엔진이 만든 토크를 소모하는 힘이므로, 엔진이 실제로 생성한 $T_e$와는 상관이 없다.</li>
<li>$I_e\dot{\omega}_e=T_e-T_p$</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="torque-converter">Torque Converter</h3>
<p>토크 컨버터는 자동 변속기 차량에서 엔진과 변속기 사이의 유체 커플링(Fluid  coupling) 장치로서, 토크를 변속기로 전달하는 역할을 한다.</p>
<ul>
<li>유체를 통해 동력을 전달하는 장치로, 클러치 없이도 자동으로 엔진의 동력을 변속기에 전달할 수 있게 한다.</li>
<li>두 개의 선풍기가 마주보는 것과 같은 원리로, 한쪽이 회전하면 공기의 흐름으로 인해 반대편이 회전하게 된다.</li>
<li>기본 부품으로 impeller, turbine, stator가 있다.<ul>
<li><strong>임펠러(Impeller)</strong>: 엔진과 연결되어 오일을 회전하는 역할을 한다. 원심력을 이용한 펌프와 같은 작동을 한다.</li>
<li><strong>터빈(Turbine)</strong>: 임펠러가 생성한 오일의 흐름에 의해 회전하며, 변속기 기어와 연결되어 동력을 전달한다.</li>
<li><strong>스테이터(Stator)</strong>: 임펠러와 터빈 사이에서 오일의 흐름을 원활히 하도록 도와주며, 저속에서의 토크 증폭 효과를 제공한다.</li>
<li>엔진이 임펠러를 회전시키면 오일이 회전하며 터빈이 회전하게 되어 변속기가 움직인다.</li>
<li>출발할 때 저속으로 움직이면 스테이터가 토크 증폭 효과를 제공하며, 차량이 일정 속도에 도달하면 효율적인 동력 전달을 위해 lock-up clutch가 작동하여 임펠러와 터빈을 직접 결합한다.<ul>
<li><strong>Lock-up clutch</strong>: 일정 속도에서 임펠러와 터빈을 기계적으로 연결하여 토크 컨버터의 효율을 증가시키는 역할을 한다. Lock-up clutch 사용 시, 슬립이 감소하여 효율이 높아진다.</li>
</ul>
</li>
</ul>
</li>
<li>Torque Converter modeling<ul>
<li>펌프 토크가 $T_p$, 터빈 토크가 $T_t$, 펌프 속도가 $\omega_p=(\omega_e)$, 터빈 속도가 $\omega_t$일 때 효율을 계산하는 수식은 다음과 같다.
$$
\text{Efficiency}=\frac{T_t\omega_t}{T_P\omega_e}
$$</li>
</ul>
</li>
</ul>
<h3 id="automatic-transmission-원리-및-구성">Automatic Transmission 원리 및 구성</h3>
<p>자동 변속기는 다양한 기어비를 제공하여, 차량 주행 상태에 따라 최적의 동력 전달을 주행하는 장치이다. 자동 변속기의 핵심 부품은 <strong>토크 컨버터</strong>이다. 일반적으로 전진 3~4개의 기어와 후진 1개의 기어로 구성된다.</p>
<ul>
<li>변속기의 작동 방식은 다음과 같다.<ol>
<li>엔진 회전 속도가 증가하면 토크 컨버터의 임펠러 오일을 회전시키고, 이 오일이 터빈을 회전시켜 변속기의 입력축을 구동한다.</li>
<li>속도가 증가하면 변속기는 자동으로 적절한 기어를 선택하여 최적의 회전 속도와 토크를 바퀴에 전달한다.</li>
</ol>
<ul>
<li>차량의 가속 시, 터빈의 회전 속도가 점차 임펠러의 속도에 가까워지고, 일전 조건에 도달하면 Lock-up clutch가 작동하여 효율을 높인다.</li>
</ul>
</li>
<li>변속 과정에서의 동역학적 특성은 다음과 같이 설명된다.<ul>
<li>변속 단계가 증가할수록 기어비 $R$은 점차 감소한다.</li>
<li>일반적으로 $R&lt;1$이며, 상위 기어로 변속될수록 더 작은 토크로 높은 속도를 얻을 수 있다.</li>
<li>변속 과정에서는 토크 컨버터에서 출력된 터빈의 토크 $T_t$와 속도 $\omega_t$가 변속기를 통해 휠 토크 $T_w$로 전달된다.</li>
<li>$I_t\dot{\omega}<em>t=T_t-RT</em>{wheel}=T_t-R(I_\omega\dot{\omega}<em>w+r</em>{eff}F_x)$<ul>
<li>터빈의 토크 $T_t$가 휠의 토크 $T_t$로 전달되고, $T_{wheel}=\frac{1}{R}T_t$가 성립한다.</li>
</ul>
</li>
<li>Transmission과 휠 속도는 $\omega_w=R\omega_t$ 관계가 성립한다.<h2 id="drivetrain">Drivetrain</h2>
<h3 id="drivetrain-power-flow">Drivetrain Power Flow</h3>
드라이브트레인의 역할은 엔진에서 바퀴까지의 동력 흐름을 직접적으로 연결하는 것이다. 드라이브트레인의 구성 요소는 다음과 같이 정의된다.</li>
</ul>
</li>
<li><em>엔진(Engine) → 토크 컨버터(Torque Converter) → 변속기(Transmission) → 구동축(Drive Axle) → 차동기어(Differential Gear) → 바퀴(Wheel)*</em>
Power는 위의 순서로 흐른다. 엔진에서 동력을 생성하고 토크 컨버터가 엔진의 회전을 변속기로 전달하면, 변속기는 기어비를 통해 속도와 토크를 변환하여 전달하고 구동축은 변속기의 출력을 차동기어로 전달하여 회전 및 주행하게 된다. 
(Load(부하)는 반대 방향으로 흐른다.)</li>
<li>차량의 종방향 운동 방정식에 따르면 tire force $F_{xf}+F_{xr}$은 차량이 움직이게 하는 주요 힘이다. 이 힘은 휠의 속도 $r_{eff}\omega_w$와 실제 속도 $V_x$의 차이에 의해 결정된다(Slip). 휠의 각속도 $\omega_w$는 drivetrain dynamics의 영향을 받는다.<h3 id="dynamics-during-a-gear-change">Dynamics during a gear change</h3>
안정된 상태에서 기어비 $R$ 값은 operating gear에 달려 있다. Transmission shaft 속도와 스로틀에 따라 gear shift가 결정되고, 작동 기어가 정해진다.</li>
<li>연비 및 차량 동력 성능을 고려하여 Gear shift schedule 맵이 사전에 설정되어 있다.<h3 id="wheel-dynamics">Wheel Dynamics</h3>
엔진의 동력이 전달되어 차량을 실제 움직이는 바퀴인, 구동 바퀴의 회전 운동 방정식은 $I_t\dot{\omega}<em>t=T_\text{wheel}-r</em>{eff}F_x$로 나타낼 수 있다. 구동하지 않는 바퀴는 엔진으로부터의 구동력이 없기 때문에 지면과 굴러가는 역할만 한다. 비궁동 바퀴에서는 타이어가 발생시키는 힘 $F_x$만이 바퀴 회전에 영향을 준다. 따라서 $I_t\dot{\omega}<em>t=-r</em>{eff}F_x$이다.</li>
<li>Wheel torque $T_{wheel}$은 brake torque와 driving torque의 합으로 표현할 수 있다. 차량 종방향 동역학을 통해 종방향 타이어 힘 정보를 구할 수 있다.
$$
T_{wheel}=I_\omega\dot{\omega}<em>{wf}+r</em>{eff}F_{xf}
$$<h3 id="타이어-종방향-힘과-engine-dynamics">타이어 종방향 힘과 Engine Dynamics</h3>
타이어 힘은 질량과 가속도의 곱, 주행으로 인한 저항의 합으로 구할 수 있다.
$$
F_x=m\ddot{x}+F_{load}=mr_{eff}R\dot{\omega}<em>e+F</em>{load}
$$</li>
<li>엔진 역학과 연계하면 다음과 같다.
$I_e\dot{\omega}<em>e=T_e-R(I_w\dot{\omega}_w+R</em>{eff}F_x)$
$$
(I_e+I_wR^2+mR^2r^2_{eff})\dot{\omega}<em>e=T_e-R(R</em>{eff}F_{load})
$$
$$
J_e\dot{\omega}<em>e=T_e-R(r</em>{eff}F_{load})=T_e-T_{load}
$$</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[이산형 확률분포]]></title>
            <link>https://velog.io/@hyeon-ii/discrete-probability-distribution</link>
            <guid>https://velog.io/@hyeon-ii/discrete-probability-distribution</guid>
            <pubDate>Mon, 07 Apr 2025 07:58:47 GMT</pubDate>
            <description><![CDATA[<h2 id="베르누이-확률변수와-이항분포">베르누이 확률변수와 이항분포</h2>
<h3 id="bernoulli-random-variables">Bernoulli Random Variables</h3>
<p>결과값이 성공과 실패로 나누어지는 실험을 한 번 수행했다고 가정하자. 결과값이 성공일 경우 $X=1$, 실패일 경우 $X=0$이라고 하자. 성공 확률을 $P$라 할 때, 확률질량함수(pmf)가 다음과 같은 확률변수를 베르누이 확률변수라 한다.
$$
\begin{cases} p(0)=P{X=0}=1-p \
p(1)=P{X=1}=p \end{cases}
$$</p>
<ul>
<li><strong>Probability mass function</strong>: $p(x)=P(X=x)=p^x(1-p)^{1-x} \quad x=0,1$</li>
<li>$E(X)=0\times(1-p)+1\times p=p$<ul>
<li>$E(X^n)$을 $X$의 $n$번째 moment라고 하며, $E\Big((X-E[X])^n\Big)$을 $n$번째 central moment라고 한다.</li>
<li>Moment generating function $M_X(t)=E(X^k)=\sum_{x=0}^1x^kp^kq^{1-k}$</li>
</ul>
</li>
<li>$Var(X)=p(1-p)$<h3 id="binomial-distribution">Binomial Distribution</h3>
베르누이 시행을 $n$번 반복했을 때 ${X_1,\dots,X_n}$ 성공의 횟수를 이항 확률변수라고 한다. 각각의 $X$가 1의 값을 가질 확률을 $p$라 한다면 $X=X_1+\cdots+X_n$은 모수 $n$과 $p$를 갖는 <strong>이항분포</strong>를 가지며 $X\sim B(n,p)$로 나타낸다. (모수란 모집단 확률분포의 형태을 규정짓는 값을 의미한다.)
$$
P(X=x)={n\choose x}p^x(1-p)^{n-x}, \quad x=0,1,\dots,n
$$</li>
<li>$\sum_{x=0}^{n}{n\choose x}p^x(1-p)^{n-x}=1$</li>
<li>독립적인 베르누이 시행의 합으로 이항 확률변수를 고려해보면, $X=X_1+\dots,X_n$이므로
$E(X)=E(X_1)+\cdots E(X_n)=np$
$Var(X)=Var(X_1)+\dots Var(X_n)=np(1-p)$</li>
<li>$B(n,0.5)$ 분포는 모수 $n$의 기대값 $\frac{n}{2}$에 대하여 좌우대칭인 좌우대칭분포이다.<h2 id="기하분포geometric-distribution">기하분포(Geometric Distribution)</h2>
성공확률 $p$를 가지는 일련의 독립 베르누이 시행 시, 첫 번째 성공이 발생할 때까지 실시해야만 하는 총 시행 횟수를 확률변수로 갖는 분포를 기하분포라고 한다. 기하분포의 모수는 성공 확률인 $p$이다. 성공이 발생할 때까지 반복한 횟수가 $x$이면 확률은 다음과 같다.
$$
P(X=x)=(1-p)^{x-1}p
$$</li>
<li>$E(X)=\frac{1}{p}$</li>
<li>$Var(X)=\frac{1-p}{p^2}$</li>
<li>$P(X&gt;x)=(1-p)^xp+(1-p)^{x+1}p+\cdots=p(1-p)^x\Big(1+(1-p)+(1-p)^2+\cdots\Big)=(1-p)^x$</li>
<li>$P(X&gt;n+x|X&gt;n)=\frac{P(X&gt;n+x)}{P(X&gt;n)}=P(X&gt;x)$<ul>
<li>이 수식을 만족하는 성질을 <strong>무기억 특성</strong>이라고 한다. 이전까지 시행된 결과가 다음 시행 확률에 영향을 주지 않는 것을 말한다.
기하분포는 무기억 특성을 갖는 유일한 이산형 분포이다.<h2 id="음이항분포negative-binomial-distribution">음이항분포(Negative Binomial Distribution)</h2>
성공확률이 $p$인 베르누이 실험을 $r$번째 성공이 발생할 때까지 수행한 횟수의 분포를 음이항분포라고 하며 $X\sim NB(r, p)$로 나타낸다. 이때 $X$는 모수가 $p, r$이며, 성공 횟수는 이항분포를 따른다.
$$
P(X=x)={x-1\choose r-1}(1-p)^{x-r}p^r, \quad x=r, r+1, \dots
$$
$X_i$가 $i$번째 성공이 나올 때까지 총 시행 회수를 의미할 때 독립적인 기하분포의 합 $X=X_1+\cdots+X_r$일 경우</li>
</ul>
</li>
<li>$E(X)=E(X_1)+\cdots+E(X_r)=\frac{r}{p}$</li>
<li>$Var(X)=Var(X_1)+\cdots+Var(X_r)=\frac{r(1-p)}{p^2}$<h2 id="초기하분포hypergeometric-distribution">초기하분포(Hypergeometric Distribution)</h2>
비복원추출에서 $N$개의 모집단 중 $n$개를 추출할 때, $r$번 성공할 확률에 대한 분포를 초기하분포라고 한다.
$$
P(X=x)=\frac{{r\choose x}\times{N-r\choose n-x}}{N\choose n}, \quad \max{(0, n+r-N)}\le x\le\min{(n,r)}
$$</li>
<li>$E(X)=\frac{nr}{N}$</li>
<li>$Var(X)=\frac{N-n}{N-1}\times n \times\frac{r}{N}\times (1-\frac{r}{N})$<h2 id="포아송분포poisson-distribution">포아송분포(Poisson Distribution)</h2>
단위시간 동안 어떤 사건이 발생하는 횟수를 확률변수로 정의하는 확률분포를 포아송 분포라고 하며, $X\sim Pois(\lambda)$로 나타낸다.
$$
P(X=x)=\frac{e^{-\lambda}\lambda^x}{x!}, \quad x=0,1,2,\dots
$$</li>
<li>$\sum_{x=0}^\infin P(X=x)=e^{-\lambda}\sum_{x=0}^\infin\frac{\lambda^x}{x!}=e^{-\lambda}e^\lambda=1$</li>
<li>$E(X)=\lambda$</li>
<li>$Var(X)=\lambda$</li>
<li>평균과 분산이 같다.<h2 id="다항분포">다항분포</h2>
발생 가능한 결과가 두 개인 이항 분포와 달리, 여러 개의 값을 가질 수 있는 독립 확률변수들에 대한 확률분포를 다항분포라고 한다. 각각의 결과값의 빈도수를 나타내는 확률변수들의 결합밀도함수는 다음과 같다.
$$
P(X_1=x_1,\dots,X_k=x_k)=\frac{n!}{x_1!\cdots x_k!}p_1^{x_1}\times\cdots\times p_k^{x_k}
$$</li>
<li>이때 $x_1+\cdots+x_k=n$</li>
<li>$E(X_i)=np_i$</li>
<li>$Var(X_i)=np_i(1-p_i)$</li>
<li>$p_1=1-p_2-\cdots-p_k$ 즉, 다른 사건에 따라 확률이 결정되므로 서로 독립적이지 않다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[확률변수]]></title>
            <link>https://velog.io/@hyeon-ii/%ED%99%95%EB%A5%A0%EB%B3%80%EC%88%98</link>
            <guid>https://velog.io/@hyeon-ii/%ED%99%95%EB%A5%A0%EB%B3%80%EC%88%98</guid>
            <pubDate>Tue, 01 Apr 2025 08:39:54 GMT</pubDate>
            <description><![CDATA[<h2 id="확률변수와-분포">확률변수와 분포</h2>
<ul>
<li>확률변수(<strong>Random variable</strong>): 표본공간(sample space)을 실수로 대응시키는 함수<ul>
<li>$X:\Omega\rightarrow\mathcal{R}$<ul>
<li>확률변수는 대문자 $X$로 표현하는 반면, 특정 value(사건)는 $x$로 표현한다. 즉 확률변수 $X$가 $x$일 확률은 $P(X=x)$</li>
</ul>
</li>
<li>확률 공간에서 가측공간으로대응시키는 함수</li>
<li>시행으로부터 무작위로 발생하는 사건들을 측정 가능한 숫자에 대응시키는 규칙</li>
<li>표본공간 $\Omega$는 가능한 모든 output을 의미한다. 즉, 동전을 던졌을 때 표본공간은 $\Omega={H, T}$</li>
</ul>
</li>
<li>어떤 시행의 표본공간으로부터 정의된 확률변수 $X$가 있을 때 집합 $A$를 실수 상의 임의의 부분집합($A\sub\mathcal{R}$)이라고 한다면 $P(x\in A)$는 집합 $A$에 대응되는 표본공간($\Omega$)의 집합 $s$의 확률과 같다. 즉, $P(X\in A)=P{s|X(s)\in A}$<h3 id="이산형-확률변수">이산형 확률변수</h3>
이산형 확률변수를 나타낼 때 일반적으로 알파벳 $P, p$를 사용한다.</li>
<li>예제) $X$: 주사위를 두 번 던져서 나온 두 값의 합<ul>
<li>표본공간: ${(1,1),(1,2),\cdots(6,6)}$</li>
<li>확률변수의 값이 유한하므로 확률변수 $X$는 이산형 확률변수이다.</li>
</ul>
</li>
<li>이산형 확률변수 $X$에 대해서 <strong>확률질량함수(probability mass function)</strong>은 $p(x)=P(X=x)$이며 집합 $A$의 확률은 $P(X\in A)=\sum_{x_i\in A}p(x_i)$<ul>
<li>확률질량함수는 함수의 값이 그 자체로 확률의 의미를 갖는다.</li>
</ul>
</li>
<li>The uniform distribution
확률변수 $X$가 정수 $1, 2, \cdots, n$에서 동일한 발생확률을 가진다면 확률질량함수 $p(x)=\frac{1}{n}$이다. 단, 이는 $x$가 1과 $n$ 사이의 값일 때 성립한다. 이외의 경우에는 $p(x)=0$이다.<h3 id="연속형-확률변수">연속형 확률변수</h3>
</li>
<li>예제) $X$: 실수 0과 1 사이에서 임의로 선택한 한 실수<ul>
<li>표본공간: 0과 1 사이 실수</li>
<li>특정 확률변수의 값 $x$가 선택될 확률 $P(X=x)=0$이지만 특정 구간에 대한 확률 $P(X&lt;x)=x$이다. 확률변수의 값이 가측 무한하지 않으므로 연속형 확률변수라고 한다.</li>
</ul>
</li>
<li>연속형 확률변수 $X$에 대해서 <strong>확률밀도함수(probability density function)</strong> $f(x)$는 다음 조건을 만족한다.<ol>
<li>확률밀도함수의 넓이는 1이다. 즉, $\int_{-\infin}^{\infin}f(x)dx=1$<ul>
<li>확률밀도함수는 확률이 아니다. 따라서 확률밀도함수를 적분해서 1보다 큰 값이 나올 수는 있다. 확률을 구하고 싶다면 확률밀도함수를 특정 범위에서 적분하면 된다.</li>
</ul>
</li>
<li>확률밀도함수는 non-negative 함수이다. 즉, $f(x)\geq0$<ul>
<li>다만, 확률변수의 특정한 값에 대한 확률은 0이다. 즉, $P(X=x)=0$</li>
<li>확률밀도함에서 함수의 값은 단지 그 순간의 점에서 밀도일 뿐 확률을 뜻하지 않는다.</li>
</ul>
</li>
<li>실수의 부분집합 $A(\sube\mathcal{R})$에 대해서 확률변수 $X$가 영역 $A$에 속할 확률은 $P(X\in A)=\int_{x\in A}f(x)dx$로 표현한다.<ul>
<li>확률변수 구간 $(a,b)$의 확률은 $P(a&lt;X&lt;b)=\int_{a}^{b}f(x)dx$</li>
</ul>
</li>
</ol>
</li>
<li>The uniform distribution
확률변수 $X$가 실수구간 $(a,b)$에서 동일한 발생확률을 가진다면 확률밀도함수 $f(x)=\frac{1}{b-a}$이다. 단, 이는 $a&lt;x&lt;b$일 때 성립한다. 이외의 경우에는 $f(x)=0$이다.</li>
<li>연속형 확률변수의 경우 이산형 확률변수와 달리 중앙값이 존재하며 중앙값까지의 누적확률분포는 항상 0.5이다.<h3 id="분포함수">분포함수</h3>
누적분포함수를 나타낼 때 일반적으로 대문자 알파벳 $F$를 사용한다.</li>
<li>확률변수 $X$에 대해서 $x$에서의 <strong>누적분포함수(cumulative distribution function)</strong>은 다음과 같이 정의된다.
$$
F(x)=P(X\le x)
$$
누적분포함수는 <ol>
<li>이산형 확률변수 $X$일 때 $F(x)=\sum_{k\le x}f(k)=\sum_{k\le x}P(X=k)$</li>
<li>연속형 확률변수 $X$일 때 $F(x)=\int_{-\infin}^{x}f(k)dk$</li>
</ol>
</li>
<li>분포함수의 성질<ul>
<li>누적분포함수 $F(x)$는 $x$에 대한 비감소함수이다. 즉, $x$가 양의 방향으로 갈수록 증가하거나 유지한다. 무한대로 가면 1에 수렴한다. $a&lt;b$이면 $F(a)\le F(b)$</li>
<li>누적분포함수에 대해서 $x\rightarrow{-\infin}$이면 $F(x)\rightarrow0$, $x\rightarrow{\infin}$이면 $F(x)\rightarrow1$이 성립한다.</li>
<li>누적분포함수는 항상 우측연속성이 성립한다.</li>
</ul>
</li>
<li>분포함수의 연산<ul>
<li>$P(X&gt;x)=P(X\ge x)=1-F(x)$</li>
<li>$P(a&lt;X&lt;b)=F(b)-F(a)=\int_{a}^{b}f(x)dx$</li>
<li>$P(X&lt;x)=F(x^-)$ (continuous from the left)</li>
<li>$P(X=x)=F(x)-F(x^-)$<h3 id="이변량-분포">이변량 분포</h3>
두 확률변수가 동시에 고려되는 분포로, <strong>이변량 [이산형, 연속형, 누적분포함수, 주변분포]</strong>가 있다.</li>
</ul>
</li>
<li><strong>이산형 이변량 분포</strong>: 확률변수 $X$와 $Y$가 이산형 확률변수일 때, 순서쌍 $(X,Y)$를 이산형 결합 이변량 확률변수라고 한다.<ul>
<li>이변량 확률질량함수(joint bivariate pmf)는 다음과 같다.
$$
f(x,y)=P(X=x,Y=y)
$$<ol>
<li>$0\le f(x,y)\le 1$</li>
<li>$\sum_{x\in X}\sum_{y\in Y}f(x,y)=1$</li>
<li>확률질량함수: $P((X,Y)\in A)=\sum\sum_{(x,y)\in A}f(x,y)$, 이때 $A\sube\mathcal{R}^2$</li>
</ol>
</li>
</ul>
</li>
<li>$X,Y$ 각각에 대한 주변확률분포 <strong>marginal pdf</strong>는 다음과 같다.
$$
f_X(x)=\int f(x,y)dy \
f_Y(y)=\int f(x,y)dx
$$<h3 id="조건부-분포">조건부 분포</h3>
조건부 확률은 $P(A|B)=P(A\cap B)P(B)$이다.
$X, Y$가 이산형 결합일 때 조건부확률은 $P(X=x|Y=y)=\frac{P(x\cap y)}{P(y)}=\frac{f(x,y)}{f(y)}$<h2 id="확률변수의-독립">확률변수의 독립</h2>
</li>
<li>두 사건의 독립 조건: $P(A|B)=P(A), P(B|A)=P(B)$<ul>
<li>확률변수 $A$의 결과는 확률변수 $B$의 결과에 영향을 미치지 않는다.</li>
</ul>
</li>
<li>이변량 함수의 독립: $f(x,y)=f_X(x)\cdot f_Y(y)$<ul>
<li>$P(X\le x, Y\le y)=P(X\le x)\cdot P(Y\le y)$<h2 id="확률변수의-기대값">확률변수의 기대값</h2>
확률변수와 그 확률을 곱한 전체 값을 합하여 구한 값을 기대값이라고 한다. 이는 각 확률변수의 확률을 가중치로 하여 모든 확률변수들에 대해 가중평균을 구한 것과 같으며, 일반적으로 중심척도를 나타내는 평균이라고 한다.</li>
</ul>
</li>
<li>확률질량함수 $f(x)$에 대해 $\mu=E[X]=\sum_Xx\cdot f(x)$</li>
<li>확률밀도함수 $f(x)$에 대해 $\mu=E[X]=\int_\mathcal{R}x\cdot f(x)dx$</li>
<li>확률변수 $X$의 $k$차 적률($k$-th moment)은 다음과 같이 정의된다.
$$
E[X^k]=\begin{cases} \sum_Xx^k\cdot f(x)\ \int_\mathcal{R}x^k\cdot f(x)dx \end{cases}
$$<ul>
<li>$M_X(t)=E[e^{tX}]$<h2 id="확률변수의-분산">확률변수의 분산</h2>
</li>
</ul>
</li>
</ul>
<h2 id="기대값과-분산의-속성">기대값과 분산의 속성</h2>
<h2 id="확률변수의-독립-1">확률변수의 독립</h2>
<p>두 확률변수 $X, Y$가 독립이면 $E[X\cdot Y]=E[X]\cdot E[Y]$
또한 $Var[X+Y]=Var[X]+Var[Y]$</p>
<ul>
<li>독립이 아닌 경우 $+2Cov(X,Y)$</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Self-Attention]]></title>
            <link>https://velog.io/@hyeon-ii/Self-Attention</link>
            <guid>https://velog.io/@hyeon-ii/Self-Attention</guid>
            <pubDate>Wed, 12 Feb 2025 08:58:59 GMT</pubDate>
            <description><![CDATA[<h2 id="attention">Attention</h2>
<ol>
<li><p>Transformer 이전에, Seq2Seq 모델에서도 Attention 자체는 사용되었다. 다만 Seq2Seq에서는 Self-Attention이 아닌 Attention을 이용해서 입력-출력 간 대응되는 단어의 관계를 파악한다. 이를 통해서 각 출력이 어떤 입력 정보를 참고했는지 알 수 있다.</p>
<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/916faa5a-33cc-4f18-82f0-f62c82f3cc89/image.png" alt=""></li>
</ul>
</li>
<li><p>이와 달리 Transformer에 사용된 Self-Attention은 입력과 출력 각 Sequence 내부 값 간의 대응 관계를 파악하기 위해 사용된다.</p>
<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/36c71d27-eaef-47c1-bc3c-2cf455d33bd1/image.png" alt=""></li>
<li>RNN 기반의 Seq2Seq 모델은 Long term dependency를 학습하기 어렵다는 점, 순차적인 연산을 해야하기 때문에 학습이 느리다는 점, 시퀀스를 모두 입력 받은 후에 Decoding이 가능하기 때문에 병렬 연산이 불가능하다는 점 등의 단점이 있다. Transformer는 이러한 단점을 해결하기 위해 RNN을 사용하지 않고 오직 Attention mechanism만으로 입력과 출력 간 의존성을 모델링한다.</li>
</ul>
</li>
</ol>
<h2 id="self-attention의-장점">Self-Attention의 장점</h2>
<p>Recurrent layer, Convoltuional layer와 비교했을 때 Self-Attention layer는 연산 복잡도가 작아서 연산 속도가 빠르다.</p>
<p>이는 문장 길이가 $n$, 입력 단어를 표현하는 벡터 차원이 $d$일 때 $n\ll d$인 경우가 많기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/6559fc45-2159-44d7-9d5b-96e1a6bf1001/image.png" alt=""></p>
<p>위의 표에서 Self-Attention restricted는 문장의 길이가 매우 길 경우 Attention을 적용하는 neighborhood size $r$을 정해주는 것이다.</p>
<h2 id="transformer에서-self-attention">Transformer에서 Self-Attention</h2>
<p>Transformer에는 총 세 가지의 Attention이 있다.</p>
<p>이해를 위해 Encoder 내에서 진행되는 Self-Attention을 기반으로 Attention score를 계산해 보기로 한다.</p>
<p>본 포스팅에서는 Transformer가 아닌 <strong>Transformer에서의 Self-Attention</strong>을 집중적으로 다룬다.</p>
<h3 id="encoder-self-attention">Encoder Self-Attention</h3>
<p>가장 먼저, 입력으로 들어온 $d_{model}$ 차원의 단어(토큰) 벡터들을 $d_k$ 차원으로 선형 변환한다.</p>
<p>이후 Attention을 계산하기 위해 선형 변환된 단어 벡터들의 모음인 $Q, K, V$ 행렬을 만든다. $Q=K=V$로, 동일한 시퀀스 내에 있는 단어들 간의 관계를 계산하기 위해 사용된다.</p>
<p>아래 그림은 &quot;The weather is very nice today&quot; 문장을 임베딩한 후 Attention을 계산하는 모습이며, 특히 &quot;today&quot;가 &quot;nice&quot;와 얼마나 관련이 있는지 구하는(query) 과정이다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/11fed381-480c-4c21-89a0-694f20f6af7f/image.png" alt=""></p>
<p>Query의 각 행(그 단어를 나타내는 벡터), Key의 각 행(그 단어를 나타내는 벡터)을 내적하여 Attention score를 계산하기 시작한다. 계산할 때에는 벡터 별로 연산하는 것이 아닌 $Q$와 $K^T$를 곱하여 계산한다. 이때 additive attention이 아닌 dot-product(multiplicative) attetion을 계산하는 이유는 최적화된 행렬 곱셈 코드를 사용하여 구현하면 더 빠르고 공간 효율적이기 때문이다.</p>
<p>$Q$와 $K^T$를 곱하여 나온 행렬 $QK^T$은 각 단어(토큰) 간의 연관성을 측정하는 행렬로, 한 단어가 다른 단어에 얼마나 주의를 기울여야 하는지, 즉 얼마나 Attention 해야 하는지 결정하는 기준이 된다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/bf343128-05f1-4a96-bbfb-7df15bd85858/image.png" alt=""></p>
<p>연관성을 나타내는 행렬에 Softmax를 적용하면 각 단어가 다른 단어와 얼마나 중요한지 나타내는 <strong>확률</strong> 값이 된다.</p>
<p>지금까지 정리하면 가장 처음 문장을 입력받아 임베딩한 후 $d_k$ 차원으로 변환하여 내적을 계산하고 Softmax를 적용했다. 그런데 만약 $d_k$가 매우 크다면 내적한 값이 $\infin$ 또는$-\infin$으로 발산하고, softmax를 적용했을 때 0이나 1로 수렴하지 않을까?</p>
<p>이 문제를 해결하기 위해 Softmax 함수에 넣기 전에 scaling을 해주어야 한다.</p>
<p>벡터 $Q$와 $K$의 평균이 0이고 분산이 1인 정귝 분포를 따른다고 할 때 $QK^T$의 평균은 0, 분산은 $d_k$이다. 따라서 표준편차를 일정하게 유지하려면 $\sqrt{d_k}$로 나누는 게 적절하다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/219bc7c3-c346-41a8-93b2-e05ba8225a55/image.png" alt=""></p>
<p>출처: <a href="https://www.tensorflow.org/text/tutorials/transformer?hl=ko">https://www.tensorflow.org/text/tutorials/transformer?hl=ko</a></p>
<p>이제 이 확률 값을 초기에 단어들을 나타내던 벡터들의 모음에 곱하면 된다. 이때 사용되는 것이 $V$ 행렬이다.</p>
<p>$$
\text{Attention}(Q,K,V) = \text{softmax}(\frac{QK^T}{\sqrt{d_k}})V
$$</p>
<ul>
<li><strong>Query</strong>: 지금 집중해야 할 단어가 무엇인지 Key에게 하나씩 물어본다.</li>
<li><strong>Key</strong>: 지금 가지고 있는 정보가 Query에 얼마나 도움이 될지 판단한다.</li>
<li><strong>Value</strong>: 계산된 점수를 기반으로 최종적으로 전달할 정보를 조절하여 Attention Score가 결정된다.</li>
</ul>
<hr>
<p>그렇다면 <strong>Multi-Head</strong>란 무엇일까.</p>
<p>Attention을 거치면 Context Vector가 도출된다. 이때 Head가 여러 개라면 명사에 집중한 Context Vector, 형용사에 집중한 Context Vector, 사람에 집중한 Context Vector, 행위에 집중한 Context Vector 등 다양한 맥락을 파악할 수 있다.</p>
<p>본 논문에서는 $d_\text{model}/h=d_k$로 설정한다. 이를 통해 초기에 $d_\text{model}$ 차원이었던 단어 벡터를 단일 Head로 연산하는 것과 동일한 연산량으로 8가지의 맥락을 파악할 수 있다.</p>
<h3 id="decoder-masked-self-attention">Decoder Masked Self-Attention</h3>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/42063793-9cfe-47d9-8e5b-45108bc8d393/image.png" alt="">
위의 그림처럼, Transformer의 Decoder에서는 다음에 이어질 단어의 예측이 연속적으로 이루어진다.</p>
<p>따라서 $i$번째 단어까지 예측을 완료하고 $i+1$번째 단어를 예측할 때 Decoder는 $i+1$을 포함한 이후 단어와의 유사도, attention을 계산하면 안 된다.</p>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/54ed9fdb-8fe8-4cc3-b2d6-448c4d7dabc3/image.png" alt=""></p>
<p>이를 위해 Mask를 적용해야 한다. 구체적인 방법은 대각행렬을 기준으로 오른쪽 위의 position에 $-\inf$를 곱하는 것이다. 그러면 위의 그림처럼 Softmax 함수 적용 시에 0(흰색 cell)이 된다.</p>
<ul>
<li><strong>Query</strong>: 지금까지 본 단어들 중에서 어느 단어에 집중해야 하는지 Key에 묻는다.</li>
</ul>
<h3 id="encoder-decoder-attention">Encoder-Decoder Attention</h3>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/4e22e5c8-7ab3-474c-8a2d-048bc8633c06/image.png" alt=""></p>
<p>가장 처음 입력된 문장은 Encoder를 통해 Context Vector로 고정되었고, Decoder에서 한 단어씩 예측할 때마다 Attention을 거친다. 이는 앞에서 구한 맥락을 기반으로 다음에 나올 단어를 결정하는 과정이다.</p>
<ul>
<li><strong>Query</strong>: 현재까지 예측한 단어가 원래 문장의 어느 부분에 집중해야 하는지 Key에 묻는다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Efficient Estimation of Word Representations in Vector Space]]></title>
            <link>https://velog.io/@hyeon-ii/Efficient-Estimation-of-Word-Representations-in-Vector-Space</link>
            <guid>https://velog.io/@hyeon-ii/Efficient-Estimation-of-Word-Representations-in-Vector-Space</guid>
            <pubDate>Wed, 22 Jan 2025 07:41:50 GMT</pubDate>
            <description><![CDATA[<h2 id="abstraction">Abstraction</h2>
<p>거대한 데이터셋에서 단어를 연속적인 벡터로 표현하기 위한 두가지 새로운 모델 아키텍처를 제안한다. Continuous vector representations의 품질은 단어 유사도 task를 통해 측정한다. 훨씬 낮은 cost로 정확도는 크게 향상되어 16억 개의 단어 datasets에서 단어 벡터를 학습하는 데에 하루도 걸리지 않는다. Vector representation은 syntatic, semantic 유사도를 측정하기 위한 test set에서 state-of-the-art를 보인다.</p>
<h2 id="introduction">Introduction</h2>
<p>본 연구에서 목표는 고품질의 word vector를 학습하는 것이다. 유사한 단어는 vector space에서 가까이에 위치할 뿐만 아니라, 여러 유사도를 가질 수 있을 것이라 기대한다.</p>
<p>놀랍게도, 유사한 단어의 representation는 간단한 구문 규칙성을 발견했다. 간단한 선형 연산을 통해 <strong>vector(&quot;King&quot;)-vector(&quot;Man&quot;)+vector(&quot;Woman&quot;)</strong>의 결과가 <strong>Queen</strong>의 vector 표현과 가까운 것을 확인했다.</p>
<p>본 연구에서 단어 간의 선형 규칙성을 보존하는 새로운 모델 아키텍처를 개발하여 vector 연산의 정확도를 높이고자 한다. Syntactic, semantic 규칙성 모두 측정할 수 있는 test set을 설계했고 많은 규칙들이 높은 정확도로 학습되었다.</p>
<h2 id="model-architecture">Model Architecture</h2>
<p>본 연구에서는 distributed representations of words에 집중하였다.</p>
<ul>
<li><strong>Distributed representation of words</strong>
기존의 one-hot encoding으로 표현된 word vector는 벡터 대부분이 0으로 채워져 메모리 비효율성이 있다. 각 차원이 고유한 의미를 가지고, 단어 간 차이를 명확하게 구분할 수 있으나 의미적으로 비슷한 단어의 관계를 표현하기 어렵다. (서로 다른 one-hot vector를 내적하면 항상 0)
Distributed representation을 통해 여러 차원에서 단어 하나의 의미를 표현할 수 있다. 앞서 본 sparse representation(one-hot)과 달리 연속적인 실수 값으로 단어를 표현할 수 있다. 유사한 의미를 가진 단어는 벡터 공간에서 가까운 위치에 존재하며 고차원의 정보를 적은 크기의 벡터로 나타낼 수 있다.</li>
</ul>
<h2 id="new-log-linear-models">New Log-linear Models</h2>
<p><img src="https://velog.velcdn.com/images/hyeon-ii/post/01ad60df-04c5-4835-80af-4bf116ab84e7/image.png" alt=""></p>
<h3 id="continuous-bag-of-words-model">Continuous Bag-of-Words Model</h3>
<p>feedforward NNLM에서 non-linear hidden layer가 삭제된 구조로, 모든 단어는 같은 position에 평균값으로 계산되어 투영된다.</p>
<ul>
<li><strong>Bag-of-words model</strong>: 단어의 빈도만 고려하여 문단을 수치화하는 것
한 Bag에서 수영장, 수모, 물안경 같은 단어가 자주 등장하면 수영 관련 문서라고 볼 수 있다.<ul>
<li>Context를 통해 중심 단어를 예측하는 방식</li>
<li>CBOW는 연속될 실수값을 사용한다.</li>
</ul>
</li>
</ul>
<ol>
<li>Input<ul>
<li>예측할 단어의 이전 N개, 이후 N개의 단어를 입력으로 사용한다.</li>
<li>Vocabulary size가 V일 때 입력 단어는 $V$ 차원의 one-hot encocing vectors이다.</li>
</ul>
</li>
<li>Projection<ul>
<li>가중치 $W_{[V\times M]}$를 입력 단어 각각 곱하고 평균을 계산하여 projection을 구한다.<ul>
<li>입력 단어는 one-hot 형태이므로 $W$의 $v$ 번째 row를 slicing 한 뒤 평균을 계산하는 것과 같다.</li>
<li>$W$의 각 row를 임베딩 벡터로 사용하게 된다.</li>
</ul>
</li>
<li>각 입력 단어와 $W$를 곱한 값이 Summation(or average) 계산되기 때문에 입력된 단어의 순서는 의미가 없다.</li>
</ul>
</li>
<li>Output<ul>
<li>$M$ 차원의 Projection 값을 가중치 $W&#39;[M\times V]$와 곱하고 softmax 계산을 통해 구하고자 한 중심 단어의 one-hot encoding과 동일한지 구한다.</li>
<li><strong>Loss</strong>: 최종적으로 구하고자 한 중심 단어의 one-hot encoding과 cross entropy를 계산한다.<h3 id="continuous-skip-gram-model">Continuous Skip-gram Model</h3>
중심 단어를 통해 주변 단어를 예측하는 것</li>
</ul>
</li>
</ol>
<ul>
<li>학습 시간이 오래 걸리지만, 전반적으로 CBOW 보다 성능이 더 좋다.</li>
</ul>
<p><a href="https://arxiv.org/pdf/1301.3781v3">논문 링크</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[In-Vehicle Network]]></title>
            <link>https://velog.io/@hyeon-ii/In-Vehicle-Network</link>
            <guid>https://velog.io/@hyeon-ii/In-Vehicle-Network</guid>
            <pubDate>Sat, 07 Dec 2024 13:00:37 GMT</pubDate>
            <description><![CDATA[<p>자동차의 전자화가 계속되면서 차량 내부의 다양한 센서, 액추에이터, ECU 등을 연결하는 네트워크 기술의 중요성이 커지고 있다. <strong>In-Vehicle Network (IVN)</strong>는 차량 내부 통신의 핵심 기술로, 각종 장치가 원활히 통신하도록 한다.</p>
<h2 id="in-vehicle-network-기술">In-Vehicle Network 기술</h2>
<p>차량 내부 통신은 속도와 비용, 용도에 따라 다양한 네트워크 기술을 활용한다.</p>
<h3 id="local-interconnect-network-lin">Local Interconnect Network (LIN)</h3>
<ul>
<li><strong>특징</strong>: 말단의 저속 네트워크 (~20 Kbit/s)<ul>
<li>Single Wire, Single Master(데이터 전송 타이밍을 중앙에서 관리)</li>
</ul>
</li>
<li><strong>장점</strong>: 단순한 구조와 저비용</li>
<li><strong>용도</strong>: 창문 제어, 조명 제어 등 자동차 움직임과 상관없는 비핵심 장치<h3 id="controller-area-network-can">Controller Area Network (CAN)</h3>
</li>
<li><strong>특징</strong>: 멀티마스터 기반 고속 네트워크 (~1 Mbit/s)<ul>
<li>Master: Gateway</li>
<li>CAN에 적용된 Dual Wires는 무게에 영향을 준다</li>
</ul>
</li>
<li><strong>장점</strong>: 안정적인 실시간 성능과 외부 노이즈에 강한 내성<ul>
<li>데이터 전달에 시간이 얼마나 소요되는지 계산이 가능하다.</li>
<li>하나의 Node는 반드시 전송한다.</li>
</ul>
</li>
<li><strong>용도</strong>: 차량 제어 시스템의 표준 네트워크<h3 id="flexray">FlexRay</h3>
</li>
<li><strong>특징</strong>: CAN보다 고속 (~10 Mbit/s)<ul>
<li>2006년 BMW X5에 처음 사용되고 2008년 BMW 7 시리즈에 본격 사용</li>
<li>전세계적으로 활발하게 사용되지 않고 Automotive Ethernet으로 대체되는 추세<ul>
<li>Automotive Ethernet은 자동차에 최적은 아니지만 속도가 100Mbit/s에 이른다.</li>
</ul>
</li>
</ul>
</li>
<li><strong>용도</strong>: 고속 제어 응용 (섀시 제어, 에어백 시스템 등)<h3 id="media-oriented-systems-transport-most">Media Oriented Systems Transport (MOST)</h3>
</li>
<li><strong>특징</strong>: 멀티미디어 데이터 (infortainment) 전송 전용 네트워크<ul>
<li>Automotive Ethernet으로 대체되는 추세</li>
</ul>
</li>
<li><strong>용도</strong>: 차량의 오디오 및 비디오 데이터 전송<h3 id="automotive-ethernet">Automotive Ethernet</h3>
</li>
<li><strong>특징</strong>: 고속 네트워크 (~100 Mbit/s)<ul>
<li>기존 이더넷을 차량용으로 개선한 것으로, 2 twisted pairs(와이어 4개)에서 Single twisted pair(와이어 2개)로 변형되어 무게가 절감되었다.</li>
</ul>
</li>
<li><strong>장점</strong>: 기속 Ethernet 기술의 차량 적용 버전으로, 대용량 데이터를 처리할 수 있다.</li>
<li><strong>단점</strong>: 대역폭은 크지만 노이즈에 취약하고 예측 가능성이 낮다.<ul>
<li>모든 Node가 데이터 전송에 실패할 수 있다.<h3 id="can-vs-ethernet">CAN vs Ethernet</h3>
CAN | Ethernet</li>
</ul>
</li>
<li>|-
Topic-based | Address-based
Node에 주소가 없다. | 각 Node는 MAC Address를 갖는다.
각 Message는 식별자(topic)를 갖는다. | Packet은 목적지 주소를 가지고 있다.
모든 Message는 모든 Node에 전달된다. | Packet은 목적한 Node에 전달된다.
Deterministic Message Arbitration | Non-deterministic random backoff<h2 id="can의-작동-원리와-구조">CAN의 작동 원리와 구조</h2>
<h3 id="can의-기본-개념">CAN의 기본 개념</h3>
</li>
<li>1980년대 BOSCH에서 개발한 serial 통신 기술<ul>
<li>한 시점에 한 bit만 전송 가능한 직렬 통신</li>
</ul>
</li>
<li>멀티마스터 &amp; 멀티캐스팅(모든 노드 간 통신)</li>
<li>와이어 길이에 따라 최대 1 Mbit/s 대역폭<ul>
<li>1초에 1M개의 bit를 구분하는 민감성(bandwidth)를 가져야 한다.</li>
<li>100m, 500kbit/s bus가 가장 많이 사용된다.</li>
</ul>
</li>
<li>외부 EMI 노이즈에 강하다.</li>
<li>실시간 성능(예측 가능성)이 좋다.</li>
<li>노드에는 주소가 없고 메시지에 ID(topic)가 있다.</li>
<li>Pub/Sub 통신 구조를 지원한다.<ul>
<li>CAN 이전에는 중앙 관리 없는 Point-to-Point 통신으로, Bus Arbitration이 필요 없었다.</li>
<li>CAN은 Bus 기반 통신으로, 중앙 관리가 있고 Bus Arbitration이 필요하다.<h3 id="can-메시지-포맷">CAN 메시지 포맷</h3>
</li>
</ul>
</li>
<li>CAN Node Configuration<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/ba902a12-ba15-45a7-a33e-76c85df6aa0d/image.png" alt=""></li>
<li>CAN Node: CAN 통신을 수행하는 단위</li>
<li>Microcontroller (MCU): 시스템의 중심으로, 데이터를 처리하고 CAN 통신을 관리한다.</li>
<li>CAN Controller: 데이터를 CAN 통신 형식에 맞게 송신하거나 수신한다.<ul>
<li>MCU가 CAN 통신을 이해하도록 돕는 중간 관리자</li>
</ul>
</li>
<li>CAN Transceiver<ul>
<li>TX(송신): CAN Controller에서 나온 데이터를 물리적인 CAN 신호(CANH 1, CANL 0)로 변환</li>
<li>RX(수신): 물리적인 CAN 신호를 다시 데이터로 변환하여 CAN Controller에 전달</li>
<li>CAN Controller와 실제 물리적인 네트워크 사이의 실시간 통역사</li>
<li>CAN Controller에서 데이터가 나오면 CAN Transceiver가 이를 변환하여 CAN H와 CAN L을 통해 내보낸다. 이때 수신 측에서는 CAN Transceiver가 CAN H와 CAN L의 신호를 다시 디지털 데이터로 변환한다.</li>
</ul>
</li>
</ul>
</li>
<li>CAN Wiring<ul>
<li>CAN H와 CAN L은 항상 쌍으로 동작하기 때문에 데이터의 안정성이 향상된다.<ul>
<li>동일한 데이터가 두 선에 반대로 전달된다.</li>
</ul>
</li>
<li>CAN H와 CAN L은 Differential Signaling을 사용한다.<ul>
<li>입력된 값이 튀면 H와 L 모두 영향을 받으므로 difference는 유지된다.</li>
<li>두 voltage의 차이가 없으면 0, 전압 차이가 있으면 1</li>
</ul>
</li>
</ul>
</li>
<li>CAN Message Format<ul>
<li><strong>메시지 ID (Arbitration Field)</strong>: 우선순위를 결정하는 11 Bits</li>
<li><strong>Data</strong>: 최대 8 Bytes</li>
<li><strong>Signal</strong>: 메시지에 포함된 하나의 값으로 factor와 offset고려가 필요하다.</li>
</ul>
</li>
<li>CAN Bus Arbitration<ul>
<li>메시지 충돌 시 ID 우선순위에 따라 전송한다.</li>
<li>ID를 나타내는 11 bits에 1을 보냈는데 다른 노드에서 0이 실리면 해당 노드는 전송을 포기한다.<ul>
<li>Node가 전송을 몇번 실패할 것인지 수학적으로 계산 가능하다.</li>
</ul>
</li>
<li>11 bits 모두 0이면 무조건 전송을 성공한다.<ul>
<li>작은 메시지 ID이면 높은 우선순위를 가진다.<h3 id="can-standards">CAN Standards</h3>
</li>
</ul>
</li>
</ul>
</li>
<li>CAN 2.0A: 현재 사용하는 포맷<ul>
<li>11-bit ID로, 전송 가능한 메시지 종류는 2048개</li>
</ul>
</li>
<li>CAN 2.0B<ul>
<li>29-bit ID로 전송 가능한 메시지 종류가 매우 많다.</li>
<li>트럭이나 버스에서 사용한다.</li>
</ul>
</li>
<li>CAN FD 1.0<ul>
<li>메시지 당 64 Bytes의 데이터를 지원한다. (현재의 8배)</li>
<li>스펙상 8 Mbit/s를 지원하지만 안정되지 않아 실제 2~5 Mbit/s의 성능을 가진다.<h3 id="can-message--signal-example">CAN Message &amp; Signal Example</h3>
</li>
</ul>
</li>
<li>Steering torque 시그널<ul>
<li>Name: CF_Mdps_StrTq</li>
<li>Length: 12 Bits<ul>
<li>4096개의 정수 표현 가능</li>
</ul>
</li>
<li>Byte Order: Intel(Little Endian)<ul>
<li><img src="https://velog.velcdn.com/images/hyeon-ii/post/5f0d961c-2547-4f12-a3ea-a1a558d8a6dc/image.png" alt=""></li>
</ul>
</li>
<li>Factor: 0.01<ul>
<li>$\text{입력값}\times\text{Factor}=0\sim40.95$</li>
</ul>
</li>
<li>Offset: -20.48<ul>
<li>$\text{입력값}\times\text{Factor}+\text{Offset}=-20.48\sim20.47$<h2 id="vector">Vector</h2>
<h3 id="vector-1">Vector</h3>
</li>
</ul>
</li>
</ul>
</li>
<li>CAN 설계 및 분석을 전문으로 하는 솔루션 기업</li>
<li>IVN 구현과 개발 과정에서 널리 사용되는 표준 도구를 제공한다.<ul>
<li>CANoe(시스템 설계 및 시뮬레이션), CANalyzer(네트워크 분석), CANape(ECU 소프트웨어 개발 및 테스트) 등</li>
<li>ECU에 설치하는 용도가 아닌 테스트, 분석을 위한 tools<h3 id="candb">CANdb</h3>
</li>
</ul>
</li>
<li>Vector에서 개발한 CAN 메시지 구조 정의 파일 포맷<ul>
<li>메시지를 정리한 문서</li>
</ul>
</li>
<li>OEM별로 고유한 CANDB를 정의해서 사용한다.<ul>
<li>노출되면 해킹에 취약하기 때문에 극비이나 역공학으로 많이 노출된다.</li>
</ul>
</li>
<li>CANdb++는 CANdb 파일 편집을 위한 소프트웨어로, CANdb를 시각화하는 데 쓰인다.<ul>
<li>68 bits의 신호 표시<h3 id="can-access-programming-language-capl">CAN Access Programming Language (CAPL)</h3>
</li>
</ul>
</li>
<li>CAN 프로그래밍을 위한 이벤트 기반 프로그래밍 언어</li>
<li>C 언어와 유사하지만 사용하기 쉽다.</li>
<li>ECU 테스트 코드 작성에 사용된다.<ul>
<li>양산 코드는 C언어이다.</li>
</ul>
</li>
<li>Vector Tools에서 지원한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[AUTOSAR]]></title>
            <link>https://velog.io/@hyeon-ii/AUTOSAR</link>
            <guid>https://velog.io/@hyeon-ii/AUTOSAR</guid>
            <pubDate>Sat, 07 Dec 2024 06:05:13 GMT</pubDate>
            <description><![CDATA[<h2 id="autosar">AUTOSAR</h2>
<h3 id="motivation">Motivation</h3>
<ul>
<li>Moto: Standards로 협력하고, 구현으로 경쟁한다.</li>
<li>ECU의 표준이 되는 architecture로, 자동차 소프트웨어의 가장 중요한 표준</li>
<li>Layered Architecture, abstractions, reusability, portability가 강조된다.</li>
<li>BOSCH, BMW, MINI 등 9개의 core partners와 56개의 premium partners, 46개의 development partners로 구성된다.</li>
<li>전세계에 걸쳐 AUTOSAR software provider가 존재한다.<ul>
<li>Vector, ETAS, Hyundai Autron, Mento Graphics 등<h3 id="platform">Platform</h3>
</li>
</ul>
</li>
<li><strong>Classic Platform</strong><ul>
<li>Real-time의 OSEK 기반</li>
<li>ROM에서 코드를 직접 실행한다.</li>
<li>Memory Protection Unit에 의해 모든 applications는 주소 공간이 동일하다.</li>
<li>CAN, FlexRay 같은 Signal-based communication에 적합하다.</li>
<li>Specification(표준)에 대한 플랫폼</li>
</ul>
</li>
<li><strong>Adaptive Platform</strong><ul>
<li>Connectivity, 자율주행, Sharing/Mobility Service, Electric Vehicle</li>
<li>POSIX 기반</li>
<li>App은 영구 메모리에서 RAM으로 로드된다.</li>
<li>각 application은 Memory Management Unit에 의해 별도의 virtual address를 가진다.</li>
<li>Eternet 기반의 Service-oriented communication</li>
<li>다중 스케줄링 기법</li>
<li>Specification(표준)과 Implementation</li>
</ul>
</li>
</ul>
<h2 id="autosar의-architecture">AUTOSAR의 Architecture</h2>
<h3 id="layered-architecture">Layered Architecture</h3>
<p>이 아키텍처의 상단은 Component-based Architecture로 이루어진다.
<img src="https://velog.velcdn.com/images/hyeon-ii/post/973c344b-1631-4006-bded-608682b9f9ab/image.png" alt=""></p>
<ol>
<li><strong>Application Layer</strong><ul>
<li>Application Software (Control Algorithms)</li>
<li>차량 기능을 구현한다.</li>
</ul>
</li>
<li><strong>Runtime Environment</strong> (Interface)<ul>
<li>ECU에 맞추어 각 계층의 통합을 관리한다.</li>
<li>소프트웨어 컴포넌트 간 통신을 ECU에서 실행 가능한 형태로 제공한다.</li>
</ul>
</li>
<li><strong>Basic Software</strong><ul>
<li>하드웨어의 독립성을 보장하며 인프라 및 서비스 기능을 제공한다.</li>
<li>RTE와 상호작용하여 소프트웨어 간의 통신을 지원한다.</li>
<li>Services Layer: OS</li>
<li>ECU Abstraction Layer</li>
<li><strong>Microcontroller Abstraction Layer (MCAL)</strong><ul>
<li>하드웨어 장치에 접근하기 위한 드라이버 계층으로, 상위 소프트웨어는 하드웨어 세부사항을 신경 쓰지 않고 동작할 수 있다.</li>
<li>기본적인 통신을 위한 표준화된 디바이스 드라이버</li>
<li>개발 표준 문서로는 SRS(requirement)와 SWS(specification)가 있다.</li>
</ul>
</li>
<li>Complex Drivers<ul>
<li>ECU에서 하드웨어적으로 직접 지원되지 않는 장치를 제어하기 위한 장치</li>
<li>비표준 디바이스를 위한 OEM 자체 드라이버로 MCU와 무관하다.</li>
<li>점화 장치, 연료 분사 장치를 제어한다.</li>
<li>표준이 아니므로 이식성이 제한된다.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Microcontroller</strong> (Hardware)</li>
</ol>
<h3 id="주요-개념">주요 개념</h3>
<ul>
<li><strong>SW-Components (SW-C)</strong><ul>
<li>소프트웨어 design, packaging, deployment에서 기능 단위 (실행 가능한 단위)</li>
<li>Runnables(함수)의 집합이며, 각각은 주기가 있다.</li>
<li>통신을 위해 포트(Requirement, Provide)로 이루어진다.</li>
</ul>
</li>
<li><strong>Virtual Functional Bus (VFB)</strong><ul>
<li>통신 메커니즘, 기본 SW의 인터페이스</li>
<li>RTE 및 BSW에서 제공하는 통합 ECU 통신 메커니즘</li>
</ul>
</li>
<li><strong>Mapping</strong><ul>
<li>RTE와 기본 SW의 구성 및 생성</li>
</ul>
</li>
<li><strong>Runtime Environment (RTE)</strong><ul>
<li>ECU에 VFB를 실제 구현</li>
</ul>
</li>
<li><strong>Basic Software (BSW)</strong><ul>
<li>ECU의 infra 기능<h3 id="동작-원리">동작 원리</h3>
</li>
</ul>
</li>
<li>Client-Server<ul>
<li>Client에서 통신을 시작하고 server에 service를 요청한다.</li>
<li>Server는 client로부터 요청을 받아 service를 전달한다.</li>
</ul>
</li>
<li>Sender-Receiver<ul>
<li>비동기식</li>
<li>Sender는 receiver로부터 응답 받기를 기다리지 않는다.</li>
<li>communication 인프라는 정보를 전달해야 한다.</li>
</ul>
</li>
</ul>
<h2 id="autosar-적용">AUTOSAR 적용</h2>
<h3 id="tool-based-work-flow">Tool-based Work Flow</h3>
<ul>
<li>AUTOSAR BSW configuration tool을 사용하면 ARXML이 도출된다.<ul>
<li><strong>ARXML</strong>: ECU Configuration Description(XML)</li>
</ul>
</li>
<li>ARXML을 이용하여 RTE, OS, Communication Services, MCAL Generator는 필요한 함수들을 자동으로 생성한다.</li>
<li>RTE API<ul>
<li>Port $P$로 Data $o$를 보내는 함수: <code>Std_ReturnType Rte_Send_p_o</code></li>
<li><code>Rte_Receive_p_o</code></li>
<li><code>Rte_Call_p_o</code><h3 id="runnable과-task-매핑">Runnable과 Task 매핑</h3>
</li>
</ul>
</li>
<li>Between SW-Cs<ul>
<li>SW-C는 runnables로 이루어진다.</li>
<li>Runnables는 Send와 Receive로 소통한다.</li>
<li>각 component의 runnables 간 data가 흐를 때 속도가 매우 중요하다.<ul>
<li>Flow가 역방향으로 진행되면 다음 runnable에서는 한 주기 더 기다려야하므로 데이터가 흐르지 않는 문제가 있다.</li>
<li>Task 안의 runnables는 Data Flow에 맞게 순방향으로 배치해야 한다.<h3 id="data-age-vs-reaction-time">Data Age vs. Reaction Time</h3>
</li>
</ul>
</li>
</ul>
</li>
<li><strong>Data age timing constraint</strong><ul>
<li>데이터가 입력되고 actuation 할 때 시간이 얼마나 지났는지 나타낸다.</li>
<li>ex) LKAS에서 오래된 입력 데이터를 기준으로 조향하면 횡방향 제어에 문제가 생긴다.</li>
</ul>
</li>
<li><strong>Reaction time contraint</strong><ul>
<li>반응 시간</li>
<li>ex) Airbag system에서 충돌에 대한 reaction이 늦어지면 큰 사고로 이어진다.</li>
</ul>
</li>
<li><strong>Sampling과 Delay</strong><ul>
<li>Undersampling: 짧은 주기 task에서 긴 주기 task로 데이터가 흐르는 것<ul>
<li>ex) Sensing 하고 주기가 맞지 않아 사용되지 않는 데이터가 발생한다.</li>
</ul>
</li>
<li>Oversampling: 긴 주기 task에서 짧은 주기 task로 데이터가 흐르는 것<ul>
<li>ex) 사용해야하는 데이터가 새로 입력되지 않아 이전 데이터를 한 차례 더 사용한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>