<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>천천히 꾸준히 조용히</title>
    <link>https://13months.tistory.com/</link>
    <description>천천히 꾸준히 조용히..
i3months 블로그</description>
    <language>ko</language>
    <pubDate>Thu, 2 Jul 2026 11:10:45 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>i3months</managingEditor>
    <image>
      <title>천천히 꾸준히 조용히</title>
      <url>https://tistory1.daumcdn.net/tistory/4775559/attach/1d8003f60bce4c3d85d7c4c06bf1ab80</url>
      <link>https://13months.tistory.com</link>
    </image>
    <item>
      <title>[Data Science] Data Mining</title>
      <link>https://13months.tistory.com/847</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Association Rule Mining&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A를 구매한 사람은 B도 같이 구매하더라~ 같은 패턴을 찾는게 목표&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;itemset : 물건들의 집합&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;support : 아이템셋이 전체 거래 중 몇 비율에서 등장하는지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQiJ6z/dJMcajbqq0P/6mYXbNPudLKsKTrtOLirMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQiJ6z/dJMcajbqq0P/6mYXbNPudLKsKTrtOLirMK/img.png&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;104&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.8492%; margin-right: 10px;&quot; data-widthpercent=&quot;53.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQiJ6z/dJMcajbqq0P/6mYXbNPudLKsKTrtOLirMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQiJ6z%2FdJMcajbqq0P%2F6mYXbNPudLKsKTrtOLirMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/05dS3/dJMcajbqq0U/0dOvfWih55aN4aWtbqBwQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/05dS3/dJMcajbqq0U/0dOvfWih55aN4aWtbqBwQk/img.png&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;130&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.988%;&quot; data-widthpercent=&quot;46.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/05dS3/dJMcajbqq0U/0dOvfWih55aN4aWtbqBwQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F05dS3%2FdJMcajbqq0U%2F0dOvfWih55aN4aWtbqBwQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나이브하게 생각하면 모든 가능한 연관 규칙을 찾고 support값과 confidence값을 계산해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이렇게 하면 규칙 수가 너무 많아져서 느림 -&amp;gt; Apriori 알고리즘 사용&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 지지도인 minsup과 최소 신뢰도인 minconf를 지정하고 비교함 (각각 직접 설정하는 파라미터)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;support &amp;gt;= minsup , confidence &amp;gt;= minconf (흔한 패턴만 보겠다 + 믿을 만한 규칙만 보겠다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 itemset이 &lt;b&gt;frequent 하다면 (support &amp;gt;= minsup 이면)&lt;/b&gt; 그 모든 부분집합도 frequent 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 어떤 itemset이 frequent하지 않으면 그걸 포함하는 큰 itemset도 frequent하지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 특정 item이 탈락하는 순간 그 item을 포함하는 itemset을 계산하지 않고 한 번에 쳐낼 수 있다. (prunning)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Apriori&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크기가 k인 frequent itemset을 Fk라고 부른다. 작은 것 부터 한 층씩 올라감.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fk가 공집합이면 종료하고, 공집합이 아니면 k+1 후 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F1을 계산할 때는 물건이 n개면 후보가 n개 뿐이니 각각 support를 세고 frequent한 것만 남긴다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k가 1보다 클 때는 두 단계로 나눠서 계산함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 후보 집합 Ck를 만든다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Ck의 각 원소 support를 세서 frequent 한 것만 Fk에 남긴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 계산 시 모든 k 조합을 후보로 넣으면 계산량이 너무 많으니 이미 구한 Fk-1을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{a1, a2 ... ak} 가 frequent 한 k-아이템셋이라면, {a1, a2 ... ak-1} 과 {a1, a2, ... ak-2, ak} 는 Fk-1에 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 두 아이템셋의 prefix는 {a1, a2, ... ak-2} 로 똑같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 모든 아이템에 순서를 정하고 Fk-1을 prefix로 정렬한 후 prefix가 같은 것 끼리 그룹화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 그룹 안에서 위의 두 아이템셋의 pair 마다 합친 결과를 Ck에 추가하는 방식을 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 앞부분 똑같고 마지막 항목만 다른 것들을 추가하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 C3를 만들 때는 3-2=1로 맨 앞 1글자가 같은걸 대상으로 그룹으로 묶는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 그룹 안에서 서로 다른 2개를 짝지어서 합치는 것. 후보가 3개면 3C2로 3개가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;F&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;}} 에서 C3는 abc abd acd 가 나옴&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;그리고 abc abd acd 에서 ab ac bc ad bd cd 가 모두 F2에 있는지 확인하는데, bd는 F2에 없으니 prunning 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prefix가 다르면 어차피 합쳐봐야 의미 없으니 계산하지 않는다. 이러면 후보 수가 확 줄어듦.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 k&amp;gt;=2 인 빈발 아이템셋 I를 하나 고르고 겹치지 않는 두 조각 I1 I2로 나눈다. (I1 U I2 = I)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 I1 -&amp;gt; I2 가 후보 규칙으로 정해짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C0bdO/dJMcaci7aop/kSGFrH9KZiLDgiKtNCaUUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C0bdO/dJMcaci7aop/kSGFrH9KZiLDgiKtNCaUUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C0bdO/dJMcaci7aop/kSGFrH9KZiLDgiKtNCaUUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC0bdO%2FdJMcaci7aop%2FkSGFrH9KZiLDgiKtNCaUUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;312&quot; height=&quot;81&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 후보 규칙의 confidence를 계산해서 minconf 이상인 것만 보고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 분자와 분모는 1단계에서 모두 구해뒀으니 규칙 생성 단계에서는 계산만 하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I가 frequent 하니까 support는 신경쓰지 않아도 되고 confidence만 검사함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 쪽이 통째로 비는 두 경우를 제외하면 I 하나당 2^k - 2개의 후보 규칙이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 계산해서 confidence 값이 mincof 이하인걸 잘라내면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rBb4i/dJMcaci7aKi/RdcPvK6W839XmrxUE5vD9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rBb4i/dJMcaci7aKi/RdcPvK6W839XmrxUE5vD9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rBb4i/dJMcaci7aKi/RdcPvK6W839XmrxUE5vD9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrBb4i%2FdJMcaci7aKi%2FRdcPvK6W839XmrxUE5vD9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;72&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽이 클수록 confidence가 높다 - 어차피 분자는 같고 더 작은 집합이 더 흔하니까..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 left-contains 한다고 부름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 규칙을 Lattice로 두고 왼쪽이 큰 규칙부터 top-down으로 검사한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 규칙이 minconf 에 도달하지 못하면 left-contains하는 모든 아래쪽 규칙도 자동으로 미달이니 confidence를 계산하지 않고 쳐낼 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;PCA meets SVD&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 d개의 특징을 가질 때, 그 특징들이 서로 상관되어 있는 경우 진짜 중요한 방향은 몇 개 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA는 데이터가 가장 크게 퍼지는 직교 방향을 찾고 새 좌표축으로 삼는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 상위 n개 축만 남기고 나머지를 버리니 d차원을 k차원으로 줄이면서 정보를 최대한 보존할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 PCA는 공분산 행렬을 만들고 고유값 분해를 하는 방법이지만 실무에서는 PCA 대신 SVD를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공분산 + 고유값분해 대신 SVD로 PCA를 수행함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬의 대각합과 고유값의 합은 동일함. 분산은 사라지지 않고 PC로 재분배되기 때문&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uxag2/dJMcajoXuIs/C534gCPApCdORsUnizxCk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uxag2/dJMcajoXuIs/C534gCPApCdORsUnizxCk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uxag2/dJMcajoXuIs/C534gCPApCdORsUnizxCk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuxag2%2FdJMcajoXuIs%2FC534gCPApCdORsUnizxCk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;598&quot; height=&quot;274&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SVD는 데이터 X를 회전(V^T) -&amp;gt; 축 별로 늘리기(S) -&amp;gt; 회전(U) 세 동작으로 분해해서 다룬다. (행렬 하나를 셋으로 쪼개서 다룸)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V는 방향, S는 그 방향으로 데이터가 퍼진 정도를 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n개의 데이터(행), d개의 특징(열), d &amp;lt; n 가정&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S는 대각행렬&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;U * U^T = I&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V * V^T = I&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PC 값은 그 자체가 분산이니 제곱하지 않아도 됨. 특이값을 줬을 때만 제곱해서 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복원이 정확하려면 버리는 방향의 분산이 0이여야 함. k=n으로 줄일때 버려지는게 0이 아니면 부정확하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjOffX/dJMcag6UUWJ/6lWuFS1Txm3rvJvdpFMFuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjOffX/dJMcag6UUWJ/6lWuFS1Txm3rvJvdpFMFuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjOffX/dJMcag6UUWJ/6lWuFS1Txm3rvJvdpFMFuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjOffX%2FdJMcag6UUWJ%2F6lWuFS1Txm3rvJvdpFMFuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;250&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 특징이 있는 데이터를 점으로 찍으면 한쪽으로 길쭉하게 펴진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 많이 퍼진 한 방향이 PC1이고, 수직이면서 그 다음으로 퍼진 방향은 PC2이다. PCA는 데이터에 맞춰 좌표축을 다시 그어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 PC1 방향으로 길고 PC2 방향으로는 거의 펴지지 않았다. 그러니 각 점을 PC1 위에서 어디쯤인지로 표현해도 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 d차원을 k차원으로 줄이는 테크닉이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, V의 열은 PC 방향 그 자체이고 S의 특이값은 각 화살표 방향으로 데이터가 퍼진 크기를 의미한다 - PC1은 크고 PC2는 작다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특이값이 큰 것 부터 정렬되어 있으니 앞에서 k개만 챙기면 좋은거만 가져가는 셈.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 점이 PC1 위에서 어디쯤 있는지 알기 위해서는 방향선에 수직으로 점의 그림자를 떨어뜨리면 된다. (투영)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내적으로 계산하면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA는 데이터가 가장 퍼진 방향을 찾고 각 점을 그 방향에 투영해서 새 좌표를 얻고 그 방향 퍼짐의 크기를 계산하는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA 공식 : Z = XV 데이터를 PC 방향에 투영해서 줄인 결과&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Z = XV = (USV^T)V = US(V^TV) = US&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PC의 분산과 방향은 따로 구해야함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V의 열은 X^TX의 고유벡터이고 U의 열은 XX^T의 고유벡터이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Clustering&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답 라벨 없이 비슷한 점끼리 묶는 테크닉으로 같은 그룹은 가깝게 다른 그룹은 멀게 매핑한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터 개수 k를 미리 정해두면 n개의 점을 k개의 클러스터로 나누되 이 값을 최소화함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oWQc4/dJMcaiRcvd5/6RKXV30i4SSjGco5zClDl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oWQc4/dJMcaiRcvd5/6RKXV30i4SSjGco5zClDl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oWQc4/dJMcaiRcvd5/6RKXV30i4SSjGco5zClDl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoWQc4%2FdJMcaiRcvd5%2F6RKXV30i4SSjGco5zClDl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;100&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적해는 가능한 모든 경우를 다 따져봐야하는데 이러면 시간이 너무 오래 걸리니 휴리스틱인 &lt;b&gt;K-Means&lt;/b&gt;를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. k를 정하고 중심 k개를 아무렇게나 찍는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 각 점을 가장 가까운 중심의 색으로 칠하고, 각 색의 중심을 점들의 평균 위치로 옮긴다. (centroid)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 어떤 점도 색이 바뀌지않으면 끝&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;global optimum이 아니라 local optimum에 수렴함. 처음 중심을 어디에 찍는지에 따라 결과가 달라진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까, 처음부터 모든 점이 특정 클러스터에 속하는거고 클러스터의 중심을 바꿔가면서 조작하는 것&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hierarchical Agglomerative&lt;/b&gt;는 기존 K-Means와 정반대로 아래에서 위로 쌓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 모든 점이 각자 클러스터고, 그 중 가장 가까운 두 클러스터를 합치는걸 가장 큰 클러스터가 남을 때 까지 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Single Linkage : 두 클러스터에서 가장 가까운 점 한 쌍의 거리&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Complete Linkage : 두 클러스터에서 가장 먼 점 한 쌍의 거리&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Average Linkage : 모든 점 쌍 거리의 평균&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 기준을 정해야 두 클러스터 사이의 거리를 측정할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘의 결과는 하나의 큰 클러스터가 아니라 합쳐진 전체 과정이다. (덴드로그램)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 덴드로그램 안에는 모든 단계의 클러스터링이 들어있으니 나무를 끝까지 키운 뒤 원하는 높이에서 자르면 클러스터의 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctBloa/dJMcab5COUm/TS8TfsNVFzxRHuIHOFX7gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctBloa/dJMcab5COUm/TS8TfsNVFzxRHuIHOFX7gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctBloa/dJMcab5COUm/TS8TfsNVFzxRHuIHOFX7gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctBloa%2FdJMcab5COUm%2FTS8TfsNVFzxRHuIHOFX7gK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;221&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터링을 돌렸는데 이게 잘 된건지를 측정하려면 Silhouette Score를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점 X 하나에 대해서 두 거리를 측정함. (내 무리랑은 가깝고 남의 무리랑은 멀어야 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. X에서 자기 클러스터 안의 다른 점들까지의 평균 거리 -&amp;gt; 작을수록 좋다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B. X에서 가장 가까운 다른 클러스터의 점들까지의 평균 거리 -&amp;gt; 클수록 좋다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ExHi2/dJMcaiwU4a3/txTdG1itztdh48W3TihYKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ExHi2/dJMcaiwU4a3/txTdG1itztdh48W3TihYKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ExHi2/dJMcaiwU4a3/txTdG1itztdh48W3TihYKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FExHi2%2FdJMcaiwU4a3%2FtxTdG1itztdh48W3TihYKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;224&quot; height=&quot;101&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A가 작고 B는 크면 S가 1에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A랑 B가 유사하면 S가 0에 가깝고 경계에 애매하게 걸친 점이 됨&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A가 더 크면 S가 음수가 되고 잘못 묶였다고 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 점의 S값을 평균 내면 클러스터링 점수가 된다 - k를 설정할 때 사용함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균 실루엣이 가장 높은 k를 선택한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DBSCAN&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터를 점이 모인 지역으로 보고, 떨어진 부분은 노이즈로 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잡음점 주변은 sparse하고 같은 클러스터의 두 점은 dense한 지역만 밟아서 오갈 수 있어야 함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K-Means처럼 덩어리만 잘 찾는게 아니라 구불구불한 모양도 밀도만 이어지면 하나의 클러스터로 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 k를 미리 정하지 않아도 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xoIv2/dJMcah5TfQR/bDlqopvzIliQubUk68Ucdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xoIv2/dJMcah5TfQR/bDlqopvzIliQubUk68Ucdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xoIv2/dJMcah5TfQR/bDlqopvzIliQubUk68Ucdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxoIv2%2FdJMcah5TfQR%2FbDlqopvzIliQubUk68Ucdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;483&quot; height=&quot;307&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엡실론 값은 거리 문턱값이고 MinPts는 정수 상수를 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점 p를 중심으로 반경이 엡실론인 공은 p의 이웃 영역이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 구역 안에 점이 MinPts개 이상 들어있는 점은 핵심점으로 DBSCAN의 가장 중요한 부분이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초록색 점 p는 핵심점이고 보라색 점은 핵심이 될 수는 없으니 경계점이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회색 점은 외딴 곳에 있으니 노이즈.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터는 두 가지 단계를 통해 만들어짐&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 핵심점끼리 묶기 - p를 구간 안의 점들과 선으로 연결하고 이어진 덩어리 하나하나를 클러스터로 본다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 경계점 배정 - 비핵심점 p는 모든 핵심점의 클러스터에 추가되니 여러 클러스터에 동시에 속할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 중심을 어디에 찍는지에 따라서 결과가 달라지는 K-Means와 다르게 결과가 유일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Single Linkage 덴드로그램이 있을 때 minPts가 1이면 모든 점이 핵심점이니 덴드로그램을 엡실론에서 자른것과 같음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 클러스터 안에 핵심점이 여러개 있을 수 있고, 경계점은 이웃이 부족해 핵심점은 아니지만 어떤 핵심점의 원 안에 들어가는 경우를 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Neural Network&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 데이터를 받아서 쓸모 있는 출력으로 바꾸는 기계이고, 그 변환 규칙이 학습 가능한 파라미터로 정해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Encoder&lt;/b&gt; - 큰 입력 데이터를 하나의 대표 벡터로 압축한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Head&lt;/b&gt; - 대표 벡터로 실제로 풀고 싶은 문제를 풀어서 출력을 만들어낸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w2Sbi/dJMcaf1fdZW/K64Gl5hZhQ6IQv6eXhaBqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w2Sbi/dJMcaf1fdZW/K64Gl5hZhQ6IQv6eXhaBqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w2Sbi/dJMcaf1fdZW/K64Gl5hZhQ6IQv6eXhaBqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw2Sbi%2FdJMcaf1fdZW%2FK64Gl5hZhQ6IQv6eXhaBqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;188&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blTVxu/dJMcaffVNCk/hnUfAxsaCwrHDtqGwalek1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blTVxu/dJMcaffVNCk/hnUfAxsaCwrHDtqGwalek1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blTVxu/dJMcaffVNCk/hnUfAxsaCwrHDtqGwalek1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblTVxu%2FdJMcaffVNCk%2FhnUfAxsaCwrHDtqGwalek1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;265&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7LHbp/dJMcaijnrWf/niTqk65gRuKDccRrOkkBy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7LHbp/dJMcaijnrWf/niTqk65gRuKDccRrOkkBy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7LHbp/dJMcaijnrWf/niTqk65gRuKDccRrOkkBy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7LHbp%2FdJMcaijnrWf%2FniTqk65gRuKDccRrOkkBy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;216&quot; height=&quot;61&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 입력 뉴런이 모든 출력 뉴런과 연결되니 fully-connected 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 뉴런 하나하나는 W의 한 행과 x의 내적으로 표현되고, 그림의 선 하나가 가중치 하나를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활성화 함수로 가중합 결과를 비선형으로 구부려주고 bias로 결과를 살짝 밀어줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활성화 함수가 없으면 그냥 선형 변환일 뿐이니 층을 아무리 여러 개 쌓아도 선형 변환으로 합쳐져 버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 할성화 함수를 통해 매 층마다 비선형하게 구부려줘야 층을 쌓는 의미가 생기고, Neural Network가 거의 모든 함수를 흉내낼 수 있다. (ex. ReLU)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Convolution Neural Network&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 2D 격자라서 한 줄로 펴서 MLP에 넣을 수도 있지만 Overfit 위험이 크고 가중치도 너무 많아서 적합하지 않음. 그리고 주변 픽셀도 못본다. Locality 편향이 있어야 하는데.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 Convolution을 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 창 하나를 이미지 위에 두고 그 내부 값들을 Kernel과 원소별로 곱해서 더한다 (내적)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과로 출력 뉴런이 하나 나오고, 이걸 Feature Map이라고 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 같은 Kernel을 모든 위치에 재사용 - 이러면 파라미터도 줄고 Locality 편향이 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kernel을 슬라이딩 윈도우 방식으로 다루니 Feature Map은 입력보다 작아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7VSjL/dJMcaftpsUf/33pRM8fUnsGfeuaNLN4hsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7VSjL/dJMcaftpsUf/33pRM8fUnsGfeuaNLN4hsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7VSjL/dJMcaftpsUf/33pRM8fUnsGfeuaNLN4hsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7VSjL%2FdJMcaftpsUf%2F33pRM8fUnsGfeuaNLN4hsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;359&quot; height=&quot;109&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Stride&lt;/b&gt; - 창이 한 번에 몇 칸씩 건너뛸지를 정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Padding&lt;/b&gt; - 연산 시 가장자리가 깎여 크기가 줄어드는데, 입력 테두리에 0을 둘러서 크기를 키워놓고 연산하면 입력과 출력이 같은 크기로 유지된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pooling&lt;/b&gt; - 가중치 없이 창 안에 있는 값을 최댓값 또는 평균값을 사용해서 계산한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convolution 뉴런은 Fully Connected 대신 Locality Window만 보니 가중치가 적으니 과적합이 방지된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가중치를 공유해 같은 Kernel을 모든 위치에 재사용할 수 있어 공간 상관관계를 포착할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채널은 같은 크기의 2D 격자 한 장으로, Tensor는 이런 격자를 여러 장 쌓아올린걸 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 RGB로 채널이 3개 -&amp;gt; Convolution을 지나면 채널은 색이 아니라 Feature Map이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter 하나가 Feature Map 한 장을 만들어낸다. 세로 모서리.. 곡선.. 무늬..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채널 수가 늘어나는건 Filter를 많이 써서 Feature Map을 여러 장 뽑는다는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convolution의 Kernel은 공간만 k * k 이고 항상 입력 채널 전부를 한 번에 본다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JGdB3/dJMcadI24UB/ekfKRhEJ5IhDbsH76oFk31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JGdB3/dJMcadI24UB/ekfKRhEJ5IhDbsH76oFk31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JGdB3/dJMcadI24UB/ekfKRhEJ5IhDbsH76oFk31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJGdB3%2FdJMcadI24UB%2FekfKRhEJ5IhDbsH76oFk31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;545&quot; height=&quot;211&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 1*1 Kernel를 사용하면 픽셀 하나만 보되 그 칸의 모든 채널 값을 다 섞어버린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 1*1 Kernel은 1*1*in Kernel과 같다고 보면 됨. 출력 채널 수는 사용하는 Kernel 개수와 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터 개수는 k*k*in*out + out(bias)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;in은 입력 채널 out은 출력 채널&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3*3 커널 2개를 사용하면 결국 5*5 시야를 가지는데, 5*5 커널 한개를 사용할 때 보다 파라미터 수가 적다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 CNN은 큰 커널 대신 작은 커널을 여러 번 쌓는 방식을 사용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Text Mining&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터가 문서를 다루려면 문서를 벡터로 변환해야 한다. (Vector Space Model)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 concept을 차원으로 본다. concept이 k개면 k차원 공간&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 문서는 두 공간의 벡터이고 문서 벡터 사이의 거리는 문서의 관계도를 의미함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VSM은 concept을 어떻게 고르는지를 정해주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미가 서로 겹치지 않는 Orthogonal 상태이고 가중치를 알아서 매길 수 있어야 한다. (Bag-of-Words)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Bag-of-Words&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어 하나하나를 차원으로 써서 문서를 벡터로 바꾸고 벡터 거리로 비교한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 문서에 나온 단어를 모아서 목록을 만든다. 이 단어 하나하나가 차원이 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 문서마다 벡터를 채워준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;text mining is mining 에서는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1,2,0,1] 각각 text mining apple is&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 단어의 등장 횟수만&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAG가 하는 일과 정확히 일치함. 질문과 문서를 벡터로 바꿔서 가장 가까운 문서 벡터를 찾아온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 BoW 대신 임베딩을 사용해 의미까지 담은 벡터를 만드는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 원문을 그대로 BoW에 넣으면 지저분하니 벡터로 만들기 전에 다듬는 과정을 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰화 -&amp;gt; 정규화 + 스테밍(mining을 mine으로. Vocabulary Gap을 커버함) -&amp;gt; 불용어 제거 -&amp;gt; BoW 벡터 완성&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어 빈도는 순위에 반비례한다. 그러니 단어를 빈도순으로 줄세우면 this that of a 같은 불용어가 대부분이라 일단 버림&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 sesquipedalianism 같은 희귀어는 거의 안나오니까 이것도 버림&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 양 끝을 쳐내는걸 Zipf 법칙이라고 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TF-IDF&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BoW는 단어를 그냥 카운트하는데, 모든 단어가 똑같이 중요하지는 않음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어가 문서를 잘 대표하려면 이 문서에는 자주 나오고 전체 문서 모음에서는 드물어야한다. TF-IDF는 이걸 정확하게 계산할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Term Frequency&lt;/b&gt;는 단어 t가 문서 d에 몇 번 나오는지를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 나오면 그 문서에 중요한거고, 근데 그냥 횟수만 쓰면 긴 문서가 무조건 유리하니 완화해서 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sub-linear : wf = 1 + log(count)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 TF 스케일링 : 문서 내 최대 단어 횟수로 나눠서 0~1로 표준화&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Inverse Document Frequency&lt;/b&gt;는 단어가 전체에서 얼마나 Rare한지를 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;df(t) 는 그 단어를 포함하는 문서 개수로, 적은 문서에 나올수록 더 변별력이 강해짐.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;df는 단어에 대해서 계산하는 것&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOijzq/dJMcaglyaqg/kgszshSG4R8wJowxbxm4Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOijzq/dJMcaglyaqg/kgszshSG4R8wJowxbxm4Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOijzq/dJMcaglyaqg/kgszshSG4R8wJowxbxm4Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOijzq%2FdJMcaglyaqg%2FkgszshSG4R8wJowxbxm4Jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;386&quot; height=&quot;77&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;128&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;428&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4tXds/dJMcadI3PDc/2j9V3wLIbvK32THBz7MDi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4tXds/dJMcadI3PDc/2j9V3wLIbvK32THBz7MDi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4tXds/dJMcadI3PDc/2j9V3wLIbvK32THBz7MDi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4tXds%2FdJMcadI3PDc%2F2j9V3wLIbvK32THBz7MDi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;258&quot; height=&quot;53&quot; data-origin-width=&quot;428&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서에는 자주 등장하고 전체에서는 드물게 나타나는 요소에 대해 높은 점수를 부여한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+1을 붙이는 이유는 흔한 단어도 최소 가중치 1은 남도록 하기 위해서임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Skip-gram&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BoW와 TF-IDF 벡터는 어휘 크기만큼 길고 의미를 담을 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 의미가 비슷한 단어는 벡터도 가깝게 표현할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 문맥에 등장하는 단어는 의미가 비슷하다. 그러니 주변 단어를 잘 골라내도록 벡터를 학습시킨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/whvjP/dJMcajoYd3L/zfPAMkGKaKYxQkaekGIOn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/whvjP/dJMcajoYd3L/zfPAMkGKaKYxQkaekGIOn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/whvjP/dJMcajoYd3L/zfPAMkGKaKYxQkaekGIOn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwhvjP%2FdJMcajoYd3L%2FzfPAMkGKaKYxQkaekGIOn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;200&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 위로 윈도우를 놓고, 가운데가 중심 단어 c이고 양 옆 +- m개가 주변 단어로 간주한다. (총 2m개)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중심 단어 c로 주변 단어 o를 맞출 확률을 벡터 내적 + softmax로 정의함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHq96Z/dJMb99NsWQd/koi8kxqyCIsmM9XuhGkWHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHq96Z/dJMb99NsWQd/koi8kxqyCIsmM9XuhGkWHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHq96Z/dJMb99NsWQd/koi8kxqyCIsmM9XuhGkWHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHq96Z%2FdJMb99NsWQd%2Fkoi8kxqyCIsmM9XuhGkWHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;79&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 벡터가 비슷한 방향일수록 이웃일 확률이 높고, 단어마다 벡터를 두 개 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주변 단어들의 확률을 최대화하고 Negative Log-Likelihood를 최소화한다. 이를 통해 SGD로 학습함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습이 끝나면 비슷한 문맥에 쓰이는 단어는 벡터가 가까워지고 의미 연산도 가능해진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 의미 벡터는 NLP와 RAG의 기반이 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 의미의 단어는 비슷한 문맥에 등장하니까 같은 이웃을 잘 맞히려면 벡터가 서로 비슷해진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 Skip-gram은 고전 임베딩이라 가볍고 로컬에서도 다룰 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 거대 트랜스포머 모델이 문맥까지 반영해서 같은 단어도 문장에 따라 벡터가 다르고 의미 보존이 훨씬 잘 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- log P(dog | cat) 을 줄이려면 P(dog | cat)을 키워야 하고, 내적값을 키워야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SGD가 서로 닮은 방향으로 밀어서 내적이 커짐.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vcat (1,0) Udog (0,1) 이라고 하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로 가까워지도록 살짝씩 밀어주는 역할&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Graph Mining&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프에서 누가 중요한 노드인지 따지는 Centrality와 웹페이지 중요도인 PageRank와 Random Walk로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Centrality&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드와 간산으로 구성되는 그래프에서 어떤 노드가 가장 중요한지를 점수로 매기기 위해 Centrality를 측정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GQ8TP/dJMcaaMp7en/RazfWANbD4xX6udRwwFhfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GQ8TP/dJMcaaMp7en/RazfWANbD4xX6udRwwFhfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GQ8TP/dJMcaaMp7en/RazfWANbD4xX6udRwwFhfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGQ8TP%2FdJMcaaMp7en%2FRazfWANbD4xX6udRwwFhfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;212&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 가지를 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Degree 측면에서는 연결된 간선이 많으면 중심이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Eccentricity 측면에서는 노드에서 가장 먼 노드까지의 거리를 측정하고 가장 먼 곳이 가까울수록 중심이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Closeness 측면에서는 다른 모든 노드까지 최단거리 합의 역수를 측정하고 합이 작을수록 중심이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Betweenness 측면에서는 노드를 지나가는 최단경로의 개수를 측정하고 경로가 많을수록 중심이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PageRank &amp;amp; Random Walk&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹을 방향 그래프로 본다. 페이지는 노드가 되고 하이퍼링크는 방향 있는 간선이 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나가는 링크가 없는 페이지는 셀프루프를 붙인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 확률 a : 페이지 u의 나가는 링크 중 하나를 무작위로 따라가서 이동함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 확률 1-a : 아무 페이지로 순간이동함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순간이동이 없으면 막다른 곳이나 링크 루프에 갇힐 수 있으니 모든 페이지가 도달 가능하도록 하기 위해 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 페이지의 PageRank는 사용자가 오랜 시간 뒤에도 그 페이지에 있을 확률을 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 페이지들이 많이 링크하는 페이지일수록 자주 방문되고 PageRank가 높아진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 수학으로 계산하는 방법이 따로 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 확률 벡터로 상태를 표현해야함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지가 n개일 때 지금 각 페이지에 있을 확률을 벡터 P로 기록한다. 이게 곧 확률벡터가 됨. (전부 더하면 1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이동 규칙을 행렬 M에 담는다. (Stochastic Matrix) - i에 있을 때 j로 갈 확률&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전부 1인 벡터를 M의 왼쪽에 곱하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 분포가 P(t) 이면 다음 분포는 P(t+1) = M * P(t) 로 정리됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;M을 한번 곱할 때 마다 한 번 더 걸은 분포가 나온다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 걷다 보면 분포가 더 이상 변하지 않는 지점에 도달함 (P = MP)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서의 P를 정상분포라고 하고, 이게 PageRank벡터.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, P는 M의 고유값 1에 대응하는 고유벡터가 됨. (PCA에서 다룬 내용과 같다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o0Rqt/dJMcahLyjQx/KO3e8EPKBTniKddLTfl211/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o0Rqt/dJMcahLyjQx/KO3e8EPKBTniKddLTfl211/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o0Rqt/dJMcahLyjQx/KO3e8EPKBTniKddLTfl211/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo0Rqt%2FdJMcahLyjQx%2FKO3e8EPKBTniKddLTfl211%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;597&quot; height=&quot;132&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬과 그 행렬의 전치행렬은 고유값이 똑같다. 그러니 P = MP 인 정상분포 P가 항상 존재하는게 보장됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 전부 1인 벡터를 왼쪽에 곱해주면 열의 합이 1이라서 그대로 나온다는거임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Recommender System&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 아직 평가하지 않은 아이템에 몇 점을 매길지 예측하고, 높을 것 같은걸 추천한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 &lt;b&gt;Collaborative&lt;/b&gt; &lt;b&gt;Filtering&lt;/b&gt;이라고 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User-User는 나와 취향이 비슷한 사용자를 찾고 걔내들의 평점으로 내 평점을 예측&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Item-Item은 내가 평가한 아이템 중 목표 아이템과 비슷한 아이템을 찾고 내가 준 평점의 가중편균으로 예측&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzeLxE/dJMcaftqiS8/ky1RP72s8JJRLBTJIOgCNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzeLxE/dJMcaftqiS8/ky1RP72s8JJRLBTJIOgCNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzeLxE/dJMcaftqiS8/ky1RP72s8JJRLBTJIOgCNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzeLxE%2FdJMcaftqiS8%2Fky1RP72s8JJRLBTJIOgCNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;266&quot; height=&quot;107&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웬만하면 Item-Item이 User-User보다 낫다. 아이템은 사람보다 단순하니까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collaborative Filtering은 아이템 종류를 가리지 않고 평점만 있어도 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 매칭할 사용자가 충분히 쌓여야 하고, 평점표가 비어있어 같은 아이템을 평가한 사용자가 찾기 어려우면 사용하기 힘들다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무도 평가하지 않은 새 아이템은 추천하기 어렵고, 독특한 취향을 반영하는것도 어려우며 극단화를 유도할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Netflix의 SVD는 희소성을 정면 돌파한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평점 행렬 R을 두 개의 얇은 행렬 곱으로 근사때려버림.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CH6ww/dJMcagMHpuY/VWZmI2X8AA6WGrTahffxbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CH6ww/dJMcagMHpuY/VWZmI2X8AA6WGrTahffxbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CH6ww/dJMcagMHpuY/VWZmI2X8AA6WGrTahffxbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCH6ww%2FdJMcagMHpuY%2FVWZmI2X8AA6WGrTahffxbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;164&quot; height=&quot;68&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q는 아이템 i의 요인 벡터 (그 영화의 액션성, 로맨스성, 예술성 등을 얼마나 가지는지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;P는 사용자 x의 요인 벡터 (그 사람이 액션을 얼마나 좋아하는지)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 x의 아이템 i 평점은 두 요인 벡터의 내적으로 구할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/phsx3/dJMcagy5OEb/B7C3TBgHkDakiRmmzZ9kdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/phsx3/dJMcagy5OEb/B7C3TBgHkDakiRmmzZ9kdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/phsx3/dJMcagy5OEb/B7C3TBgHkDakiRmmzZ9kdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fphsx3%2FdJMcagy5OEb%2FB7C3TBgHkDakiRmmzZ9kdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;98&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈칸이 많아도 평점만 잘 맞추도록 Q와 P를 학습하면 그 내적값으로 빈칸을 예측할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lattice는 말 그대로 격자를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOUtVH/dJMcaayVZDH/0ucwmwdkh8TUu84pEoTpU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOUtVH/dJMcaayVZDH/0ucwmwdkh8TUu84pEoTpU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOUtVH/dJMcaayVZDH/0ucwmwdkh8TUu84pEoTpU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOUtVH%2FdJMcaayVZDH%2F0ucwmwdkh8TUu84pEoTpU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;318&quot; height=&quot;245&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 아이템셋과 포함관계를 한눈에 그린 그림으로, 어떤 아이템셋이 infrequent하면 그 위쪽도 전부 infrequent함을 보여주기 위해 등장함. 그냥 Apriori 시각화를 위해 사용되는 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4HSNj/dJMcaiRd6BP/7X8ojHoPQh6nQ7nBGnJamk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4HSNj/dJMcaiRd6BP/7X8ojHoPQh6nQ7nBGnJamk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4HSNj/dJMcaiRd6BP/7X8ojHoPQh6nQ7nBGnJamk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4HSNj%2FdJMcaiRd6BP%2F7X8ojHoPQh6nQ7nBGnJamk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;80&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rank는 0이 아닌 특이값의 개수로, 데이터의 독립적인 방향이 몇 개인지를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점들이 한 직선 위에만 있으면 방향이 1개라서 rank도 1이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Orthogonal은 수직을 의미하고 기하적으로는 두 벡터가 수직이라는 뜻이다. (내적값 0)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA에서 PC들이 직교하면 서로 수직이라서 정보가 겹치지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미가 서로 겹치지 않아서 독립적이라는 뜻. 독립적이면서 겹치지 않는 방향을 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BoW는 전처리 후 어휘 만들고 단어 횟수만 세서 벡터로 만든다. 이게 너무 간단하니 TF-IDF와 임베딩이 나온 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 frequent한 I 에서 I1 -&amp;gt; I2를 만드는거니까 규칙 단계에서는 support를 신경쓰지 않고 confidence만 검사하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X = U S V^T&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SVD가 데이터 X를 셋으로 쪼갠다 (이게 시작점)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V의 열은 PC의 방향이고, S의 특이값은 그 방향으로 퍼지는 정도&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Z = XV (이건 PCA 공식)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Z = XV = U S V^T V = US&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X = Z V^T&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minPts가 1이면 모든 점이 핵심점이 된다. 이러면 DBSCAN은 거리 엡실론 이하로 이어지는 점을 모두 묶음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 그냥 Single Linkage에서 높이 엡실론으로 덴드로그램 자른거랑 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서가 길면 그냥 TF가 높아지니까 Scaling이 필요함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sub-linear는 1 + log(횟수). 로그로 눌러버린다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 TF Scaling은 그 문서에서 가장 많이 나온 단어로 나눠서 0~1로 맞추고 긴 문서 편향을 제거함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TF만 쓰면 모든 문서에 흔한 단어가 점수를 독식하니 IDF를 사용함 -&amp;gt; TF * IDF 로 최종 계산&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;df는 그 단어가 몇 개의 문서에 등장하는지를 카운트함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ttf는 그 단어가 전체에서 몇 번 나온지를 카운트함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 ttf 대신 df 쓴다. 단어가 한 문서에서만 100번 나오면 ttf는 크지만 df는 1이기 때문 -&amp;gt; 특정 문서 전용단어임을 캐치&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;희귀할수록 IDF가 올라감&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Data Science</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/847</guid>
      <comments>https://13months.tistory.com/847#entry847comment</comments>
      <pubDate>Thu, 18 Jun 2026 14:02:28 +0900</pubDate>
    </item>
    <item>
      <title>[Data Science] BirdCLEF+ 2026 챌린지 결과 발표</title>
      <link>https://13months.tistory.com/846</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ0ghA/dJMcabEuLiq/qZKOjw7VKkVjlA8Pb5wqpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ0ghA/dJMcabEuLiq/qZKOjw7VKkVjlA8Pb5wqpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ0ghA/dJMcabEuLiq/qZKOjw7VKkVjlA8Pb5wqpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ0ghA%2FdJMcabEuLiq%2FqZKOjw7VKkVjlA8Pb5wqpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2018&quot; height=&quot;1164&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이어서 BirdCLEF에 대해 발표하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q3ouz/dJMcagMDvz3/xcgpsJVtejekKsQW4lx4EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q3ouz/dJMcagMDvz3/xcgpsJVtejekKsQW4lx4EK/img.png&quot; data-origin-width=&quot;2036&quot; data-origin-height=&quot;1176&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.68%; margin-right: 10px;&quot; data-widthpercent=&quot;50.26&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q3ouz/dJMcagMDvz3/xcgpsJVtejekKsQW4lx4EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq3ouz%2FdJMcagMDvz3%2FxcgpsJVtejekKsQW4lx4EK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2036&quot; height=&quot;1176&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dS1AHc/dJMb997KS8Q/M0oAikNTKDHv9Kq2EWyMKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dS1AHc/dJMb997KS8Q/M0oAikNTKDHv9Kq2EWyMKK/img.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1178&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.1572%;&quot; data-widthpercent=&quot;49.74&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dS1AHc/dJMb997KS8Q/M0oAikNTKDHv9Kq2EWyMKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdS1AHc%2FdJMb997KS8Q%2FM0oAikNTKDHv9Kq2EWyMKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2018&quot; height=&quot;1178&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 결과는 public에서 은메달권까지 갔다가 1시간만에 4-500등이 밀리는 경험을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 이것저것 여러 시도를 해 보면서 결국 1200등 내에 들었지만 좀 아쉬웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck0kjT/dJMcadvtuJe/9L5R0sIuuvZOgpDLxd9l7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck0kjT/dJMcadvtuJe/9L5R0sIuuvZOgpDLxd9l7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck0kjT/dJMcadvtuJe/9L5R0sIuuvZOgpDLxd9l7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck0kjT%2FdJMcadvtuJe%2F9L5R0sIuuvZOgpDLxd9l7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2024&quot; height=&quot;1160&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 가지 가설을 세웠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BirdCLEF의 학습데이터는 크게 inat 출처의 비교적 깔끔한 새소리와, soundscape 출처의 잡음이 많이 섞인 소리로 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EDA를 통해 이 둘 간의 격차가 굉장히 크다는걸 확인했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 소리 크기 자체의 편향을 정규화하는 모델 구조가 필요함을 확인할 수 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;1158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzmCcp/dJMcaci4rB9/MSW1fIDfHjw8355o12NOM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzmCcp/dJMcaci4rB9/MSW1fIDfHjw8355o12NOM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzmCcp/dJMcaci4rB9/MSW1fIDfHjw8355o12NOM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzmCcp%2FdJMcaci4rB9%2FMSW1fIDfHjw8355o12NOM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2012&quot; height=&quot;1158&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;1158&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로는 학습데이터에서 여러 종 간의 동시 출현 관련 생물학적 신호를 확인하기 위해서 수행한 EDA입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이드에는 자세히 적어뒀지만.. 사실 저 신호는 장소 내의 신호 또는 시간에 따른 신호였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A9B3D/dJMcaaS89Zw/G5tHbe1QmAvLgxNoT0DEL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A9B3D/dJMcaaS89Zw/G5tHbe1QmAvLgxNoT0DEL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A9B3D/dJMcaaS89Zw/G5tHbe1QmAvLgxNoT0DEL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA9B3D%2FdJMcaaS89Zw%2FG5tHbe1QmAvLgxNoT0DEL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1186&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 정말 장소나 시간의 문제인지 확인해봤고, 실제로는 시간에 대한 문제였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접 윈도우 chunk간 연속성 통계에서 이런 강한 상관관계를 나타내고 있음을 추론할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 다양한 EDA를 많이 수행했지만 생략하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8nsPy/dJMcabRZ8Qc/KDn5D5GVpbvqqJaQItm380/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8nsPy/dJMcabRZ8Qc/KDn5D5GVpbvqqJaQItm380/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8nsPy/dJMcabRZ8Qc/KDn5D5GVpbvqqJaQItm380/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8nsPy%2FdJMcabRZ8Qc%2FKDn5D5GVpbvqqJaQItm380%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2004&quot; height=&quot;1154&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EDA 결과를 기반으로 음향 이벤트를 검출하는 문제와 이 문제를 어떻게 해결할지에 대해 생각했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 고성능 GPU가 부족하니, 저희가 할 수 있는건 잘 만들어진 모델을 선택하고 그 모델을 바탕으로 사후처리 및 하이퍼파라미터를 조율하는 작업입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 선택한 모델의 파이프라인은 이렇습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미시적 음향 이벤트를 잡아내는 SED, 거시적 시계열 문맥을 읽어내는 ProtoSSMv5의 이중 파이프라인 구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 모델의 예측치를 블렌딩하여 구조적 사각지대를 보완했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nYYfp/dJMcafz9Q98/EQkqWEbIRXAxAMg4WnrE30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nYYfp/dJMcafz9Q98/EQkqWEbIRXAxAMg4WnrE30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nYYfp/dJMcafz9Q98/EQkqWEbIRXAxAMg4WnrE30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnYYfp%2FdJMcafz9Q98%2FEQkqWEbIRXAxAMg4WnrE30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1150&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌측에서는 Mel-Spectrogra을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소리를 시간-주파수 정보로 변환한 정보를 2D CNN으로 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우측에서는 Perch v2 임베딩과 함께 SSM을 수행하여 temporal cross-attention으로 음향 시계열 문맥을 잡아 두 경로간의 1차 예측을 Rank / Logit Blending으로 결과를 도출합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들어진 1차 예측을 4단계 게이트로 정제합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MLP Probe로 1차 보정을 진행한 후, 음향 이벤트 검출을 연속적으로 정리하고 생태학적으로 공존할 수 없는 종을 상호 배제 필터링하는 순서입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX4U5Y/dJMcabRZ8Vw/HOPu6sIANneCgR7NZPikk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX4U5Y/dJMcabRZ8Vw/HOPu6sIANneCgR7NZPikk1/img.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1150&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3515%; margin-right: 10px;&quot; data-widthpercent=&quot;49.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX4U5Y/dJMcabRZ8Vw/HOPu6sIANneCgR7NZPikk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX4U5Y%2FdJMcabRZ8Vw%2FHOPu6sIANneCgR7NZPikk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1150&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmWZ4O/dJMcaijkJQ0/vOrgyuAXGjCYaK0bXYocJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmWZ4O/dJMcaijkJQ0/vOrgyuAXGjCYaK0bXYocJ0/img.png&quot; data-origin-width=&quot;1988&quot; data-origin-height=&quot;1140&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4857%;&quot; data-widthpercent=&quot;50.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmWZ4O/dJMcaijkJQ0/vOrgyuAXGjCYaK0bXYocJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmWZ4O%2FdJMcaijkJQ0%2FvOrgyuAXGjCYaK0bXYocJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1988&quot; height=&quot;1140&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는 선택한 모델에 대한 이야기였고, 이제는 저희가 수행한 후처리 방식에 대해 말씀드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균 풀링 방식은 이미 확실한 종의 점수까지 Dilution하는 문제가 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 슬라이드는 저희의 핵심 방법론과 성능 향상 방안을 요약한 내용입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;1152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwqVKG/dJMcaar58lk/yk4jr8sYPm4I8XfAqlNb61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwqVKG/dJMcaar58lk/yk4jr8sYPm4I8XfAqlNb61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwqVKG/dJMcaar58lk/yk4jr8sYPm4I8XfAqlNb61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwqVKG%2FdJMcaar58lk%2Fyk4jr8sYPm4I8XfAqlNb61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1998&quot; height=&quot;1152&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;1152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Genus 단위에는 최대 풀링을, Class 단위에는 평균 폴링을 하이브리드로 적용하는 비대칭적 Smoothing을 도입해 확신 점수를 보존하면서도 형제 종의 점수를 높였습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 기존의 모델과 비교했을 때 직교성을 가지는 모델인 ProtoSSMv5를 작은 가중치로 블렌딩해서 작게나마 점수를 상승시켰습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 MAE를 mel-spectrogram에 적용하는 등 다양한 시도를 해봤지만, 이미지랑은 정말 안 맞아도 점수가 제대로 나오지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2014&quot; data-origin-height=&quot;1160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1pgft/dJMcaaMmuGd/Fu38fUhipmncHjvon4iDY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1pgft/dJMcaaMmuGd/Fu38fUhipmncHjvon4iDY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1pgft/dJMcaaMmuGd/Fu38fUhipmncHjvon4iDY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1pgft%2FdJMcaaMmuGd%2FFu38fUhipmncHjvon4iDY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2014&quot; height=&quot;1160&quot; data-origin-width=&quot;2014&quot; data-origin-height=&quot;1160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꽤나 긴 발표였는데 들어주셔서 정말 감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상 발표 마치겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  기록</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/846</guid>
      <comments>https://13months.tistory.com/846#entry846comment</comments>
      <pubDate>Wed, 10 Jun 2026 23:44:38 +0900</pubDate>
    </item>
    <item>
      <title>[StackUp] 종합설계 Sprint 2&amp;middot;3 Backlog 및 계획 발표</title>
      <link>https://13months.tistory.com/843</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2310&quot; data-origin-height=&quot;1326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccapmX/dJMcaiQ2KYb/O7tbhVCORVBJ0wAeXZcYlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccapmX/dJMcaiQ2KYb/O7tbhVCORVBJ0wAeXZcYlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccapmX/dJMcaiQ2KYb/O7tbhVCORVBJ0wAeXZcYlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccapmX%2FdJMcaiQ2KYb%2FO7tbhVCORVBJ0wAeXZcYlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2310&quot; height=&quot;1326&quot; data-origin-width=&quot;2310&quot; data-origin-height=&quot;1326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티모달 AI를 활용한 챗봇 개발을 주제로 I&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;T 직군을 위한 모의 면접 경험을 제공하는 서비스를 개발하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 스프린트 2와 3에 대한 계획과 백로그에 대해 말씀드리려고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;1338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhCf9H/dJMcahR7qEX/dc0AueWSL4usbxhgPWduxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhCf9H/dJMcahR7qEX/dc0AueWSL4usbxhgPWduxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhCf9H/dJMcahR7qEX/dc0AueWSL4usbxhgPWduxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhCf9H%2FdJMcahR7qEX%2Fdc0AueWSL4usbxhgPWduxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2316&quot; height=&quot;1338&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;1338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 프로젝트는 스프린트 3까지로 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 스프린트 2까지를 이번 학기에 수행하고, 다음 학기에 이어서 스프린트 3을 개발하려 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 계획을 수정해 이번 학기에 스프린트 3까지 진행할 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주차는 스프린트2 에 대한 계획과 백로그를 발표하는 시간이지만 프로젝트 계획 상 스프린트 2와 3에 대해 모두 말씀드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2324&quot; data-origin-height=&quot;1334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/riDdw/dJMcahq7uIS/rLXYWtfANZFoFitIN5KQCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/riDdw/dJMcahq7uIS/rLXYWtfANZFoFitIN5KQCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/riDdw/dJMcahq7uIS/rLXYWtfANZFoFitIN5KQCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FriDdw%2FdJMcahq7uIS%2FrLXYWtfANZFoFitIN5KQCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2324&quot; height=&quot;1334&quot; data-origin-width=&quot;2324&quot; data-origin-height=&quot;1334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프린트 2와 스프린트 3은 이전 스프린트1에서 닦아둔 기반을 바탕으로 실제 면접 시뮬레이션을 구현하는 단계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프린트 2에서는 텍스트 기반 면접 세션 구현과 면접 세션 피드백을 제공하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프린트 3에서는 텍스트 기반 면접을 음성 기반 면접으로 전환하는 작업을 수행합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2320&quot; data-origin-height=&quot;1348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bduzPA/dJMcaffMrVq/lVStgOKemvVH2PF1JEhnX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bduzPA/dJMcaffMrVq/lVStgOKemvVH2PF1JEhnX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bduzPA/dJMcaffMrVq/lVStgOKemvVH2PF1JEhnX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbduzPA%2FdJMcaffMrVq%2FlVStgOKemvVH2PF1JEhnX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2320&quot; height=&quot;1348&quot; data-origin-width=&quot;2320&quot; data-origin-height=&quot;1348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 처리해야 할 작업에 대해 하나씩 말씀드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접 세션 생성 작업에서는 기술면접, 인성면접 등 면접 유형, 면접 직군 등 면접에 대한 기본 설정을 진행하고 백엔드가 SSE 요청을 보내는 작업을 처리합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2346&quot; data-origin-height=&quot;1350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vq6SF/dJMcagTgjVb/bJfqKTAFVzJy98ZVrBsQwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vq6SF/dJMcagTgjVb/bJfqKTAFVzJy98ZVrBsQwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vq6SF/dJMcagTgjVb/bJfqKTAFVzJy98ZVrBsQwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvq6SF%2FdJMcagTgjVb%2FbJfqKTAFVzJy98ZVrBsQwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2346&quot; height=&quot;1350&quot; data-origin-width=&quot;2346&quot; data-origin-height=&quot;1350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 및 초기 질문 생성 작업에서는 사용자가 선택한 유형 및 업로드한 이력서를 바탕으로 초기 질문을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메세지 큐를 사용해 백엔드간 통신을 중개하고, AI 서버는 LLM을 기반으로 질문을 생성합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2334&quot; data-origin-height=&quot;1348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rt6k3/dJMb990VBLH/yKtJVDGTUOaKqpZWPuWg91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rt6k3/dJMb990VBLH/yKtJVDGTUOaKqpZWPuWg91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rt6k3/dJMb990VBLH/yKtJVDGTUOaKqpZWPuWg91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frt6k3%2FdJMb990VBLH%2FyKtJVDGTUOaKqpZWPuWg91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2334&quot; height=&quot;1348&quot; data-origin-width=&quot;2334&quot; data-origin-height=&quot;1348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 스프린트 2에서는 텍스트 면접을 구현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 면접에 필요한 UI UX를 구현하고 꼬리질문 관련 UX를 구현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 서버는 면접자의 답변을 분석해 부족한 부분을 파고드는 꼬리질문을 생성합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2328&quot; data-origin-height=&quot;1354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZpgAJ/dJMcabEozzr/wU5jIGV7TGSGirA1fn0Fm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZpgAJ/dJMcabEozzr/wU5jIGV7TGSGirA1fn0Fm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZpgAJ/dJMcabEozzr/wU5jIGV7TGSGirA1fn0Fm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZpgAJ%2FdJMcabEozzr%2FwU5jIGV7TGSGirA1fn0Fm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2328&quot; height=&quot;1354&quot; data-origin-width=&quot;2328&quot; data-origin-height=&quot;1354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2318&quot; data-origin-height=&quot;1328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qrElI/dJMcaicvANs/rKAYzxyudsydJKGVWgKUI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qrElI/dJMcaicvANs/rKAYzxyudsydJKGVWgKUI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qrElI/dJMcaicvANs/rKAYzxyudsydJKGVWgKUI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqrElI%2FdJMcaicvANs%2FrKAYzxyudsydJKGVWgKUI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2318&quot; height=&quot;1328&quot; data-origin-width=&quot;2318&quot; data-origin-height=&quot;1328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접이 마무리되면 피드백 리포트를 생성합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접은 기본적으로 Websocket 대신 SSE를 사용해서 처리됩니다. SSE로 완료 메세지를 수신하면 프론트엔드는 리포트 화면으로 이동합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 서버는 4가지 측정 지표를 기반으로 면접 세션을 깊게 분석합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;1342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPnjXC/dJMcaarZmsA/G6C9hEjwVAytj53eW2whA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPnjXC/dJMcaarZmsA/G6C9hEjwVAytj53eW2whA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPnjXC/dJMcaarZmsA/G6C9hEjwVAytj53eW2whA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPnjXC%2FdJMcaarZmsA%2FG6C9hEjwVAytj53eW2whA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2316&quot; height=&quot;1342&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;1342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프린트 3에서는 텍스트 기반 면접을 음성 기반 면접으로 전환합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 텍스트 기반 면접도 함께 지원하기 위해 토글로 면접 모드를 설정할 수 있도록 제공합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 서버는 OpenAI Whisper, Deepgram API를 사용해 STT / TTS 를 구현합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;1300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HVuEe/dJMcagMwG1h/0bAiOvQIJqBBFKCfVXYVf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HVuEe/dJMcagMwG1h/0bAiOvQIJqBBFKCfVXYVf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HVuEe/dJMcagMwG1h/0bAiOvQIJqBBFKCfVXYVf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHVuEe%2FdJMcagMwG1h%2F0bAiOvQIJqBBFKCfVXYVf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2228&quot; height=&quot;1300&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;1300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 아키텍처입니다. 스프린트 3까지 마무리되면 위의 아키텍처를 모두 구현하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2224&quot; data-origin-height=&quot;1272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UDQaT/dJMcahdzcFT/lx5bmZpyEQRmyvEA2WqxxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UDQaT/dJMcahdzcFT/lx5bmZpyEQRmyvEA2WqxxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UDQaT/dJMcahdzcFT/lx5bmZpyEQRmyvEA2WqxxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUDQaT%2FdJMcahdzcFT%2Flx5bmZpyEQRmyvEA2WqxxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2224&quot; height=&quot;1272&quot; data-origin-width=&quot;2224&quot; data-origin-height=&quot;1272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 작업별 DoD입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접 세션 생성에서는 입력한 설정값 기반으로 세션이 제대로 생성되는지를 확인하고, 연결 및 초기 질문 생성에서는 면접 유형에 적합한 질문이 생성되는지를 확인합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼬리질문은 사용자의 답변이 있고 나서 3초 이내에 전송됨을 목표로 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2226&quot; data-origin-height=&quot;1266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sDMs8/dJMcaa6Bh4G/vTTPFYqUUsQRQ7UXXTkndk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sDMs8/dJMcaa6Bh4G/vTTPFYqUUsQRQ7UXXTkndk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sDMs8/dJMcaa6Bh4G/vTTPFYqUUsQRQ7UXXTkndk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsDMs8%2FdJMcaa6Bh4G%2FvTTPFYqUUsQRQ7UXXTkndk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2226&quot; height=&quot;1266&quot; data-origin-width=&quot;2226&quot; data-origin-height=&quot;1266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피드백 리포트는 미리 설정한 4개 지표 기반으로 점수가 제대로 산출됐는지 확인하고, 스프린트 3의 음성 기반 면접에서는 발화 지표 분석이 제대로 수행되는지 확인합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2064&quot; data-origin-height=&quot;1198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MGmPM/dJMcaiwK2py/hwXvO4R9ZzLjQ6enKbYwq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MGmPM/dJMcaiwK2py/hwXvO4R9ZzLjQ6enKbYwq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MGmPM/dJMcaiwK2py/hwXvO4R9ZzLjQ6enKbYwq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMGmPM%2FdJMcaiwK2py%2FhwXvO4R9ZzLjQ6enKbYwq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2064&quot; height=&quot;1198&quot; data-origin-width=&quot;2064&quot; data-origin-height=&quot;1198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 스프린트에서는 시연 시 동영상 기반으로 시연해 이 부분에 대해서 피드백이 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 스프린트를 거치면 프론트엔드와 백엔드 모두 구축된 서버로 배포되고 실시간으로 시연할 수 있는 환경이 구축됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  기록</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/843</guid>
      <comments>https://13months.tistory.com/843#entry843comment</comments>
      <pubDate>Mon, 1 Jun 2026 15:35:02 +0900</pubDate>
    </item>
    <item>
      <title>[Data Science] ETRI 휴먼이해 인공지능 논문경진대회 - 5</title>
      <link>https://13months.tistory.com/841</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 OOF는 믿을 수가 없으니 데이콘 LB 자체를 채점기로 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출은 하루에 세 번만 가능하니 이 제출을 검증기로 사용. 세번밖에 못 쓰니 아무거나 던지면 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가설을 세우기 전에 고려할 점&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 현재 Best와 얼마나 다른지?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한거 섞어봤자 성능이 좋아지지 않는다. 현재 Best가 못 보는 부분을 다른 관점에 봐 줘야 의미가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후보의 Test 예측과 현재 Best의 예측이 얼마나 비슷한지를 상관계수로 기록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 혼자서도 얼마나 잘 맞히는지?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Best랑 다르기만 하고 혼자서는 잘 못 맞추는 후보는 그냥 다른 노이즈일 뿐이다. 그러니 실제로 라벨을 잘 맞추는지도 확인해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OOF 점수가 Baseline보다 얼마나 나은지를 평가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OOF를 믿을 수 없는건 최종 판정에서 못 믿는다는거지 혼자서 잘 맞추는지의 척도로는 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 기준에 부합하는 모델을 Best에 합치는 방식으로 점수를 누적한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 합치는 방식도 중요함. 그냥 평균을 내는 것 보다 logit 공간에서 섞어 줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평가지표가 Average Log-Loss라서 산술평균하면 보정이 망가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1780986796982&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# logit 관련 연산 
def logit(p):
    p = np.clip(p, EPS, 1 - EPS)
    return np.log(p / (1 - p))

def sigmoid(x):
    return 1.0 / (1.0 + np.exp(-x))


def blend(base, axis, a):
    return sigmoid((1 - a) * logit(base) + a * logit(axis))


def load_axis(name):
    d = np.load(ART / f'{name}_aggregated.npz')
    return d['oof_v2'].astype(np.float64), d['tp_v2'].astype(np.float64)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 시 이렇게 변환 함수를 만들어서 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 그림은 위의 방식대로 설정하고 Best를 계속 갱신한 결과&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 138px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;Card A&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;피실험자 하나씩 빼고 학습 돌리기&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;0.5794&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;TabPFN&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Tabular Transformer GBM을 안씀&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;0.5793&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;MLP + SleepV6&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;분 단위 수면 피쳐가 MLP에 도움이 됨&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;0.5762&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;MLPContrast&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Contrastive 피쳐 MLP로 Q2 최적화&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;0.57579&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;MIS-LSTM&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;외부 논문 참고 - CNN+LSTM + 시계열&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;0.56795&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;MIS-LSTM 누적&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;S2 S3 최적화&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;0.56525&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Sleep6-Q3 적용&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Q3 전용 누적&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;0.56524&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;SleepV6 정렬버그 수정 + Q3 적용&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Off-By-One 정렬 버그 수정&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;0.56505&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 조금씩 오른다 작은 검증들을 모으고 또 모아서 0.56505까지 깎았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 논문에서 사용한 방식인 4h CNN + LSTM 을 그대로 적용했던게 좀 컸다 (&lt;a href=&quot;https://arxiv.org/abs/2509.11232&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/abs/2509.11232&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SleepV6을 적용할 때는 야간창 계산할때 off-by-one 정렬 버그가 있었고 그걸 수정하니 Q3가 최적화됐다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Data Science</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/841</guid>
      <comments>https://13months.tistory.com/841#entry841comment</comments>
      <pubDate>Sat, 23 May 2026 13:46:29 +0900</pubDate>
    </item>
    <item>
      <title>[Embedded] Device Driver</title>
      <link>https://13months.tistory.com/840</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디바이스 드라이버는 하드웨어를 추상화하는 소프트웨어 계층.. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;OS 다룬 내용이랑 유사할 수 밖에 없음.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Upper Half 계층과 HAL 두 계층으로 나뉜다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778754069907&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// GPIO
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);

// 통신 UART
HAL_UART_Transmit(&amp;amp;huart2, buf, len, 100);

// 초음파 TIMER
HAL_TIM_Base_Start_IT(&amp;amp;htim2);

// 모터 PWM
HAL_TIM_PWM_Start(&amp;amp;htim3, TIM_CHANNEL_1);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 지금까지 자연스럽게 작성하던 HAL_* 함수가 모두 디바이스 드라이버임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPIO 레지스터를 직접 조작하지 않고 함수 호출만 했고, 내부에서는 디바이스 드라이버가 작동하던 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJ2rzQ/dJMcabxpWdM/qIrjjjkA2qJQkaWb2rkU5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJ2rzQ/dJMcabxpWdM/qIrjjjkA2qJQkaWb2rkU5k/img.png&quot; data-origin-width=&quot;1934&quot; data-origin-height=&quot;824&quot; data-is-animation=&quot;false&quot; style=&quot;width: 38.762%; margin-right: 10px;&quot; data-widthpercent=&quot;39.22&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJ2rzQ/dJMcabxpWdM/qIrjjjkA2qJQkaWb2rkU5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJ2rzQ%2FdJMcabxpWdM%2FqIrjjjkA2qJQkaWb2rkU5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1934&quot; height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPHzGP/dJMcafs3QGJ/aoKnKRBGiBDgPfKU2f8L20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPHzGP/dJMcafs3QGJ/aoKnKRBGiBDgPfKU2f8L20/img.png&quot; data-origin-width=&quot;2088&quot; data-origin-height=&quot;574&quot; data-is-animation=&quot;false&quot; style=&quot;width: 60.0752%;&quot; data-widthpercent=&quot;60.78&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPHzGP/dJMcafs3QGJ/aoKnKRBGiBDgPfKU2f8L20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPHzGP%2FdJMcafs3QGJ%2FaoKnKRBGiBDgPfKU2f8L20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2088&quot; height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Upper Half 부분은 디바이스 독립적 API 부분으로 디바이스에 따라 바뀌지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 Hardware Abstraction Layer는 디바이스마다 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 코드를 STM32F4에서 STM32H7로 옮길 때, 디바이스마다 UART 레지스터 위치와 클럭 구조가 다 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 Upper Half 부분은 그대로 두고 HAL 내부 구현만 고치면 되니 유용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드용 RTOS는 드라이버와 커널이 같은 층이고, Standard OS는 드라이버가 커널 아래에 위치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념 정리를 더 하고 싶은데 CS가 그렇듯 항상 똑같아서 할 게 없다. OS에서 다룬 내용이 그대로 여기서도 적용됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상화 + 표준인터페이스 + 계층화&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;1068&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qycvX/dJMcadhJmvn/3ifoFi91A8ibyxX451BGqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qycvX/dJMcadhJmvn/3ifoFi91A8ibyxX451BGqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qycvX/dJMcadhJmvn/3ifoFi91A8ibyxX451BGqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqycvX%2FdJMcadhJmvn%2F3ifoFi91A8ibyxX451BGqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;343&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;1068&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 폴더를 살펴보면 STM32F4xx_HAL_Driver를 찾을 수 있음. 이 폴더 전체가 디바이스 드라이버 모음집이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ppp는 peripheral의 약자임. uart, adc, gpio 버전도 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main.c와 stm32f4xx_it.c 는 HAL 드라이버를 코드와 연결해주는 역할을 수행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 인터럽트가 발생하면 IRQHandler가 인식하고 HAL에서 내부 처리를 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나서 내가 작성한 main.c에서 로직을 처리하는 순서임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HAL이 로직의 대부분을 처리해주고 마지막 사용자 정의 부분만 콜백으로 외부로 던진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 작성한 콜백 함수가 디폴트 함수를 덮어쓰는 구조.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HAL 자료구조는 세 가지로 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Peripheral Handle&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Init / Config&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 특정 작업을 위한 구조체 (&amp;amp;huart2, &amp;amp;htim3)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세서와 I/O 디바이스의 속도가 다르니 데이터 Sync를 맞추기 위해 둘 사이에 버퍼가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU와 메모리 사이에 캐시가 있어야 하고, 네트워크에는 송수신 버퍼가 있듯 CPU와 I/O 디바이스 사이에도 버퍼가 있어야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;속도 차이 문제를 버퍼로 해결하고, 공유 데이터 문제는 Semaphore와 Mutex로 해결한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1994&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JHvmk/dJMcaaSQOFY/bJmGJiyw2PykAtdtPB97oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JHvmk/dJMcaaSQOFY/bJmGJiyw2PykAtdtPB97oK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JHvmk/dJMcaaSQOFY/bJmGJiyw2PykAtdtPB97oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJHvmk%2FdJMcaaSQOFY%2FbJmGJiyw2PykAtdtPB97oK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;257&quot; data-origin-width=&quot;1994&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세서는 병렬버스로 데이터에 접근하지만, 외부 디바이스는 직렬로 데이터에 접근한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 변환 회로가 필요하고, 그 회로로 UART를 사용함. (Universial Asynchronous Receiver and Transmitter)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 콜로 OS에게 출력을 부탁하고, UART 드라이버가 문자열을 받아 한 문자씩 UART로 전송한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 UART의 Shift Reg가 직렬로 바깥에 송출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자를 한 번에 한 개씩 UART로 전송하는게 포인트. 문자 단위로 루프가 실행된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778755863299&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (*string != '\0') 
    printChar(*string++);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 짜면 간단하지만 while 루프는 UART가 문자를 전송하는 속도보다 훨씬 빠르게 실행되니 문제가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778755897965&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (*string != '\0') {
    if (UART_is_empty()) {     
        printChar(*string++);  
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 UART가 비어있을 때만 다음 문자를 쓰는 Busy Waiting 방식을 사용하면 너무 비효율적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778755934920&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;keyboard_ISR() {
    ch = Read keyboard input register;   
    switch (ch) {
        case 'b': startGame();           
        case 'x': doSomeProcessing();    
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 시점을 바꿔서 입력 쪽을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;startGame보다 doSomeProcessing이 훨씬 오래 걸리면 또 오류가 발생할 가능성이 높다. 다른 키를 누를 수 있으니까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 ISR 안에서는 절대 무거운 작업을 처리하면 안됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778756032506&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;keyboard_ISR() {
    *input_buffer++ = ch;   // &amp;larr; 버퍼에 저장만 (1줄!)
    // 즉시 리턴
}

// 메인 루프 어딘가에서
while (!quit) {
    if (*input_buffer) {
        processCommand(*input_buffer);   // 무거운 처리는 여기서
        removeCommand(*input_buffer);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼에 입력 문자를 일단 저장하고 ISR은 즉시 리턴한다. 무거운 처리는 메인 루프가 알아서 처리함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼는 문자의 입력속도와 프로세서의 처리속도간 차이를 분리하고, ISR 시간을 보장한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS의 Producer - Consumer 패턴과 동일..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼를 도입해서 속도 차이는 해결했지만, 그 버퍼에 여러 주체가 동시에 접근하면 또 문제가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Atomic Action과 Critical Section이 필요함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778756886890&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;; *input_buffer++ = ch 를 어셈블리 명령어로 보면... 
LDR  R0, =input_buffer    ; ① input_buffer의 현재 주소를 R0에
LDR  R1, [R0]             ; ② R0가 가리키는 곳의 값(포인터)을 R1에
STR  ch, [R1]             ; ③ R1이 가리키는 메모리에 ch 저장
ADD  R1, R1, #1           ; ④ R1을 1 증가 (포인터 ++)
STR  R1, [R0]             ; ⑤ 증가된 포인터를 다시 저장&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5단계로 쪼개진다. 그런데 여기서 2번과 5번 사이에 인터럽트가 발생한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 ISR이 2번까지 실행하고 인터럽트가 발생해 새로운 ISR이 진입한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ISR이 할거 다하고 포인터를 1 증가시키고 원래 ISR로 돌아온다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 새로운 ISR이 증가시킨 포인터를 덮어쓰고 사라지게 됨. (Race Condition)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778756993673&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;keyboard_ISR() {
    MaskInterrupts();              // ① 인터럽트 비활성화
    ch = Read keyboard input register;
    *input_buffer++ = ch;          // ② 이제 안전하게 기록
    UnmaskInterrupts();            // ③ 다시 활성화
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 아예 위험 구간에서의 인터럽트 자체를 막아버리는것도 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MaskInterrupts()를 호출하면 CPU가 인터럽트를 받지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 해결되지만 다른 중요한 ISR까지 다 지연되니.. 꼭 필요한 곳에서만 사용해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778757049690&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 메인 루프
while (!quit) {
    if (*input_buffer) {
        processCommand(*input_buffer);   // &amp;larr; 버퍼 읽기
        removeCommand(*input_buffer);    // &amp;larr; 버퍼에서 삭제
    }
}

// ISR (마스킹 처리 됨)
keyboard_ISR() {
    MaskInterrupts();
    ch = Read ACIA input register;
    *input_buffer++ = ch;
    UnmaskInterrupts();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InputBuffer에서 문자를 하나 삭제할 때 키보드 ISR이 발생하면 똑같은 문제가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;removeCommand()도 내부적으로는 여러 명령어로 이루어지니 중간에 ISR이 끼어들면 버퍼가 또 깨진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778757100006&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (!quit) {
    if (*input_buffer) {
        MaskInterrupts();                  // &amp;larr; 추가
        processCommand(*input_buffer);
        removeCommand(*input_buffer);
        UnmaskInterrupts();                // &amp;larr; 추가
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 같은 방식으로 보호해주자. MaskInterupts() 를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778757383440&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 메인이 호출
printStr(&quot;this is a line&quot;);

void printStr(char *string) {
    while (*string) {
        outputBuffer[tail++] = *string++;   // &amp;larr; 진행 중
    }
}

// 타이머 ISR
timer_ISR() {
    clockTicks++;
    printStr(convert(clockTicks));          // &amp;larr; 같은 함수를 ISR도 호출!
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 다른 문제가 발생한다. print 버퍼에 다른 ISR에서 접근하는 경우.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this is 까지만 버퍼에 기록하고 타이머 인터럽트가 발생해 clockTicks를 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 버퍼에 시간 문자열이 기록되고 버퍼가 오염된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본질은 printStr 함수가 메인과 ISR에서 동시에 실행되는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 함수가 재진입 가능하려면 모든 상태를 지역 변수로만 가지고 있어야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778757494939&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void printStr(char *string) {
    MaskInterrupts();                    // ┐
    while (*string) {                    // │
        outputBuffer[tail++] = *string++;//   │ Critical Section
    }                                    // │
    UnmaskInterrupts();                  // ┘
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 문제가 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마스킹으로 인터럽트 자체를 차단하는게 가장 단순하긴 하지만 모든게 지연되는게 단점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mutex는 인터럽트를 그대로 받지만 Task 간 동기화만 수행해줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Semaphore는 자원이 여러 개인 경우 Task간 신호를 전달할 때 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Embedded Software</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/840</guid>
      <comments>https://13months.tistory.com/840#entry840comment</comments>
      <pubDate>Thu, 14 May 2026 20:38:56 +0900</pubDate>
    </item>
    <item>
      <title>[Data Science] ETRI 휴먼이해 인공지능 논문경진대회 - 4</title>
      <link>https://13months.tistory.com/839</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dacon.io/competitions/official/236690/data&quot;&gt;https://dacon.io/competitions/official/236690/data&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778739037615&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;제 5회 ETRI 휴먼이해 인공지능 논문경진대회 - DACON&quot; data-og-description=&quot;분석시각화 대회 코드 공유 게시물은 내용 확인 후 좋아요(투표) 가능합니다.&quot; data-og-host=&quot;dacon.io&quot; data-og-source-url=&quot;https://dacon.io/competitions/official/236690/data&quot; data-og-url=&quot;https://dacon.io/competitions/official/236690/data&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/V5b8i/dJMb83SnUEu/qubPILaTUSn4nRbuKXLOqk/img.png?width=2880&amp;amp;height=1620&amp;amp;face=0_0_2880_1620&quot;&gt;&lt;a href=&quot;https://dacon.io/competitions/official/236690/data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dacon.io/competitions/official/236690/data&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/V5b8i/dJMb83SnUEu/qubPILaTUSn4nRbuKXLOqk/img.png?width=2880&amp;amp;height=1620&amp;amp;face=0_0_2880_1620');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;제 5회 ETRI 휴먼이해 인공지능 논문경진대회 - DACON&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;분석시각화 대회 코드 공유 게시물은 내용 확인 후 좋아요(투표) 가능합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dacon.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 내용을 기반으로 여러 가지 시도를 거쳤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ensemble 크기 키우기, pseudo label을 다른 방식으로 적용해보기, rank average 적용 등등..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 전혀 진전이 없었음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 내 로컬 컴에서는 Out-Of-Fold 방식으로 채점한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Train 데이터 450개를 5개의 Fold로 나누고, Valid로 번갈아 선택하는 방식임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 분명 점수가 잘뽑힘&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 데이콘에다가 제출만 하면 점수가 떨어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이콘 서버는 비공개 라벨로 채점하니까 이게 문제인듯..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델이 Train Fold에는 잘 맞지만, Test에는 잘 맞지 않는다는거임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 Out-Of-Fold 방식을 사용하면 같은 피실험자의 인접 날짜가 Train과 Valid에 동시에 있을 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 Fold 1로 학습할 때의 7-14 학습 -&amp;gt; 7-16 학습 -&amp;gt; 7-15 은 보간할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러니까 Valid 점수가 좋을 수 밖에 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 Test 환경에서는 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Test일자는 Train에 전혀 없고, 그러니 저 보간 방식이 Test에서 그대로 적용될 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 alt-paradigm CV로 이 가설을 검증해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접 일자 보간이 불가능한 Fold Split으로 학습한 후 OOF를 비교해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL9C32/dJMcafGCIkT/zAORFgfDQf7wBn5p4w5Pkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL9C32/dJMcafGCIkT/zAORFgfDQf7wBn5p4w5Pkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL9C32/dJMcafGCIkT/zAORFgfDQf7wBn5p4w5Pkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL9C32%2FdJMcafGCIkT%2FzAORFgfDQf7wBn5p4w5Pkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;504&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3가지 Fold Split 방식을 만들어서 비교해봤다. 같은 데이터, 같은 피쳐, 같은 모델.. 다만 Fold Split 로직만 다르게 진행.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 방식 모두 OOF가 점수가 높았음. 즉, Random K-Fold 방식에는 거품이 꼈다는 것..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 LB 는 Random K-Fold 방식이라 bias가 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 alt-paradigm으로 leakage를 차단하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;final&amp;nbsp;=&amp;nbsp;(1-3&amp;alpha;)&amp;nbsp;&amp;times;&amp;nbsp;cardBest&amp;nbsp;+&amp;nbsp;&amp;alpha;&amp;nbsp;&amp;times;&amp;nbsp;TimeAware&amp;nbsp;+&amp;nbsp;&amp;alpha;&amp;nbsp;&amp;times;&amp;nbsp;NoSubjId&amp;nbsp;+&amp;nbsp;&amp;alpha;&amp;nbsp;&amp;times;&amp;nbsp;SubjStratCV&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &amp;alpha;를 다양하게 설정하고 실행해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;alpha;를 5%로 설정하고 채점했을 때 0.5807&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;alpha;를 10%로 설정하고 채점했을 때 0.5812&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 확실히 성능 향상이 있었다. 비슷한 방식으로, 다른 관점의 paradigm으로도 점수를 최적화 할 수 있지 않을까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 적용한 paradigm은 Fold 구조를 바꾸는 작업이였고, 이번에 적용할 AVStrat은 각 Fold마다 Test 유사도 분포를 다르게 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;final&amp;nbsp;=&amp;nbsp;0.95&amp;nbsp;&amp;times;&amp;nbsp;each5&amp;nbsp;+&amp;nbsp;0.05&amp;nbsp;&amp;times;&amp;nbsp;AVStratCV&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWI7Vo/dJMcaiQPqr6/9kSSLhzmFeiBhwA0ZgdwPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWI7Vo/dJMcaiQPqr6/9kSSLhzmFeiBhwA0ZgdwPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWI7Vo/dJMcaiQPqr6/9kSSLhzmFeiBhwA0ZgdwPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWI7Vo%2FdJMcaiQPqr6%2F9kSSLhzmFeiBhwA0ZgdwPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1198&quot; height=&quot;86&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용 후 채점해보니 0.5806으로 미세하지만 성능이 더 좋아졌음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 좀 더 깎아보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;alt-paradigm이 제대로 작동했다면 더 Strict한 Fold Strategy를 적용해도 괜찮지 않을까? 결국 문제는 Fold 였으니까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 가설, 계산식과 결과만 간단하게 언급..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가설&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6 paradigm으로 확장해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;계산식&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;final&amp;nbsp;=&amp;nbsp;0.85&amp;nbsp;&amp;times;&amp;nbsp;cardBest&amp;nbsp;+&amp;nbsp;0.025&amp;nbsp;&amp;times;&amp;nbsp;(TA&amp;nbsp;+&amp;nbsp;NS&amp;nbsp;+&amp;nbsp;SS&amp;nbsp;+&amp;nbsp;AV&amp;nbsp;+&amp;nbsp;GroupMonth&amp;nbsp;+&amp;nbsp;LabelStrat)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;= cardBest 85% + 6 paradigm &amp;times; 2.5% each&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0.5813&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GroupMonth는 한 달을 그대로 가져가서 baseline 학습을 막는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Train과 Test는 같은 10명이고, 그 피실험자의 baseline 정보는 LB에도 실제로 도움되는데 이걸 막아버려서 오히려 성능이 떨어짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가설&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아예 K-Fold를 쓰지 말고 다른 방식을 도입해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;계산식&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 Train으로 학습하고 K-Fold Averaging을 적용하지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0.58073&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LB 점수는 거의 변화가 없었다. 다양한 신호를 섞는다고 무조건 좋아지는건 아닌듯..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K-Fold Averaging 자체가 LB를 까먹는 원인이였다면 안쓰면 좋아져야 되지 않나? 그런데 변동이 없었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 또 다른 방식을 생각해 봐야 함..&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Data Science</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/839</guid>
      <comments>https://13months.tistory.com/839#entry839comment</comments>
      <pubDate>Thu, 14 May 2026 15:50:17 +0900</pubDate>
    </item>
    <item>
      <title>[Embedded] Embedded Operating System</title>
      <link>https://13months.tistory.com/838</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS가 없으면 프로그래머가 무한루프로 직접 순서를 정해야 하지만, OS가 있으면 스케줄러가 자동으로 태스크를 실행해 멀티태스킹을 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무한루프 + 인터럽트 구조는 OS가 없는 상황에서 사용하는 코딩 컨벤션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS 가 있으면 이렇게 짤 필요가 없다. 여러 함수를 동시에 돌리는 것처럼 보이는 구조를 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우나 리눅스에서는 Process와 Thread를 나눠서 부르지만, 임베디드 OS에서는 Task라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어차피 모든 Task가 메모리 공간을 공유하니 Process와 Thread의 구분이 중요하지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PPT1T/dJMcacb1WuX/BIsRI4gntgP3ce2yRajVD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PPT1T/dJMcacb1WuX/BIsRI4gntgP3ce2yRajVD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PPT1T/dJMcacb1WuX/BIsRI4gntgP3ce2yRajVD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPPT1T%2FdJMcacb1WuX%2FBIsRI4gntgP3ce2yRajVD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;351&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS 공부할때랑 정말 비슷한.. 임베디드 OS도 일단 근본은 OS니까..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커널은 OS로 애플리케이션에 서비스를 제공한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API는 OS와 라이브러리에서 제공하는 인터페이스 함수이고, BSP는 특정 타겟 보드와 연관된 지원코드를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 작성한 코드는 모두 Application 레벨에서 실행됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS가 없는 시스템에서는 RTOS Kernel과 API층이 비어있다. Application이 Device Driver를 직접 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 OS 가 있으면 Application과 Driver사이에 OS가 끼어들어서 자원 관리를 대신해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 보드로 옮기더라도 Application 코드와 API 호출은 그대로 유지하고, BSP와 Device Driver만 보드에 맞춰서 교체할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 시스템에 OS가 없는 경우도 있다. 이런 경우 무한루프 안에서 작업을 여러 개의 Task함수로 나눠서 순서대로 실행함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트 핸들러는 우선순위가 높은 효과를 가지면서 작업을 수행한다. (Foreground / Background)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 메인 루프 안에서의 여러 Task들은 모두 같은 우선순위를 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778679280829&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* Background */
void main(void)
{
    Initialization;
    FOREVER {
        Read analog inputs;
        Read discrete inputs;
        Perform monitoring functions;
        Perform control functions;
        Update analog outputs;
        Update discrete outputs;
        Scan keyboard;
        Handle user interface;
        Update display;
        Handle communication requests;
        Other...
    }
}

/* Foreground */
ISR(void)
{
    Handle asynchronous event;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Task가 평등하고 지연 발생 시 모든 작업이 함께 멈추게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STM32F429는 싱글코어로, Cortex-M4 위에서 돌아가는 FreeRTOS는 Concurrent 멀티태스킹을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Parallel 이 아님.. Task를 교대로 실행하는 방식으로 멀티태스킹을 흉내낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS는 추상화를 제공한다. 각 Task가 자기 혼자 CPU를 독점하는 것 처럼 느끼게 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Task는 다른 Task의 존재를 신경쓰지 않아도 됨. 어차피 OS가 다 해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAhDAu/dJMcaiDi7nc/cNZozLKcYQd6aOOsUFLa61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAhDAu/dJMcaiDi7nc/cNZozLKcYQd6aOOsUFLa61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAhDAu/dJMcaiDi7nc/cNZozLKcYQd6aOOsUFLa61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAhDAu%2FdJMcaiDi7nc%2FcNZozLKcYQd6aOOsUFLa61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;383&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 레지스터는 하나밖에 없지만 OS는 다수의 Task Context를 교대로 선택해서 CPU를 사용하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 Task마다 자기 스택을 가져야 하니 메모리 비용이 발생함. Task를 너무 많이 만들면 메모리가 부족해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리가 매우 부족한 경우 각 필요한 만큼 CPU를 독점해서 실행시키는 협력형이 사용되지만, 웬만하면 CPU 시간을 Time Slice로 배분하는 선점형 방식을 사용한다. (타이머 인터럽트 사용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778679730013&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Task1(void *p) {
    while(1) { 일하기(); vTaskDelay(100); }    // &amp;larr; Task마다 자기 무한 루프
}
void Task2(void *p) {
    while(1) { 일하기(); vTaskDelay(50); }
}
void Task3(void *p) {
    while(1) { 일하기(); vTaskDelay(200); }
}

void main(void) {
    xTaskCreate(Task1, ...);     // &amp;larr; Task 등록만
    xTaskCreate(Task2, ...);
    xTaskCreate(Task3, ...);
    vTaskStartScheduler();        // &amp;larr; OS에게 맡김
    // main은 여기서 끝. 이후엔 OS가 모든 걸 관리
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS가 도입되면 소스코드를 이런 식으로 작성함. Task마다 무한루프가 작성되고 실행 순서는 OS가 결정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트 핸들러인 ISR은 항상 가장 높은 순위를 가지고, 모든 Task의 실행을 중단시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Task의 우선순위는 여러 단계 있지만 ISR은 그 무조건 우선시된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FreeRTOS는 임베디드 환경을 위한 실시간 내장형 운영체제로, 단순하고 여러 CPU에서 돌릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스코드가 4000줄 미만임 (주석제외 로직만)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티태스킹을 제공하니 여러 Task간 충돌이 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌을 막기 위해 Queue, Semaphore, Mutex 세 가지를 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐는 Task간 데이터를 주고받을 때 사용하고, Semaphore는 다수의 쓰레드가 다수의 자원을 접근하는 방법을 제어한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mutex도 마찬가지.. 그런데 OS에서 이미 다 다룬 내용이긴 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1740&quot; data-origin-height=&quot;1166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAwndc/dJMcacwl7lO/cnkSgQbCwFLILmO007kUfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAwndc/dJMcacwl7lO/cnkSgQbCwFLILmO007kUfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAwndc/dJMcacwl7lO/cnkSgQbCwFLILmO007kUfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAwndc%2FdJMcacwl7lO%2FcnkSgQbCwFLILmO007kUfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;592&quot; height=&quot;397&quot; data-origin-width=&quot;1740&quot; data-origin-height=&quot;1166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FreeRTOS 구조는 그림과 같음. CPU 독립 부분과 CPU 의존 부분으로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hardware Abstraction Layer 덕분에 새로운 CPU를 지원하려면 Port.c 부분만 새로 작성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TickType_t, BaseType_t 같은 자체 자료형을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C언어의 int 자료형은 CPU마다 다르니 같은 코드가 다르게 동작할 수 있음. 그러니 명시적으로 크기를 정한 자료형을 따로 만드는게 임베디드 코딩의 표준이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FreeRTOS API List에서 지원하는 기능을 카테고리별로 확인할 수 있으니 필요할 때 확인하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케쥴러는 ticks에 따라 CPU 시간을 태스크에 할당하고, OS의 매 Tick Interupt마다 Kernel은 다음에 할 일을 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS를 사용하면 Timer하나는 OS 전용으로 사용된다. 그러니 TIM3 TIM4 TIM10 등.. 여러 Timer 중 하나는 OS 전용이 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS의 모든 시간 흐름은 SysTick에서 시작되고, 스케쥴러를 호출하고 Ready Task 중 가장 높은 우선순위를 선택하고 실행하는 사이클이 계속해서 반복된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778681046506&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main(void)
{
    xTaskCreate(
        vTask1,      // ① 태스크 함수 포인터
        &quot;Task 1&quot;,    // ② 디버깅용 이름
        1000,        // ③ 스택 크기 (words)
        NULL,        // ④ 태스크에 전달할 파라미터
        1,           // ⑤ 우선순위
        NULL );      // ⑥ 태스크 핸들 (반환)
    
    xTaskCreate( vTask2, &quot;Task 2&quot;, 1000, NULL, 1, NULL );
    
    vTaskStartScheduler();  // OS 시작
}

void vTask1(void *pvParameters)
{
    const char *pcTaskName = &quot;Task 1 is running\r\n&quot;;
    volatile unsigned long ul;
    
    /* As per most tasks, this task is implemented in an infinite loop. */
    for( ;; )
    {
        /* Print out the name of this task. */
        vPrintString(pcTaskName);
        
        /* Delay for a period. */
        for(ul = 0; ul &amp;lt; mainDELAY_LOOP_COUNT; ul++)
        {
            /* crude delay implementation */
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Task 함수 2개 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. xTaskCreate 호출해서 우선순위 Task 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. vTaskStartScheduler로 스케쥴러 실행&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 단계가 FreeRTOS 프로그래밍의 기본 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;978&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ecs3wE/dJMcaglbsbG/5ycuQlBu9hprJQHf8RhMw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ecs3wE/dJMcaglbsbG/5ycuQlBu9hprJQHf8RhMw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ecs3wE/dJMcaglbsbG/5ycuQlBu9hprJQHf8RhMw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fecs3wE%2FdJMcaglbsbG%2F5ycuQlBu9hprJQHf8RhMw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;628&quot; height=&quot;412&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 우선순위는 Tick Interrupt 서비스에 따라 라운드 로빈 방식으로 실행이 바뀐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위가 다른 경우이더라도, Task가 일을 하지 않을 때는 자발적으로 CPU를 양보하는 구조를 작성해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Busy Waiting방식을 사용하기도 하지만.. vTaskDelay(x)API를 호출해 현재 태스크를 X Tick만큼 지연시키는 방식이 더 합리적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Busy Waiting은 CPU를 계속 점유하면서 다른 Task를 차단해 높은 우선순위의 Task만 실행될 수 있지만, vTaskDelay 방식은 낮은 우선순위 Task도 실행될 기회를 얻는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Embedded Software</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/838</guid>
      <comments>https://13months.tistory.com/838#entry838comment</comments>
      <pubDate>Wed, 13 May 2026 23:13:13 +0900</pubDate>
    </item>
    <item>
      <title>[Embedded] Motor</title>
      <link>https://13months.tistory.com/837</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모터는 PWM으로 속도를 조절하고 인코더로 회전 결과를 측정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PWM은 출력이고 인코더는 입력으로, 두 가지가 한 쌍을 이뤄야 정확한 제어가 가능함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PWM, Timer 등 지난번에 센서를 공부할 때 다뤘던 내용들이 모터에 그대로 등장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 모터의 회전을 측정하는 인코더와 보정 파라미터를 찾는 Calibration이 새로 도입됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1020&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qYpFV/dJMcabK0Flt/kas5lEo2owj13H2zBNk9pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qYpFV/dJMcabK0Flt/kas5lEo2owj13H2zBNk9pK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qYpFV/dJMcabK0Flt/kas5lEo2owj13H2zBNk9pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqYpFV%2FdJMcabK0Flt%2Fkas5lEo2owj13H2zBNk9pK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;430&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1020&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DC 모터는 자석에 흐르는 전류의 방향과 세기를 조절해 모터에 회전력을 발생시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전류의 방향이 회전 방향을 결정하고, 전류의 세기가 회전 속도를 결정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 전류를 어떻게 조절하는지가 핵심.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인코더는 모터의 회전 방향과 이동거리 계산을 위해 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모터에 전류를 줘서 돌리더라도, 얼마나 돌았는지 계산해야 한다. 그러니 이 측정을 인코더가 담당함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가변 저항으로 전압 자체를 줄이거나 PWM으로 ON/OFF 를 빠르게 반복하면 모터의 전압을 조절할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방법 중 PWM을 사용하면 전력 손실도 없고 효율도 좋음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지에서 Duty Cycle이 곧 속도가 됨. 그러니 저걸 조절하면 모터 속도가 조절된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 초음파센서를 다룰 때 Trigger 신호 길이를 조절할 때와 같은 방식으로 PWM 기능을 사용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;1138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cng73I/dJMcaf7DugK/eIhWrjNCMKS12RZJQ2xpx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cng73I/dJMcaf7DugK/eIhWrjNCMKS12RZJQ2xpx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cng73I/dJMcaf7DugK/eIhWrjNCMKS12RZJQ2xpx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcng73I%2FdJMcaf7DugK%2FeIhWrjNCMKS12RZJQ2xpx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;490&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;1138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인코더 때문에 선이 6개 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모터 전원 관련 2개 / 인코더 전원 관련 2개 / 인코더 출력 관련 2개로 구성됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정방향으로 돌리려면 +쪽에 전압을 주고 역방향으로 돌리려면 -쪽에 전압을 줘야 한다. 그러니 두 선 모두 제어할 수 있어야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신호 하나로는 회전 방향을 알 수 없으니 A와 B 두 신호의 위상 차이로 방향을 알아냄.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MC_EN은 PB2에 연결하는데, 모터에 전원을 공급할지 말지를 결정하는 마스터 스위치 역할을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어를 직접 다루는거니 안전에 주의해야 함. 전원을 켜자마자 모터가 돌면 위험하니 PB2를 low로 두면 안전하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;센서를 다룰 때는 echo 측정 시 Timer Input Capture를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인코더 측정에서는 EXTI 외부 인터럽트를 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방법 모두 가능함. Timer의 Encoder Mode라는 전용 기능을 사용해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 uBrain 코드에서는 이해하기 쉽고 직관적인 방식인 EXTI 외부 인터럽트를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Crc3U/dJMcacQCHgg/BaPZD1b8okZfJ89sAkYcQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Crc3U/dJMcacQCHgg/BaPZD1b8okZfJ89sAkYcQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Crc3U/dJMcacQCHgg/BaPZD1b8okZfJ89sAkYcQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCrc3U%2FdJMcacQCHgg%2FBaPZD1b8okZfJ89sAkYcQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;282&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;786&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 하드웨어의 스펙 표가 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모터 한개에 채널 두개가 연결됨. + / - 모터 두 선 모두 제어해야 하니까..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STM32 핀에서 나오는 전기로는 모터를 돌릴 수 없으니 CMOS 전압과 전류를 모터 구동을 위한 전류로 변환해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 모터 드라이버 칩인 L6227Q를 사용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yiPJP/dJMcahYHuZ1/wB8NmpWdBtQVOnBnkCuXX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yiPJP/dJMcahYHuZ1/wB8NmpWdBtQVOnBnkCuXX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yiPJP/dJMcahYHuZ1/wB8NmpWdBtQVOnBnkCuXX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyiPJP%2FdJMcahYHuZ1%2FwB8NmpWdBtQVOnBnkCuXX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;254&quot; height=&quot;447&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPIO 포트의 각 핀은 그룹으로 묶이고 EXTI0 ~ EXTI15 까지 16개의 외부인터럽트를 발생시킬 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPIO 핀이 변하면 EXTI 회로가 감지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;센서의 Input Capture는 언제 변했는지 정확한 시간도 기록하지만, EXTI는 변했다는 사실만 알려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회로에서의 규칙은 EXTI 번호는 핀 번호의 끝자리와 같다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 번호의 EXTI는 한 번에 하나의 포트만 쓸 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 핸들러 이름은 좀 다른데, 인터럽트 벡터 슬롯을 절약하기 위해서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXTI0 ~ EXTI4 까지는 각각 다른 핸들러를 사용하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXTI5 ~ EXTI9 는 묶어서 하나의 핸들러로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EXTI10 ~ EXTI15 까지도 묶어서 하나의 핸들러로 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hall 효과는 자기장 속에 전류가 흐르는 도체를 두면 전류와 자기장 양쪽에 수직 방향으로 전압이 발생하는 현상이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hall 센서를 사용해 자기장 변화를 감지하고 출력으로 펄스를 발생시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zhmWe/dJMcahdltYy/jEtE2pwPaFhlHMdbPRlgd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zhmWe/dJMcahdltYy/jEtE2pwPaFhlHMdbPRlgd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zhmWe/dJMcahdltYy/jEtE2pwPaFhlHMdbPRlgd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzhmWe%2FdJMcahdltYy%2FjEtE2pwPaFhlHMdbPRlgd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;475&quot; height=&quot;174&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 센서를 90도로 위상차로 배치한다. 이러면 어느 신호가 먼저 변하는지 파악할 수 있고, 이를 통해 방향을 결정할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;uBrain의 모터는 1회전에 26개의 펄스가 생성되니 A입력의 펄스를 카운트하고 회전당 펄스 수를 나누면 전체 회전수를 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778677778113&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    switch(GPIO_Pin)
    {
        case GPIO_PIN_15:  // PA15, 오른쪽 인코더 A
            encoder_right = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3);  // B 읽기
            if(encoder_right == 0)  // B=0 &amp;rarr; Forward
            {
                motorInterrupt1++;
                encoder_right = READY;
            }
            else if(encoder_right == 1)  // B=1 &amp;rarr; Backward
            {
                motorInterrupt1--;
                encoder_right = READY;
            }
            break;
        // (case GPIO_PIN_4 는 다음 슬라이드에서)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A가 변한 순간 B를 읽고, 상태 변수를 READY로 표시해 다음 인터럽트를 받을 준비를 마친다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모터가 한 바퀴 회전했을 때, 인코더 신호로부터 계산된 카운터의 변화량에 따른 이동거리는 모터의 상태에 따라 다르니 인코더 값을 측정한 후 모터의 상태에 따라 코드를 조절해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 차이는 소프트웨어로 측정할 수 없으니 Calibration이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어제 잘 됐다고 오늘 잘 될거라는 보장이 없으니.. 매번 Calibration을 해 줘야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IR 센서를 사용할 때 Lookup 테이블이 필요했는데, 저것도 일종의 Calibration이다. 센서와 액추에이터는 실제로 돌려보면 이론이랑 다르니 꼭 필요함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Embedded Software</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/837</guid>
      <comments>https://13months.tistory.com/837#entry837comment</comments>
      <pubDate>Wed, 13 May 2026 22:21:44 +0900</pubDate>
    </item>
    <item>
      <title>[Embedded] Sensor</title>
      <link>https://13months.tistory.com/836</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;센서는 아날로그 현상을 디지털 값으로 바꾸는 역할을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;센서가 어떤 물리량을 어떻게 측정하는지 이해하고, 출력 신호를 MCU의 어떤 자원으로 받아들일지 결정해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핸드폰만 해도 카메라, 지문인식, 화면 회전을 위한 가속도계, 습도 및 조도 센서, GPS 등 굉장히 많은 센서가 들어있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 각 센서마다 측정하는 물리량과 용도가 다 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AXLM(가속도계)와 Gyro(자이로스코프)는 항상 pair로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자이로스코프는 축을 중심으로 한 회전운동을 의미하고, 가속도계는 축 방향으로의 직선운동을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핸드폰을 들고 위로 올리면 직선이동이니 가속도계가 감지하고, 손목을 비틀면 회전이니 자이로스코프가 감지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지가 함께 사용되어야 핸드폰을 잡은 자세를 파악할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 두 가지를 측정할 때 측정 단위에 주의하자. 센서 값을 의미 있는 숫자로 바꾸려면 단위를 명확하게 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자이로스코프와 가속도계는 측정 대상은 다르지만 측정 방식은 똑같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MEMS&lt;/b&gt;는 물체의 공간이동 변위를 측정하는 회로로, 구현 축당 변위값을 ADC를 거쳐 디지털 신호로 변환함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MEMS 가속도계 안에는 작은 덩어리가 스프링에 매달려있고, 센서를 흔들면 틀은 오른쪽으로 가지만 덩어리는 관성 때문에 제자리를 유지하려고 한다. 그러니 덩어리가 틀 기준으로 왼쪽으로 밀린 것 처럼 보임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;센서는 가속도의 수치를 측정하는게 아니고 덩어리가 얼마나 밀렸는지를 측정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 저 밀린 정도를 전기 신호로 바꾸고 ADC로 디지털화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책상 위에 가만히 놓인 가속도계는 1g를 측정한다. 중력이 작용하니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핸드폰을 옆으로 눕히면 1g 벡터가 옆을 가리키고 폰을 가로 모드로 인식을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자이로스코프도 같은 원리. 똑같이 변위를 측정하지만, 변위를 만드는 힘이 좀 다를 뿐이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwXrdf/dJMcaiDiPuA/3QdniT7UwcIQkEWxz6TykK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwXrdf/dJMcaiDiPuA/3QdniT7UwcIQkEWxz6TykK/img.png&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;610&quot; data-is-animation=&quot;false&quot; width=&quot;582&quot; height=&quot;310&quot; style=&quot;width: 54.2328%; margin-right: 10px;&quot; data-widthpercent=&quot;54.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwXrdf/dJMcaiDiPuA/3QdniT7UwcIQkEWxz6TykK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwXrdf%2FdJMcaiDiPuA%2F3QdniT7UwcIQkEWxz6TykK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1146&quot; height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYI8LC/dJMcaiJ2isY/G8vRHQKguzMmAOonewDxf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYI8LC/dJMcaiJ2isY/G8vRHQKguzMmAOonewDxf0/img.png&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;598&quot; data-is-animation=&quot;false&quot; style=&quot;width: 44.6044%;&quot; data-widthpercent=&quot;45.13&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYI8LC/dJMcaiJ2isY/G8vRHQKguzMmAOonewDxf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYI8LC%2FdJMcaiJ2isY%2FG8vRHQKguzMmAOonewDxf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;924&quot; height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MEMS -&amp;gt; AC 증폭 -&amp;gt; DEMOD -&amp;gt; 출력 증폭 -&amp;gt; 출력 (Xout, Yout, Zout)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X Y Z 세 축의 가속도를 각각 아날로그 전압으로 내보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3개의 아날로그 출력은 아두이노의 A0 A1 A2 핀으로 받는다. A 시리즈 핀은 아두이노의 ADC가 연결된 핀.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;센서가 아날로그 출력을 내보내면 MCU는 ADC를 사용해야 하고, IR 센서에서도 마찬가지로 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초음파 센서처럼 디지털 Pulse를 내보내면 Timer / Input Capture를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7mBWF/dJMcaipMEsF/KjSHpgr5kitYIUEJREoyTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7mBWF/dJMcaipMEsF/KjSHpgr5kitYIUEJREoyTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7mBWF/dJMcaipMEsF/KjSHpgr5kitYIUEJREoyTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7mBWF%2FdJMcaipMEsF%2FKjSHpgr5kitYIUEJREoyTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;319&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드는 기기 스펙이 전부니까.. 센서 스펙을 보고 이해할 수 있어야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자이로스코프도 가속도계와 똑같이 MEMS 기술을 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 칩 내부에 ADC가 들어있는지 아님 외부에 들어있는지의 차이와 출력 방식만 좀 다르다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가속도계와 자이로스코프는 현재 어떻게 움직이고 있는지를 측정하고, 초음파 거리센서 SRF04는 내 앞에 뭐가 있는지를 측정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;송신기, 수신기, 제어회로를 사용한다. 초음파를 쏘고 그 반사음이 돌아오는 시간을 듣고 거리를 측정함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;40kHz 를 사용해 사람 귀에는 들리지 않고, 짧은 파장이라 작은 물체도 감지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 가까우면 송신과 수신이 겹치고 너무 멀면 반사파가 너무 약해서 감지할 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. CPU -&amp;gt; SRF04 신호 전송&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. SRF04가 초음파를 쏘고 echo 핀을 high로 설정&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. SRF04에게 반사파가 도착하고 echo 핀을 low로 설정&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. echo 펄스의 길이를 측정해서 거리 계산&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 시간 초과 시 자동 리셋&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Timer의 Input Capture 모드로 echo 핀이 high로 있던 시간을 측정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 멀어서 반사파가 돌아오지 않으면 36ms 까지만 기다리고 알아서 low로 떨어짐.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리는 아날로그 데이터지만, 디지털 데이터인 시간으로 바꿔서 MCU가 측정할 수 있도록 다룬다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg6qIl/dJMcahxEz73/WBdKVQsX5Tsy4gFl7F6Ow0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg6qIl/dJMcahxEz73/WBdKVQsX5Tsy4gFl7F6Ow0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg6qIl/dJMcahxEz73/WBdKVQsX5Tsy4gFl7F6Ow0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg6qIl%2FdJMcahxEz73%2FWBdKVQsX5Tsy4gFl7F6Ow0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;558&quot; height=&quot;346&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 Trigger는 CPU가 만들고 SRF04에게 준다. 즉, 측정을 시작하라는 명령을 내림.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Trigger를 받으면 SRF04가 알아서 초음파를 쏜다. 이거는 SRF04 내부 회로가 알아서 만드니 CPU랑은 무관함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;echo는 SRF04가 CPU에게 알려주는 신호. 초음파를 쏘는 순간 echo 핀을 high로 올리고, 반사파가 돌아온 순간 echo 핀을 low로 내린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STM32의 Timer는 PWM출력과 Input Capture를 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Trigger를 만드는 작업과 echo를 측정하는 작업을 Timer가 수행하고, CPU는 그동안 다른 일을 처리하는 방식임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 Timer는 한 가지 모드로만 동작한다. 내부 카운터를 어떻게 활용하는지가 모드와 연관됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PWM 모드에서는 카운터가 특정 값일 때 핀을 high/low로 바꾸는 작업을, Input Capture 모드에서는 핀이 변할 때 카운터 값을 기록.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 echo 3개에 Timer가 3개 있어야 할 것 같지만..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TIM3은 채널이 4개 있고, 각 채널은 독립적으로 같은 카운터를 공유하면서 Input Capture를 수행할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCU 핀 하나도 여러 기능으로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PF6핀은 일반 GPIO로 사용할 수 있고, AF를 설정해두면 TIM10_CH1으로도 쓸 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 회로도와 데이터시트를 함께 보고 설계해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Input Capture는 Timer 내부 카운터를 사용해 핀이 변하는 순간 카운터 값을 CCRx 레지스터에 복사한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Risign Edge에서 T1을 캡쳐하고 Falling Edge에서 T2를 캡쳐. 그리구 T2 -T1이 캡쳐 길이가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778658902627&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TimHandle1.Instance       = TIM3;              // 어떤 타이머?
TimHandle1.Init.Period    = 0xFFFF;            // 카운터 최댓값
TimHandle1.Init.Prescaler = uwPrescalerValue;  // 클럭 분주값
TimHandle1.Init.ClockDivision = 0;
TimHandle1.Init.CounterMode   = TIM_COUNTERMODE_UP;  // 0&amp;rarr;max 방향

HAL_TIM_IC_Init(&amp;amp;TimHandle1);  // 위 설정으로 초기화

sICConfig1.ICPolarity  = TIM_ICPOLARITY_RISING;    // Rising Edge에서 캡처
sICConfig1.ICSelection = TIM_ICSELECTION_DIRECTTI; // 직접 입력
sICConfig1.ICPrescaler = TIM_ICPSC_DIV1;           // 입력 분주 안 함
sICConfig1.ICFilter    = 0;                        // 필터 없음

// uBrain의 초음파는 3개 각각 TIM3의 2,3,4 Channel을 사용
HAL_TIM_IC_ConfigChannel(&amp;amp;TimHandle1, &amp;amp;sICConfig, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&amp;amp;TimHandle1, TIM_CHANNEL_2);
HAL_TIM_IC_ConfigChannel(&amp;amp;TimHandle1, &amp;amp;sICConfig, TIM_CHANNEL_3);
HAL_TIM_IC_Start_IT(&amp;amp;TimHandle1, TIM_CHANNEL_3);
HAL_TIM_IC_ConfigChannel(&amp;amp;TimHandle1, &amp;amp;sICConfig, TIM_CHANNEL_4);
HAL_TIM_IC_Start_IT(&amp;amp;TimHandle1, TIM_CHANNEL_4);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 코드 작성은 굉장히 쉽다.. 구조체에 값 채우고 HAL 함수 몇개 호출하면 끝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카운터가 알아서 돌고 핀이 변하면 알아서 캡쳐하고 캡쳐되면 알아서 인터럽트 발생하고..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IR 센서는 적외선 쏘고 반사된 양을 ADC로 읽는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초음파는 시간을 측정하고.. IR은 빛의 양을 측정하고..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 측정이라도 출력 형태가 다르면 MCU 자원도 다르다. 출력이 비선형이니 Lookup 테이블으로 보간이 필요하긴 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Embedded Software</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/836</guid>
      <comments>https://13months.tistory.com/836#entry836comment</comments>
      <pubDate>Wed, 13 May 2026 17:01:01 +0900</pubDate>
    </item>
    <item>
      <title>[Embedded] Communication Programming</title>
      <link>https://13months.tistory.com/835</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STM32 에서 UART를 사용하려면 4가지 단계를 거쳐야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. GPIO를 Alternate Function으로 Multiplexing&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. USART 모듈을 활성화하고 송수신 모드 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Baud Rate를 계산하고 BRR 레지스터에 작성&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. TXE 및 RXNE 플래그 기반으로 송수신&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ7N1G/dJMcadaRfw0/2YeJ59QQPLGRjmluF3M1n1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ7N1G/dJMcadaRfw0/2YeJ59QQPLGRjmluF3M1n1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ7N1G/dJMcadaRfw0/2YeJ59QQPLGRjmluF3M1n1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ7N1G%2FdJMcadaRfw0%2F2YeJ59QQPLGRjmluF3M1n1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;687&quot; height=&quot;298&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;790&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STM32F429xx 에는 USART 및 UART가 8개 들어있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개 모두 섞여있다. STM32는 동기 모드도 지원함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;APB1과 APB2는 속도가 다름. 각각 저속, 고속을 담당하고 USART1과 USART6은 빠른 버스에 붙어 baud rate가 높음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STM32의 핀 하나는 기본 GPIO 외 16가지 Alternate Function 중 하나로 사용될 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전에 다룬 USART CAN I2C 등 통신 모듈을 사용하려면 GPIO 핀을 해당 통신용 AF로 멀티플렉싱해서 통신 모듈에 빌려줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MODER - OTYPER - PUPDR - OSPEEDR - AFRL/AFRH 순서를 거쳐서 GPIO를 AF로 멀티플렉싱한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 모듈을 별도 핀에 할당하면 핀이 정말 많이 필요하니 핀 하나를 하나의 역할로 골라서 사용하는 전략을 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 GPIO로 쓰더라도 부팅 후에는 USART2_TX, 다른 보드에서는 SPI1_MOSI 이렇게 플젝마다 다르게 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;918&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QPfoU/dJMb997qKJ8/oevfoLvgYCVkymvQdKiIB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QPfoU/dJMb997qKJ8/oevfoLvgYCVkymvQdKiIB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QPfoU/dJMb997qKJ8/oevfoLvgYCVkymvQdKiIB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQPfoU%2FdJMb997qKJ8%2FoevfoLvgYCVkymvQdKiIB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;537&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핀 안에는 MUX 회로가 들어있어 16개의 입력 중 하나를 고를 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리셋 시 핀은 기본 GPIO 모드인 AF0로 설정된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USART 송신은 USART_DR에 데이터를 쓰면 알아서 하드웨어가 Shift Register로 옮기고 비트 단위로 Tx 핀에 토글한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상세 절차는 아래 그림과 같음 (순서대로 해야함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1638&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IM1Pf/dJMcahLaRoL/GgCrc8RIYOKwE7PzqFiBXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IM1Pf/dJMcahLaRoL/GgCrc8RIYOKwE7PzqFiBXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IM1Pf/dJMcahLaRoL/GgCrc8RIYOKwE7PzqFiBXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIM1Pf%2FdJMcahLaRoL%2FGgCrc8RIYOKwE7PzqFiBXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;310&quot; data-origin-width=&quot;1638&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 쓰면 하드웨어가 옮길 때 까지 기다려야 하는데. ABC 를 쓴다고 하자. A를 쓰고 언제 B를 써야 할까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 TXE비트 로 처리한다. (Transmit data register Empty)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TXE가 1이면 다음 걸 받을 수 있다는 뜻이고 TXE가 0이면 처리 중이라는 뜻.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 완전히 끝났으면 TC비트를 사용한다. USART 끄기 직전에 TC 비트 1을 기다리고 Shift Register까지 비어있음을 확인함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USART 수신은 송신을 거꾸로 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Rx 핀 -&amp;gt; Shift Register -&amp;gt; RDR -&amp;gt; USART_DR 읽기&lt;/b&gt; 순서대로 진행됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 도착하면 RXNE 비트가 1로 알려주고, 내가 읽으면 자동으로 0처리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;송신에서의 활성화 비트는 TE지만 수신에서의 활성화 비트는 RE를 사용하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RXNEIE를 1로 설정하면 RXNE가 1로 될 때 인터럽트가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;USART_SR&lt;/b&gt; 은 Status Register로 지금 USART가 어떤 상태인지를 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TXE TC RXNE&lt;/b&gt; ORE FE 등..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;USART_CR1은&lt;/b&gt; Control Register로 USART를 어떻게 동작시킬지를 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UE M TE RE 및 인터럽트 활성화 비트 등이 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;USART_BRR&lt;/b&gt; 은 Baud Rate Register로 통신 속도를 어느정도로 정할지를 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Baud Rate는 USART 입력 Clock을 USARTDIV 값으로 나눈 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mantissa + Fraction으로 BRR 레지스터에 저장되고, Mantissa만 쓰면 baud rate가 부정확해서 소수점 이하를 분할함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STM32의 USART는 고정된 Clock 신호를 입력받지만 통신 상대는 9600bps같은 속도를 원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 고속 Clock을 나눠서 원하는 속도를 만드는 방식을 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5hEeP/dJMcadaRgoZ/TeVI8GLOmrh5KYpU5y5fq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5hEeP/dJMcadaRgoZ/TeVI8GLOmrh5KYpU5y5fq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5hEeP/dJMcadaRgoZ/TeVI8GLOmrh5KYpU5y5fq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5hEeP%2FdJMcadaRgoZ%2FTeVI8GLOmrh5KYpU5y5fq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;96&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OVER8 비트가 0이면 16배 오버샘플링이고 1이면 8배 오버샘플링을 적용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Embedded Software</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/835</guid>
      <comments>https://13months.tistory.com/835#entry835comment</comments>
      <pubDate>Tue, 12 May 2026 23:57:20 +0900</pubDate>
    </item>
  </channel>
</rss>