# Career Portfolio - 이강수 최근의 좌우명은 "What you eat, how you think, and most importantly what you have done become who you are. Who are you? and who will you be?" ## PH
  • 2017-03-21 : 정리.
  • 2016-03-16 : 정리.
  • 2015-12-23 : 대충 좀 더 정리.
  • 2015-12-18 : First posting.
## TOC ##[.no-sec-N#sec-CV] Curriculum vitae (이력서)
SNU
### Some other remarks
  • Feb. 2008 ~ Spring 2010: Programmed plenty of Labview, C++ programs. Almost of them analyze image files taken from microscope with vector calculus. Some of them compile statistics on properties of magnetic domain.
  • Jan. 2010: Organized ‘3rd BK21 Young Physicists Workshop’. A committee of arrangements.
### Papers published #### Truncated many-body dynamics of interacting bosons: A variational principle with error monitoring Read More : http://www.worldscientific.com/doi/abs/10.1142/S0217979215500216 This is one of my favorite papers published, although many would not understand this well enough.
#### Emergence of a new pair-coherent phase in many-body quenches of repulsive bosons
#### Universality Classes of Magnetic Domain Wall Motion
#### Long-Range Domain Wall Tension in Pt/Co/Pt Films with Perpendicular Magnetic Anisotropy
## Recoeve.net 최근까지 개발했었던 서비스. Fuzzy search, Multi-Categorized Records 등이 핵심 포인트. Vert.x JAVA server + MySQL JDBC (Java DataBase Connector) + Javascript, jQuery, AJAX 등 이용하여 개발. 개발에 쓰인 코드들은 github.com/kipid/Recoeve 에서 열람 가능합니다. history.pushState 를 이용해서 페이지를 새로 띄우지 않고 내부적으로 이동하도록 디자인 했습니다. 개발하면서 정리했던 Recoeve database setup 도 참고하시기 바랍니다. Machine learning 을 이용한 user-collaborative recommendation 이 핵심. Self-customizing + Multi-Categorized Records, or Scrapbook, for Everything, and Personalized Recommendation for Everything at each Category, which can be called Computer-Assisted Cloud/Crowd Curating.
### Fuzzy search Fuzzy search 를 이용해 자신이 reco 했던 것들을 쉽게 다시 찾을 수 있도록 만들었습니다.
### Structured and Multi Categorization Tag 기능과 비슷하지만 상하위 구조를 가지는 (structured) categorization 이 가능하도록 만들었습니다. Tag 처럼 한 reco 에 여러 category 를 구분자 ";"를 통해 지정할 수 있습니다. Category 를 입력할때도 fuzzy search 의 도움을 받을 수 있도록 구현하였습니다.
Reco 의 category 부분 link 를 통해서도 category jump 가 가능하도록 만들었습니다.
### Change orders of category list Category list 의 위치를 user 가 쉽게 바꿀 수 있도록 디자인하고 구현하였습니다. 제 페이지 http://recoeve.net/user/kipid 에서 테스트 해보실 수 있습니다. (본인 페이지가 아니더라도 category list 위치를 수정할 수 있게 디자인하였습니다. 자기 페이지가 아닌만큼 이 순서는 페이지 새로고침 전까지만 유지됩니다. 새로고침하면 원래 user 의 category list 순서대로 다시 돌아옵니다.)
### Pattern replace 를 통한 다국어 지원 Pattern replace 를 통해 다국어 지원이 쉽도록 디자인 하였습니다.
[--Pattern--] 형태를 찾아 다국어 replace. 아래는 코드 일부분. ```[.linenums.scrollable.lang-java] public static final Pattern ptnReplacer=Pattern.compile("\\[--[\\s\\S]+?--\\]"); public static final Pattern ptnVariable=Pattern.compile("\\{--[\\s\\S]+?--\\}"); static { fileMap=new HashMap<String, Map<String, ArrayList<String>>>(fileMapSize); File file=null; String fileStr=null; file=new File(filePath+"lang.txt"); if (file.exists()) { try { StringBuilder sb=new StringBuilder(); int ch; FileReader reader=new FileReader(file); while((ch=reader.read())!=-1) { sb.append((char)ch); } reader.close(); fileStr=sb.toString(); } catch (IOException e) { System.out.println(e); } finally { file=null; } } StrArray langMap=new StrArray(fileStr, true, true); // System.out.println(langMap); fileStr=null; for (String fileName: fileNames) { file=new File(filePath+fileName); if (file.exists()) { try { StringBuilder sb=new StringBuilder(); int ch; FileReader reader=new FileReader(file); while((ch=reader.read())!=-1) { sb.append((char)ch); } reader.close(); fileStr=sb.toString(); } catch (IOException e) { System.out.println(e); } finally { file=null; } } if (fileStr!=null) { // System.out.println("\nfileName : "+fileName); fileMap.put(fileName, new HashMap<String, ArrayList<String>>(fileLangMapSize)); Map<String, ArrayList<String>> fileLangMap=fileMap.get(fileName); ArrayList<String> strListVars=new ArrayList<String>(); Matcher matchVariable=ptnVariable.matcher(fileStr); // default int start=0; while (start<fileStr.length()) { if (matchVariable.find(start)) { strListVars.add(fileStr.substring(start, matchVariable.start())); strListVars.add(matchVariable.group()); start=matchVariable.end(); } else { strListVars.add(fileStr.substring(start)); start=fileStr.length(); } } fileLangMap.put("df", strListVars); // default. ArrayList<String> strList=new ArrayList<String>(); Matcher matchReplacer=ptnReplacer.matcher(fileStr); start=0; while (start<fileStr.length()) { if (matchReplacer.find(start)) { strList.add(fileStr.substring(start, matchReplacer.start())); strList.add(matchReplacer.group()); start=matchReplacer.end(); } else { strList.add(fileStr.substring(start)); start=fileStr.length(); } } if (strList.size()>1) { int colSize=langMap.getColSizeAtRow(0); for (int k=2;k<colSize;k++) { String lang=langMap.get(0,k); if (!lang.equals("desc")) { String strReplaced=""; String replaced=null; for (int i=0;i<strList.size();i++) { if (i%2==0) { strReplaced+=strList.get(i); } else { replaced=langMap.get(strList.get(i), lang); if (replaced==null||replaced.isEmpty()||replaced.equals("-")) { replaced=langMap.get(strList.get(i), "en"); // "en" is default lang. } if (replaced==null) { replaced=strList.get(i); } strReplaced+=replaced; } } strListVars=new ArrayList<String>(); matchVariable=ptnVariable.matcher(strReplaced); // [--lang--] replaced start=0; while (start<strReplaced.length()) { if (matchVariable.find(start)) { strListVars.add(strReplaced.substring(start, matchVariable.start())); strListVars.add(matchVariable.group()); start=matchVariable.end(); } else { strListVars.add(strReplaced.substring(start)); start=strReplaced.length(); } } fileLangMap.put(lang, strListVars); // after replacing langMap. } } } fileStr=null; } } } public FileMapWithVar() {} public static String get(String fileName, String lang, Map<String,String> varMap) { Map<String, ArrayList<String>> fileLangMap=fileMap.get(fileName); if (fileLangMap==null) {return null;} ArrayList<String> strList=fileLangMap.get(lang); if (strList==null) { strList=fileLangMap.get("df"); } String res=""; String replaced=null; for (int i=0;i<strList.size();i++) { if (i%2==0) { res+=strList.get(i); } else { replaced=varMap.get(strList.get(i)); if (replaced==null) { replaced=strList.get(i); } res+=replaced; } } return res; } ```/ ### Recoeve.net as a playlist of YouTubes and videos Youtube API 를 이용해서 자신이 reco 한 youtube 영상들을 연속으로 재생할 수 있게 해놓았습니다. 1개의 동영상만 반복해서 재생할수도 있고, 전체 영상을 반복해서 재생할수도 있게 디자인했고, Shuffle 기능도 구현해 놨습니다. Reco 해 놓은 youtube 영상이 재생될 수 없는 경우에는 1초뒤 다음 영상으로 재생되도록 error handling 도 해 놓았습니다.
테스트는 http://recoeve.net/user/kipid?cat=[Music/Break]--K-Pop 에서 해보실 수 있습니다. "Toggle reco list play" 버튼을 눌러보세요. ### Side widget Side widget 을 만들어서 어느 위치에서든 Go (Fuzzy search), Forward, Backward, New Reco 가 쉽도록 디자인 하였습니다.
### Recoeve widget (Recoeve 로 내보내기) Recoeve widget 을 만들어서 twitter 나 facebook 처럼 SNS 내보내기 가 가능하도록 만들었습니다.
### Editting reco Reco 의 수정이 쉽도록, 그리고 바로 화면에 반영되도록 구현하였습니다.
### 동영상과 가사 함께보기 Reco description 에 #lyrics 를 통해 가사를 입력하면 Toggle lyrics 버튼과 함께 가사를 접었다 펼 수 있게 디자인했습니다. 동영상은 stick to the left top 버튼을 통해 왼쪽 위에 붙일 수 있도록 만들었습니다.
### Scalable design 스마트폰에서도 잘 동작하도록 CSS media query 를 통해 Responsible/Scalable 하게 디자인 하였습니다. 사이트를 방문하셔서 직접 테스트 해보세요.
아래는 사용된 CSS. ```[.linenums.scalable.lang-css] @media all and (min-width:701px) { #container {margin-left:14.9em} #sidebar {margin:0; position:fixed; left:0; top:0; bottom:0; width:15em} #sidebar-dragger {display:none} #sidebar-exit {display:none} .side2 {padding:.5em} .rC.fixed {width:646px; border-right:.15em solid black} .lyrics {text-align:right} ::-webkit-scrollbar {width:11px; height:11px} } @media all and (min-width:901px) { #container {margin-left:19.9em} #sidebar {width:20em} } @media all and (min-height:500px) { #fuzzy-search-list {max-height:430px;} } ```/ ### 로그인 암호 해킹 방지 시스템 Iteration 이 들어가는 단방향 암호화 (Hash) 를 이용해서 네트워크 중간에 가로채는 해킹에 대해서도 어느정도 면역이 생기게 디자인하였습니다. User 쪽 javascript 단에서 처음에는 10000 iteration 해서 보내고. 다음부터는 9999 iteration 해서 보내고 나머지는 server 에서 iteration 통해 암호가 일치하는지 확인하는 방법. 사용자 암호가 털리지 않는한, 네트워크 중간에서 가로챈 암호화 된 암호 가지고도 해킹이 불가능하게 디자인. 단 user 쪽 iteration 은 항상 줄어들어야 함. 안그러면 hash function 이 javascript 에 노출되므로 뒷쪽 iteration 을 유추가능. Server 의 user data 에는 iteration 정보를 저장하고 있어야 하고, user 가 로그인할때 id/e-mail 만 AJAX 로 먼저 보내서 암호 iteraion 을 몇번할 것인지 받아낸 다음 iteration 으로 암호화 후 전체 데이터 전송. 아래는 코드 일부분. ```[.linenums.scrollable.lang-javascript] eve.encrypt=function(salt, pwd, iter) { iter=pwd.length+131+((iter&&iter.constructor==Number&&iter>=0)?iter:0);; pwd=salt+pwd; var h1=eve.hash1(pwd); var h2=eve.hash2(pwd); var h3=eve.hash3(pwd); var h4=eve.hash4(pwd); var h5=eve.hash5(pwd); var h6=eve.hash6(pwd); var h7=eve.hash7(pwd); var h8=eve.hash8(pwd); var h9=eve.hash9(pwd); var h10=eve.hash10(pwd); var h11=eve.hash11(pwd); var h12=eve.hash12(pwd); var h13=eve.hash13(pwd); var tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13; for (var i=0;i<iter;i++) { tmp1=h13+h12+h11+h10+h9+salt+h8+h7+h6+h5+h4+h3+h2+h1; tmp2=h1+h3+salt+h2; tmp3=salt+h2+h8+h1+h3; tmp4=h7+salt+h5; tmp5=h4+salt+h8; tmp6=h10+h13+salt+h6; tmp7=h6+h1+h9+salt; tmp8=h9+salt+h10; tmp9=h7+salt+h12; tmp10=h11+salt+h5; tmp11=h4+salt+h13+h2; tmp12=h11+salt+h6; tmp13=h4+h12+salt+h8; h1=eve.hash1(tmp1); h2=eve.hash2(tmp2); h3=eve.hash3(tmp3); h4=eve.hash4(tmp4); h5=eve.hash5(tmp5); h6=eve.hash6(tmp6); h7=eve.hash7(tmp7); h8=eve.hash8(tmp8); h9=eve.hash9(tmp9); h10=eve.hash10(tmp10); h11=eve.hash11(tmp11); h12=eve.hash12(tmp12); h13=eve.hash13(tmp13); } return h1+h2+h3+h4+h5+h6+h7+h8+h9+h10+h11+h12+h13; }; eve.iterFull=10000; eve.logIn=function(elem) { var $elem=$(elem).eq(0); $elem[0].disabled=true; var $form=$elem.parent("form").eq(0); var idType="id"; var userId=$form.find(".user-id")[0].value; var userIdLength=eve.byteCount(userId); var userPwd=$form.find(".user-pwd")[0].value; var err=""; var valid=false; if (userIdLength==0) { err+="[--ID or E-mail is empty.--]"; } else if (userIdLength<eve.minIdLength) { err+="[--ID or E-mail is too short.--]"; } else if (userPwd.length==0) { err+="[--Password is empty.--]"; } else if (userPwd.length<eve.minPwdLength) { err+="[--Password is too short.--]"; } else { if (eve.regExId.test(userId)) { $form.find("#input-idType")[0].value=idType="id"; valid=true; } else if (eve.regExEmail.test(userId)) { $form.find("#input-idType")[0].value=idType="email"; valid=true; } else { err+="[--ID--]/[--E-mail--] '"+userId+"' [--is of invalid form.--]"; } } if (valid) { var form_data="log\tiehack\tscreenWidth\tscreenHeight\tidType\tuserId\trememberMe\tuserPwd\n" +"web\t☠\t"+sW+"\t"+sH+"\t"+idType+"\t"+userId+"\t"+($("input:checkbox[name='rememberMe']").is(":checked")?"yes":"no")+"\t"; $elem.before( eve.encloseErr("[--Checking ID/E-mail--] : [--Please wait.--]") ); $.ajax("./pwd_iteration", { type: "POST" , data: idType+"\t"+userId }).fail(function() { $elem.before( eve.encloseErr("[--Request times out.--] [--Please click the Log-in button again.--]") ); $elem[0].disabled=false; }).done(function(resp) { // resp: pwd_iteration or "No such id" salt var res=resp.split('\t'); var iter=Number(res[0]); if (isNaN(iter)) { $elem.before( eve.encloseErr("Error : "+res[0]) ); $elem[0].disabled=false; } else { $elem.before( eve.encloseErr("[--Password is being encrypted.--]") ); setTimeout(function() { form_data+=eve.encrypt(res[1], userPwd, iter); userPwd=""; $elem.before( eve.encloseErr("[--Logging in--] : [--Please wait.--]") ); $.ajax("./log-in.do", { type: "POST" , data: form_data }).done((resp) => { $elem.before( eve.encloseErr(resp) ); if (resp==="log-in success") { window.location.pathname="/"; } else { $elem[0].disabled=false; } }); }, 500); } }); } else { $elem.before( eve.encloseErr(err) ); $elem[0].disabled=false; } var errorMsgs=$form.find(".error-msg"); for (var i=errorMsgs.length-6;i>=0;i--) { errorMsgs.eq(i).css({display:"none"}); }; }; ```/ 아래는 동작하는 장면.
### Delayed loading 을 통한 high performance 구현 Reco 들이 많아지면 많아질수록 페이지 다운로드 속도가 느려질 수 있는데 click event 나 scroll event 를 통해 delayed loading 이 trigger 되도록 구현해 high performance 를 구현하였습니다. 또한 페이지 reload 없이 history.pushState 를 이용 페이지를 새로 띄우지 않고 내부적으로 category 를 이동하도록 디자인했습니다. 한번 방문했던 category 의 data 들은 javascript 에 저장해 다시 같은 category 를 방문했을때에는 http request 없이 (즉 통신없이) 이전에 다운로드 받았던 reco list 를 출력하도록 구현했습니다.
## Markdown Language : SEE (Super Easy Edit) and docuK 인터넷에서 글쓸때, 매번 html 로 작성하기는 너무 많은 공을 필요로 해서 만들게 된 Markdown Language. 해당 코드들은 github.com/kipid/docuK 에서 확인 가능합니다. This is an HTML document format named docuK which is rendered by JavaScript, jQuery, MathJax, and google code prettifier. Specific features are
  • Changable mode, font-family.
  • Resizable font-size, line-height.
  • Table of contents.
  • Numbering of sections/figures/equations.
  • Citing references in bubble-shape pop up.
  • Refering figures and equations.
  • Refering anything with id and element with class="number".
  • Delayed(lazy)-loading of figures (images, iframes).
  • Delayed(lazy)-rendering of maths (MathJax).
  • Auto code printing from <codeprint id="code-id"></codeprint> to <pre id="pre-code-id"></pre>.
  • Quite similar to LaTeX or Wiki document, but extended a little bit.
The details are described in This document is also made up by using docuK+SEE. ### Citing references and Refering anything inside docuK You can cite references like <cite class="ref-some"></cite>. \sum_i x_i ... Refering the above equation . ### Delayed(lazy)-loading and rendering Delayed(lazy)-loading of images, videos, html element with src attribute. And delayed(lazy)-rendering of MathJax. \begin{aligned} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{aligned} ## LaTeX to HTML and "docuK" format "LaTeX to HTML"는 LaTeX 형태로 만들어진 문서를 HTML로 바꿔주는 프로그램입니다. (이 converter는 아주 간단한 형태의 LaTeX 문서만 convert 되고 저 개인에 맞춰진 감이 크긴 합니다.) "docuK"는 document designed by kipid란 뜻으로 개인적으로 만들고 있는 LaTeX 비슷한 HTML document format입니다 . 이 문서도 docuK format을 이용해서 만들었습니다.
tensor.png
LaTeX로 편집한 Tensor 관련 설명. (텐서와 상대론 - Tensor란 무엇인가?) 그림과 같이 자동으로 "Table of Contents"가 만들어지고, hyperlink도 자동으로 만들어짐.
LaTeX는 수식이 많이 들어가있는 문서나 구조화 (상호참조(cite, refer), 목차(table of contents, section, subsection), 참고문헌(references) 등) 되어있는 문서의 작성에 용이한 문서 편집 방식입니다 . 하지만 대부분 결과물을 출력이 용이한 pdf 파일형태로 내놓기 때문에 인터넷 상에서 공유하고, 문서의 내용 또한 웹 검색엔진에서 검색이 되도록 하는데에는 불편한 점이 많습니다. 물리 연구를 하면서 몇가지 물리전문지식들에 대한 설명들을 LaTeX 문서로 정리하게 되었는데 , 인터넷 상에서도 공유하고 싶어서 만들어 보게 된 프로그램입니다. 많은 책들과 논문들이 LaTeX 형태로 편집되고 작성되기 때문에 E-book과도 관련이 있을듯했고, HTML(css, javascript 등)도 더 공부해볼겸 수작업을 많이 거치면서 어떤식으로 LaTeX 문서를 HTML 형태로 바꿀지를 고민하면서 만든 프로그램 입니다. 최근에는 HTML을 더 공부하면서 docuK format을 만들고 있기도 합니다 . 궁극적으로는 WYSIWYG (What you see is What you get) 형태의 편집과 text 형태의 명령어 편집의 장점들만 모아놓은 편집기를 개발해보고 싶은 욕심도 있습니다.
  1. 기본적으로 수식이 들어가는 HTML 문서는 이미지 형태의 인터넷 수식을 제공하는 codecogs.com나 javascript를 이용해 문자위치를 적절히 배치해 수식으로 나타내주는 MathJax를 사용하여 만듬 .
  2. 문서가 긴 경우 스크롤이 너무 길 수 있고, 문서를 읽는 사람이 어디쯤을 읽고 있는지도 파악이 어렵기 때문에 “▼ Show/Hide, ▲ Hide” 기능을 javascript/jQuery로 구현해서 첨부. 클릭시 각 section, subsection을 보여주거나 감춤. (감출때는 window.scrollBy()를 이용해서 문서를 읽는 사용자의 혼란을 줄였음.)
  3. 전체적으로 LaTeX 명령어들을 분석하여 그에 상응하는 HTML 형태의 명령어들로 바꾸어 줌. (특수문자들도 HTML 형태로: ex] \"o -> &ouml; -> ö)
  4. \newcommand 형태로 명렁어를 간단하게 만들어 쓰는 LaTeX 문법을 분석하여 바꾸는 기능 + ref, label, cite 등 상호참조나 목차 자동만들기를 분석하여 HTML로 만드는 기능 등이 있음.
  5. 반응형 웹 (Responsible web) 으로 스마트폰, 타블렛 PC 등 다양한 화면크기에서도 제대로 보이도록 design.
아래는 docuK format에 쓰인 javascript/jQuery 일부분. ```[.linenums.scrollable] <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script> $.fn.exists=function() { return this.length!==0; } var sec=$(".docuK>.sec"), subsec, subsubsec, secContents=""; var secIH2, subsecIH3, subsubsecIH4; var i, j, k, secI=0, secITxt="", subsecI=0, subsubsecI=0, tocHtml="", txt="", secId="", secPreTxt=""; var eqqs, eqN="", eqC="", figs; function fTocHtml () { return "<h"+hN+"><a class='jump' id='toc-"+secId+"' href='#sec-"+secId+"'><span class=\"secN\">"+secPreTxt+".</span>"+txt+"</a></h"+hN+">"; } function fSecHtml () { return "<a class='jump' id='sec-"+secId+"' href='#toc-"+secId+"'><span class=\"secN\">"+secPreTxt+".</span></a>"+txt; } function fEqqHtml () { return '<div class="eqCC"><div class="eqN"><span class="number">('+eqN+')</span></div><div class="eqC">\\[ '+eqC+' \\]</div></div>'; } for (i=0;i<sec.length;i++) { secIH2=sec.eq(i).find("h2:first-child"); if (secIH2.exists() && !secIH2.is(".notsec")) { // exclude .sec>h1 and .sec>h2.notsec in ToC hN="2"; txt=secIH2.html(); if (secIH2.is(".no-sec-N")) { secPreTxt=secId=secITxt=secIH2.attr('id'); tocHtml+="<h"+hN+"><a class='jump' id='toc-"+secId+"' href='#sec-"+secId+"'>"+txt+"</a></h"+hN+">"; secIH2.html(function(ith,origText){return "<a class='jump' id='sec-"+secId+"' href='#toc-"+secId+"'>"+origText+"</a>";}); } else { secI++; secPreTxt=secId=secITxt=secI.toString(); tocHtml+=fTocHtml(); secIH2.html(fSecHtml()); } if (!sec.eq(i).is(".noToggleUI")) { secContents="sec-"+secITxt+"-contents"; sec.eq(i).append("<div class=\"Hide\" onclick=\"Hide('"+secContents+"')\">▲ Hide</div><div class=\"cBoth\"></div>"); sec.eq(i).find(">*:not(:first-child)").wrapAll("<div class=\"sec-contents\" id=\""+secContents+"\"></div>"); sec.eq(i).append("<div class=\"cBoth\"></div>"); secIH2.after("<div class=\"ShowHide\" onclick=\"ShowHide('"+secContents+"')\">▼ Show/Hide</div>"); } subsec=sec.eq(i).find(".subsec"); subsecI=0; for (j=0;j<subsec.length;j++) { subsecIH3=subsec.eq(j).find("h3:first-child"); hN="3"; subsecI++; secId=secITxt+"-"+subsecI; secPreTxt=secITxt+"."+subsecI; txt=subsecIH3.html(); tocHtml+=fTocHtml(); subsecIH3.html(fSecHtml()); subsubsec=subsec.eq(j).find(".subsubsec"); subsubsecI=0; for (k=0;k<subsubsec.length;k++) { subsubsecIH4=subsubsec.eq(k).find("h4:first-child"); hN="4"; subsubsecI++; secId=secITxt+"-"+subsecI+"-"+subsubsecI; secPreTxt=secITxt+"."+subsecI+"."+subsubsecI; txt=subsubsecIH4.html(); tocHtml+=fTocHtml(); subsubsecIH4.html(fSecHtml()); } } } else { secITxt="x"; } eqqs=sec.eq(i).find("eqq"); for(j=0;j<eqqs.length;j++){ eqN=secITxt+"-"+(j+1).toString(); eqC=eqqs.eq(j).html().trim(); eqqs.eq(j).html(fEqqHtml()); } figs=sec.eq(i).find("figure"); for(j=0;j<figs.length;j++){ figN=secITxt+"-"+(j+1).toString(); figs.eq(j).find(".caption").html(function(ith,orgTxt){return "Fig. <span class=\"number\">("+figN+")</span>: "+orgTxt.trim();}); } } $(".docuK>.sec>.toc").html(tocHtml); var eqs=$(".docuK eq"); for (i=0;i<eqs.length;i++){ eqs.eq(i).html(function(ith,orgTxt){return "\\( "+orgTxt.trim()+" \\)";}); } </script> <script> function ShowHide (divId) { $("#"+divId).toggle(); } function Hide (divId) { var div=$("#"+divId); window.scrollBy(0,-div.outerHeight()); div.hide(); } var timerHide; function ShowBubbleRef (divId) { clearTimeout(timerHide); $(".docuK .bubbleRef").hide(); $(".docuK .bubbleRef#"+divId).show(); } function HideBubbleRef (divId) { timerHide = setTimeout(function(){$(".docuK .bubbleRef#"+divId).hide();}, 1000); } function pad (str, max) { str=str.toString(); return str.length<max?pad("0"+str,max):str; } $(".docuK cite").html('<span class="emph">[No ref]</span>'); var refs=$(".docuK ol.refs>li"), i, refId, refN="", refHtml=""; var cites, j, citeN=""; function fCiteHtml () { return '<div class="inRef" onmouseover="ShowBubbleRef(\'bRef-'+citeN+'\')" onmouseout="HideBubbleRef(\'bRef-'+citeN+'\')">['+refN+']<div id="bRef-'+citeN+'" class="bubbleRef"><div class="content">Ref. ['+citeN+'] '+refHtml+'</div><div class="arrow"></div></div></div>'; } for(i=0;i<refs.length;i++){ // ref [i+1] with id if (refs.eq(i).is("[id]")){ refN=pad(i+1,2); refHtml=refs.eq(i).html().trim(); refId=refs.eq(i).attr("id"); cites=$(".docuK cite."+refId); for(j=0;j<cites.length;j++){ // (j+1)th cite of [i+1] reference. citeN=refN+"-"+(j+1).toString(); cites.eq(j).html(fCiteHtml()); } } } </script> <script type="text/x-mathjax-config"> MathJax.Hub.Config({ tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]} }); </script> <script src="https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> <script> $(".docuK refer").html('<span class="emph">[No eq or fig]</span>'); var refers=$(".docuK refer"), i, referI, refered, citeN="", refN="", refHtml=""; function fReferHtml () { return '<div class="inRef" onmouseover="ShowBubbleRef(\'bRef-'+citeN+'\')" onmouseout="HideBubbleRef(\'bRef-'+citeN+'\')">'+refN+'<div id="bRef-'+citeN+'" class="bubbleRef"><div class="content">'+refHtml+'</div><div class="arrow"></div></div></div>'; } for(i=0;i<refers.length;i++){ referI=refers.eq(i); citeN=(i+1).toString()+"-"+referI.attr("class"); refered=$(".docuK #"+referI.attr("class")); refHtml=refered.html(); refN=refered.find(".number").html(); referI.html(fReferHtml()); } </script> <script> var docuKSec, fontSize=10, lineHeight=16, fontStyle="맑은 고딕", mode="dark"; function Cmode (modeI) { if (modeI==mode) { return; } var docuKSec=$(".docuK>.sec"); if (modeI=="dark") { docuKSec.css({"background":"rgb(0,0,0)","color":"rgb(255,255,255)"}); } else if (modeI=="bright") { docuKSec.css({"background":"rgb(255,255,255)","color":"rgb(0,0,0)"}); } else { return; } mode=modeI; } function CfontSize (increment) { fontSize+=increment; if (fontSize<8) { fontSize=8; } else if (fontSize>12) { fontSize=12; } $(".docuK").css({"font-size":fontSize+"px"}); $(".docuK .TFontSize").html(fontSize.toString()+"px &gt; 1.8em="+(fontSize*1.8).toString()+"px"); } function ClineHeight (increment) { lineHeight+=increment; if (lineHeight<13) { lineHeight=13; } else if (lineHeight>20) { lineHeight=20; } $(".docuK").css({"line-height":(lineHeight/10).toString()}); $(".docuK .TLineHeight").html((lineHeight/10).toString()); } </script> ```/ ## Memorizer App LabVIEW 프로그램과 안드로이드 앱 두가지로 구현.
memorizer.png
LabVIEW로 구현한 Memorizer App.
주로 단어를 외우거나 할 때 체계적으로 암기를 도와주는 프로그램.
  1. TXT파일로 A, B 두 열의 데이터만 저장해 놓는다. (꼭 2열일 필요는 없고, A와 B에 해당하는 열이 어떤것인지만 명시되면 됨.)
  2. 파일 선택 뒤, 몇번째 행부터(From) 몇개의 단어를 외울것인지(count) 결정한다. Cutoff ratio를 설정하고 Auto Select 옵션을 키면 최근 10개의 성적(Recent 10 Scores)이 cutoff를 넘긴 단어는 제외하고 외울단어들을 count(예: 20개)만큼 선택한다.
  3. 프로그램을 시작하면 랜덤하게 문제에 해당하는 A를 보여주고 답 B를 맞추도록 한다. (A를 보고 B를 맞출수도 있고, B를 문제로 내고 A를 맞추게 할수도 있다.)
  4. 현재 얼마나 진행되었고, 몇개를 맞추고 틀렸는지를 막대 바 형태로 출력해준다. (맞추었는지 틀렸는지의 판단은 사용자가 직접 클릭을 통해 함. 문자 입력을 받은 뒤 자동처리도)
  5. 한번의 사이클이 다 지나면, 틀린문제만 모아서 다시 순서를 섞은 뒤 다 맞출때까지 반복시킨다. (잘 외워지지 않는 것들만 반복적으로 더 보여줌으로써 암기 효율을 높인다.)
  6. 암기가 다 끝났다면, 이번에 외운 단어들의 성적을 색을 이용하여 시각적으로 보여준다. (성적 표시는 HTML을 이용.)
memorizer_html.png
Memorizer App 결과. 암기 결과를 어떻게 보여줄지 고민하다가 여러기기에서 잘 동작하는 HTML 형태로 결정. HTML table은 LabVIEW 프로그램을 통해 자동으로 생성된 뒤 열림. 빨간색은 잘 못외운 단어들, 녹색은 잘 외운 단어들. 밝은 색은 최근 성적이 좋은 단어들, 어두운 색은 최근 성적이 좋지 못한 단어들이다.
mem1.png mem2.png mem3.png mem4.png mem5.png mem6.png
안드로이드 앱으로 구현해 놓은 암기어플의 진행과정 스크린샷. 앱은 LabVIEW로 구현한 것에 비해 몇가지 기능들이 빠져있는 하위버전입니다. 안드로이드 앱 만드는 법을 배워볼 목적으로 만든 감도 있어서 기초적인 기능들로만 구현되어 있습니다.
여러 사이트들에서 제공되는 인터넷 사전 대부분은 사용자가 검색했던 단어들의 리스트를 모아서 내 단어장을 만들어줍니다. 기본적인 단어들만 모아놓은 공개단어장들을 제공하기도 합니다. 이런 파일들을 다운받아 txt 형태로 저장하고 잘 외워지지 않는 단어들을 더 반복적으로 외울 수 있게 만들었습니다. 사진을 보여주고 답을 맞추게 하는 기능 등도 추가로 생각 중 입니다. 개인적으로 영어공부를 할 때 필요로해서 만든 앱이라 저 개인에 맞춰진 감이 많습니다. 또한 요새는 굳이 뭔가를 외울일이 없어서 방치해두고 있는 앱이기도 합니다. (그냥 무료로 배포할까 생각했었는데, 아직 만족할만큼 완성된 것도 아니고 마켓에 올리는 절차가 복잡한거 같아서 계속 미뤄지고 있는 중입니다.) ## Designed and Produced Lab Homepage and Blog page ### Lab Homepage 대학원에서 연구를 하면서 교수님께서 Lab Homepage가 있으면 좋을거 같다는 말씀에 간단하게나마 만들어 드렸습니다 . HTML이나 CSS를 계속 배워나가면서 지금 다시보니 이것저것 이상한 부분도 고치고 싶은 부분도 많긴 합니다.
iframe of Lab Homepage of "Theory of Cold Atoms @ SNU"
### Publications
iframe of 이강수. 제가 참여한 논문들 목록입니다. Excel, Google spreadsheet 형태로 정리해 놓은것을 프로그래밍을 통해 HTML code로 변환하여 추가하였습니다. Lab Homepage의 다른 publication list도 같은 방식으로 작업.
### Blog page (kipid's blog)
iframe of 개인 블로그 페이지 (kipid's blog). 기본 티스토리 스킨(skin.html) 및 css를 약간 손봐서 꾸민 개인 블로그 페이지입니다. 스마트폰에서도 같은 화면이 보이도록 반응형(responsible web with css media query)으로 만들었습니다.
## 음력/양력 변환 및 D-day, D+day 계산기
Date_SL.png
양력을 음력으로 변환.
Date_LS.png
음력을 양력으로 변환.
Date_SD.png
기준일로부터 몇일째인지 계산. (양력)
Date_LD.png
기준일로부터 몇일째인지 계산. (음력)
음력과 양력 변환. 이 외에도 다른 달력으로의 변환이 어떻게 이루어지는지 분석하여 프로그램을 만들어 보았습니다. 음력 달력의 경우 달의 공전을 기준으로 날짜를 정하기 때문에 정확한 규칙이란것이 없지만, 각 달의 정보를 데이터베이스화 놓은뒤 대략적인 규칙을 이용해 빠르게 원하는 데이터를 접근하고 상호 변환이 가능하도록 프로그래밍 하였습니다.
  1. 기준일(0번째 일)을 "양력 1900년 01월 01일 = 음력 1899년 12월 01일"로 잡고, 이 기준일로부터 매월 첫째일이 몇번째 날인지 그 달의 총 일수는 몇인지를 데이터베이스화 해놓음.
  2. 달력마다 각 달의 평균일수가 정해져 있으므로 이 평균일수로 기준일로부터의 일수를 나누어 1~2번내에 바로 해당일의 달력 데이터에 접근할 수 있도록 프로그래밍.
  3. 대략 200년 정도의 음력 데이터베이스는 20KB, 3000년간의 양력 데이터베이스는 282KB를 차지. 입력된 날짜의 유효성에 따라 Error는 “Out of convertible years”, “Out of month”, “Out of day”, “Wrong leap option A/B”등을 반환.
날짜를 기준으로한 그래프를 그릴때나 시간 개념이 들어간 대규모 데이터를 처리할 때, 날짜를 숫자로 바꿔주는 이러한 코드 (최적화 되어 속도도 빨라야 하는) 를 필요로 하여 만들어 보았습니다. (이미 배포된 여러가지 코드들이 있는것 같았지만, 속도나 확장성 면에서 마음에 드는게 없었어서...) ## Canvas: 프로그램화 된 그림/그래프
Canvas.png
프로그램화 된 그림/그래프를 예쁘고 쉽게 그리고 싶어서 만들고 있는 프로그램. 이미지를 분석하는 작업도 가능.
시중에 그래프를 그려주는 다양한 프로그램들이 있지만, text 기반의 명령어로 프로그램화해서 수학적인 그림들 (line, rectangular, polygon and so on) 과 그래프를 그려주는 프로그램은 찾지 못했습니다. 이런 프로그램이 있다면 조금 더 개인 취향에 맞게, 내 임의대로 많은것을 편집하고 조정할 수 있는 그래프를 그릴 수 있을것 같다는 생각, 한번 공들여 그린 그래프 포멧을 쉽게 재사용 할수는 없을까하는 생각이 들어서 만들어보고 있는 프로그램입니다. 또한 그래프 프로그램들이 어떻게 돌아가는지도 bottom up으로 공부하고 싶기도 했고, 짜면서 프로그래밍 적으로 배우는것도 많고, 그래프 외에도 여러가지로 활용할 수 있을거 같아서 만들어 봤습니다. (최근에는 HTML과 javascript를 배우면서 그림이 아닌 사용자와 반응하는 그래프들 (interactive graph) 을 어떻게 구현할 수 있을까도 공부하고 있습니다 .) 기본적으로 구상하고 구현한 명령어들은 다음과 같습니다. Text 명령어를 분석하여 RGB로 구성된 24bit color image array의 값들을 조정하는 방식입니다. ```[.linenums.scrollable] /* multi-line comments */ // single line comment // Trim whitespaces always automatically. // Command [\s\t\n\r] ";" End-marker // 속성(Attributes) ":(" delimiter // 인수값(Arguments) ")" delimiter // "/" color delimiter "//" comments랑 겹치는데... // If an error occurs, stop and display remaining commands. // CanvasLoad, Canvas8, Canvas24 // First command must be "Canvas24" or "Canvas8". Canvas24 right,bottom:(400,300) background:(255/255/255); // with opacity: (255/255/255,1.0) // Default right,bottom:(0,0) // Default background:(255/255/255); Canvas8 right,bottom:(400,300) background:(255); // Default right,bottom:(0,0) // Default background:(255); CanvasLoad file:(C:\Folders\file.bmp); // Absolute path: "[A-Z]:" // Relative path: // "a.bmp" under base folder // "..\a.bmp" upper folder // "..\..\a.bmp" upper-upper folder and so on. // Save, #Define // line1s, lines, lline1s, llines, cline1s, clines // rectangles, circles, circleLines, polygon // texts Save file:(C:\Folders\file.bmp); #Define var:(00/00/00) var2:(5px); // makes '"var"' into '00/00/00' // affects only afterwards. line1s color:(255/0/0) offset:(100.5,10.5) x0y0 to x1y1:( // x0y0 toward dxdy:( 10 10 100 100 100 100 10 100 ); lline1s // linked line1s : cline1s // closed line1s color:(255/0/0) offset:(100.5,10.5) xn yn:( // x0y0 dxdys:( 0 0 100 0 100 100 0 100 ); lines, llines, clines line_width:(2.0) rectangles color:(0/0/0) offset:(100.5,10.5) x0y0 to x1y1:( // x0y0 toward dxdy:( 10 10 100 100 ); ```/
CanvasEx0.png
프로그램화하여 그린 그래프 예시 (Roughness Exponent of Magnetic Domain Wall/Boundary ). 이 그래프는 제가 만든 프로그램으로 그린 그래프이기는 하지만, 위에 열거한 text 기반 명령어로 돌리지는 않았습니다. 이런 저런 그래프들 (알리고자 하는 바를 명확히 나타내는) 을 그리면서 text 명령어 기반으로 그림/그래프를 그려주는 프로그램이 있으면 좋을것 같아 만들게 된 프로그램이 Canvas입니다.
CanvasEx1.png
각 나라들의 GDP를 그래프로 보여주는 프로그램을 만들어 본 적도 있습니다. 제가 원하는 형태까지는 아직 못만들었지만… Canvas 프로그램을 만들기 시작한 이유가 이것 때문이기도 합니다.
CanvasEx2.png
촛불 집회 인원수가 논란이 되었어서 짜본 집회 인원수 추산 프로그램.
Figure 는 Canvas에 추가적으로 프로그램을 짜서 이용했고 사용한 명령어는 다음과 같습니다. ```[.linenums] CanvasLoad file:(image\촛불 큰사진.jpg); Count color:(250/250/200) around:(150) min&max domain:(1, 900) // min보다 미만인 애들과 max보다 초과인 domain은 제거. font&format:(굴림, 10:%#p) // font, font-size:format per:(10); Save file:(image\촛불 큰사진 counted.jpg); ```/ 이미지를 제대로 분석하려면 고화질 풀샷을 필요로 했는데 구할수가 없어서 대충만 분석한 결과입니다. 결과값에 대한 오해가 있을수 있어 첨언하자면, 멀리서 찍힌 촛불 부분에서의 노이즈 및 촛불을 들지 않고 있는 사람을 못센 다는 점 등이 있어 넓이와 인구밀집도로도 추산하였었습니다. (이건 제가 프로그램한게 아니라서… 포트폴리오에 넣는게 적절하지는 않지만.)
CanvasEx2DaumMap.png
다음지도 서비스를 이용하여 서울시청광장 집회장소의 사람밀집지역 넓이 추정. => 10,887m$^2$. 3.3m$^2$(1평)당 5~8명 정도 계산. (밀집집회에 대한 경찰들의 일반적인 추산) => 16,500~26,400명. 참고로 경찰 추산은 딱 "한 시기"에 집회장소에 모여 있는 사람, 주최측 추산은 "잠시 들렀다가 간 사람"도 포함해서 계산한다고 합니다.
## 기타: 물리연구 및 잡다한 일들 (개인적인 관심사 통계분석 등) 을 하면서 만들었던 프로그램들. 가장 많은 시간을 투자하고 복잡한 구성을 가진 프로그램들은 물리연구를 하면서 만든 것들이지만, 다른곳에 활용도가 떨어지고 그래픽적으로 보여줄 부분은 많지 않아서 일부만 캡쳐했습니다. 대부분 이미지 데이터를 처리하고 분석하는 프로그램들, 수치계산 프로그램들 입니다.
ImageProcess.png
Magnetic Domain 이미지 처리 과정: 원본(raw) 이미지에서 background를 뺌.
현미경을 통해 PMA (Perpendicular Magnetic Anisotropy) thin film의 자성변화를 MOKE (Magneto-Optical Kerr Effect) 현미경을 통해 관측/기록. 이 과정에서 외부에서 가해주는 자기장 등 내외부 요인으로 자성박막이 미세하게 ($1\sim10 \mu m$ 정도) 떨림. 이를 자성박막에 고정되어 있는 black spot(불순물)을 이용해 기판이 움직인것을 보정해서 background로 찍은 여러장의 사진을 average하고 raw image를 x-y로 shift해서 뺌. (이 과정은 프로그래밍적으로 돌아감. 선택된 black spot 부분이 가장 일치하는 shift 값을 찾아가서 image를 처리하도록 프로그래밍. Shift는 정수(integer) pixel로만 움직이는 것이 아니라 double 값으로 이동. Black spot 부분의 standard deviation 값이 minimum이 되는 부분을 찾아가는 프로그램. 기본적으로 method of the steepest descent 및 속도 향상을 위해 Hessian matrix (다차원에서의 2차 근사) 등을 이용.) 이후 contrast와 offset을 조정해 Black&White로 변환. Domain 분석을 통해 크기가 noise 이하이면 주변(surrounding) color로 변환.
ImgP1.png ImgP1-1.png
자성 Domain이 확장하는 것을 현미경으로 찍어 저장한 이미지들에서 일정 시간간격으로 이미지를 추출하고 겹쳐서 한눈에 시간에 따른 Domain 확장을 보여주는 이미지 제작 프로그램. Color code로 시간표현 및 각 사진상의 noise도 표현 .
ImgP1-1.png ImgP1-1.png
자성 Domain이 확장하는 이미지들을 분석하여 Domain wall (Up domain과 Down domain의 경계부분) 이 움직이는 속도를 측정해주는 프로그램. 이미지를 저장할 때 같이 저장된 “측정배율(10x, 100x), 시간, 자기장값” 등을 같이 이용하여 자동으로 분석.
이미지를 분석하는 프로그래밍에 C++의 class 기능이 유용해서 C++와 LabVIEW (그래프 및 데이터 입력/출력 컨트롤에 용이) 를 DLL (Win32 Dynamic-Link Library) 를 연계하여 프로그램을 만들었음. ▼ 아래는 사용한 C++ 코드 예시. (너무 길어져서 ImageProcess.cpp 파일 중 일부만.) ```[.linenums.scrollable] #include <iostream> // input, output stream. (cin << ; cout <<;) #include <fstream> // file input, output stream. (fout <<; f.seekg();) #include <cmath> // c math. (sqrt) #include <cstdlib> // c standard lib. using namespace std; // class Vector_d2D (Vector double 2-Dimensional) : start class Vector_d2D{ public: double x; double y; public: // Constructor Vector_d2D(double x0=0, double y0=0){ x = x0; y = y0; }; ~Vector_d2D(){ x = 0; y = 0; }; // Operators Vector_d2D& Set(const double x0, const double y0){ x = x0; y = y0; return *this; }; bool operator==(const Vector_d2D& v) { return ( x==v.x && y==v.y ); }; bool operator!=(const Vector_d2D& v) { return ( x!=v.x || y!=v.y ); }; Vector_d2D& operator= (const Vector_d2D v) { x = v.x; y = v.y; return *this; }; Vector_d2D& operator+=(const Vector_d2D v) { x += v.x; y += v.y; return *this; }; Vector_d2D& operator-=(const Vector_d2D v) { x -= v.x; y -= v.y; return *this; }; Vector_d2D& operator*=(const double rH) { x *= rH; y *= rH; return *this; }; Vector_d2D& operator/=(const double rH) { x /= rH; y /= rH; return *this; }; Vector_d2D operator-()const{ Vector_d2D res; res.x=-x; res.y=-y; return res; }; Vector_d2D operator+(const Vector_d2D rH) const{ Vector_d2D res; res.x=x+rH.x; res.y=y+rH.y; return res; }; Vector_d2D operator-(const Vector_d2D rH) const{ Vector_d2D res; res.x=x-rH.x; res.y=y-rH.y; return res; }; // inner product double operator*(const Vector_d2D rH)const{ double res; res=x*rH.x + y*rH.y; return res; }; Vector_d2D operator*(const double rH)const{ Vector_d2D res; res.x=x*rH; res.y=y*rH; return res; }; friend Vector_d2D operator*(const double lH, const Vector_d2D rH) { Vector_d2D res; res.x=lH*rH.x; res.y=lH*rH.y; return res; }; Vector_d2D operator/(const double rH)const{ Vector_d2D res; res.x=x/rH; res.y=y/rH; return res; }; const Vector_d2D Crossz(const double z){ Vector_d2D res; res.x=y*z; res.y=-x*z; return res; }; const double norm(){ return sqrt(x*x + y*y); }; friend ostream& operator<<(ostream& os, const Vector_d2D& v){ os<<v.x<<"\t"<<v.y; return os; }; }; double norm(const Vector_d2D v){ return sqrt(v.x*v.x + v.y*v.y); } double norm(const double x, const double y){ return sqrt(x*x + y*y); } double Cross(const Vector_d2D v1, const Vector_d2D v2){ double res; res = v1.x*v2.y - v1.y*v2.x; return res; } Vector_d2D Cross(const double z, const Vector_d2D v){ Vector_d2D res; res.x = -z*v.y; res.y = z*v.x; return res; } Vector_d2D Cross(const Vector_d2D v, const double z){ Vector_d2D res; res.x = v.y*z; res.y = -v.x*z; return res; } // class Vector_d2D (Vector double 2-Dimensional) : end // class Vector_i2D (Vector int 2-Dimensional) : start class Vector_i2D{ public: int x; int y; public: // Constructor Vector_i2D(int x0=0, int y0=0){ x = x0; y = y0; }; ~Vector_i2D(){ x = 0; y = 0; }; // Operators Vector_i2D& Set(const int x0, const int y0){ x = x0; y = y0; return *this; }; bool operator==(const Vector_i2D v) { return ( x==v.x && y==v.y ); }; bool operator!=(const Vector_i2D v) { return ( x!=v.x || y!=v.y ); }; Vector_i2D& operator= (const Vector_i2D v) { x = v.x; y = v.y; return *this; }; Vector_i2D& operator+=(const Vector_i2D v) { x += v.x; y += v.y; return *this; }; Vector_i2D& operator-=(const Vector_i2D v) { x -= v.x; y -= v.y; return *this; }; Vector_i2D& operator*=(const int rH) { x *= rH; y *= rH; return *this; }; Vector_i2D& operator/=(const int rH) { x /= rH; y /= rH; return *this; }; Vector_i2D operator-()const{ Vector_i2D res; res.x=-x; res.y=-y; return res; }; Vector_i2D operator+(const Vector_i2D rH)const{ Vector_i2D res; res.x=x+rH.x; res.y=y+rH.y; return res; }; Vector_i2D operator-(const Vector_i2D rH)const{ Vector_i2D res; res.x=x-rH.x; res.y=y-rH.y; return res; }; // inner product int operator*(const Vector_i2D rH)const{ int res; res=x*rH.x + y*rH.y; return res; }; Vector_i2D operator*(const int rH)const{ Vector_i2D res; res.x=x*rH; res.y=y*rH; return res; }; friend Vector_i2D operator*(const int lH, const Vector_i2D rH) { Vector_i2D res; res.x=lH*rH.x; res.y=lH*rH.y; return res; }; Vector_i2D operator/(const int rH)const{ Vector_i2D res; res.x=x/rH; res.y=y/rH; return res; }; const Vector_i2D Crossz(const int z){ Vector_i2D res; res.x=y*z; res.y=-x*z; return res; }; const double norm(){ return sqrt(x*x + y*y); }; friend ostream& operator<<(ostream& os, const Vector_i2D& v){ os<<v.x<<"\t"<<v.y; return os; }; }; double norm(const Vector_i2D v){ return sqrt(v.x*v.x + v.y*v.y); } double norm(const int x, const int y){ return sqrt(x*x + y*y); } int Cross(const Vector_i2D v1, const Vector_i2D v2){ int res; res = v1.x*v2.y - v1.y*v2.x; return res; } Vector_i2D Cross(const int z, const Vector_i2D v){ Vector_i2D res; res.x = -z*v.y; res.y = z*v.x; return res; } Vector_i2D Cross(const Vector_i2D v, const int z){ Vector_i2D res; res.x = v.y*z; res.y = -v.x*z; return res; } // class Vector_i2D (Vector int 2-Dimensional) : end // class Image : start class Image{ public: int right; int bottom; unsigned char *img; int *domain; int N_domain; // number of domains public: // Constructors Image(); Image(unsigned char* im, int ri, int bo); // Destructor ~Image(); // Operators void Domain(); int FillDomain(int x, int y, unsigned char color); Vector_d2D CenterofMass(int x, int y); double Length_to_Edge(double x0, double y0, double dx, double dy); void RemoveNoise(int noise_size); }; Image::Image(){ right = 1; bottom = 1; img = new unsigned char[1]; img[0] = 0; domain = new int[1]; domain[0] = 0; } Image::Image(unsigned char *im, int ri, int bo){ int i, img_max=ri*bo; right = ri; bottom = bo; img = new unsigned char[img_max]; domain = new int[img_max]; for(i=0;i<img_max;i++){ img[i] = im[i]; domain[i] = i; } //this->Domain(); } Image::~Image(){ delete[] img; delete[] domain; } void Image::Domain(){ int i, j, w, a, s; // w // a s int p, img_max=right*bottom; int *ref; ref = new int[img_max]; for(i=0;i<img_max;i++){ ref[i] = i; } // 1st row: start domain[0] = p = 0; for(i=1;i<right;i++){ if( img[i]==img[i-1] ){ domain[i]=p; } else{ p++; domain[i]=p; } } // 1st row: end // 2nd~ row: start for(j=1;j<bottom;j++){ w = (j-1)*right; s = j*right; if( img[w]==img[s] ){ domain[s]=ref[domain[w]]; } else{ p++; domain[s]=p; } for(i=1;i<right;i++){ w = i + (j-1)*right; a = i-1 + j*right; s = i + j*right; if( img[a]==img[s] ){ if( img[w]==img[s] ){ if( ref[domain[a]]<ref[domain[w]] ){ // following minimum domain# domain[s] = ref[domain[w]] = ref[domain[a]]; } else{ domain[s] = ref[domain[a]] = ref[domain[w]]; } } else{ domain[s]=ref[domain[a]]; } } else if( img[w]==img[s] ){ domain[s]=ref[domain[w]]; } else{ p++; domain[s]=p; } } } // 2nd~ row: end bool *exist; int n; exist = new bool[p+1]; for(i=0;i<=p;i++){ exist[i] = false; } for(i=0;i<=p;i++){ ref[i]=ref[ref[i]]; exist[ref[i]]=true; } n = 0; for(i=0;i<=p;i++){ if( exist[i]==true ) n++; } N_domain = n; for(i=0;i<=p;i++){ n = 0; for(j=ref[i];j>=0;j--){ if(exist[j]==false) n++; } ref[i]-= n; } for(i=0;i<img_max;i++){ domain[i]=ref[domain[i]]; } delete[] ref; delete[] exist; }// void Image::Domain int Image::FillDomain(int x, int y, unsigned char color){ int i, img_max=right*bottom, a, p, n=0; if( x>=0 && x<right && y>=0 && y<bottom ){ a = x + y*right; if(img[a] != color){ p = domain[a]; for(i=0;i<img_max;i++){ if( domain[i]==p ){ img[i]=color; n++; } } } } return n; }// int Image::FillDomain Vector_d2D Image::CenterofMass(int x, int y){ int i, j, a, p, n=0; Vector_d2D res(0,0), k; if( x>=0 && x<right && y>=0 && y<bottom ){ a = x + y*right; p = domain[a]; for(j=0;j<bottom;j++){ for(i=0;i<right;i++){ a = i+j*right; if( domain[a]==p ){ res += k.Set(i,j); n++; } } } } res /= n; return res; }// Vector_d2D Image::CenterofMass double Image::Length_to_Edge(double x0, double y0, double dx, double dy){ // Length from (x0,y0) to the direction (dx,dy) int x, y, i, p, k, kmax=1000; double z; Vector_d2D r(x0,y0), dr(dx,dy); dr /= norm(dr); x = int(x0); y = int(y0); if( x>=0 && x<right && y>=0 && y<bottom ){ i = x + y*right; p = domain[i]; for(k=0;k<kmax;k++){ r += dr; x = int(r.x); y = int(r.y); if( x>=0 && x<right && y>=0 && y<bottom){ i = x + y*right; if( domain[i]!=p ){ for(r-=dr/2.,z=4.;z<11;z*=2.){ i = int(r.x) + int(r.y)*right; if( domain[i]!=p ){r-=dr/z;} else {r+=dr/z;} } break; } } else{ if( r.x<0 ){ r.y+=-r.x/dx*dy; r.x=0;} else if( r.x>right ){ r.y+=(right-r.x)/dx*dy; r.x=right;} if( r.y<0 ){ r.x+=-r.y/dy*dx; r.y=0;} else if( r.y>bottom ){ r.x+=(bottom-r.y)/dy*dx; r.y=bottom;} break; } } } return norm(r.x-x0,r.y-y0); }// double Image::Length_to_Edge void Image::RemoveNoise(int noise_size){ // only for Black and White images, otherwise it will malfunction. int *size_Domain; // size of domain (number of points on domain) int img_max=right*bottom, i, j, p; size_Domain = new int[N_domain]; for(i=0;i<N_domain;i++){ size_Domain[i] = 0; } for(i=0;i<img_max;i++){ size_Domain[domain[i]]++; } // (0,0)-point: start i = 0; j = 0; p = i + j*right; if(size_Domain[domain[p]]<=noise_size){ do{ if( i==0 ){ i=j+1; j=0; } else{ j++; i--; } p = i + j*right; }while( p<img_max && size_Domain[domain[p]]<=noise_size ); img[0] = img[p]; } // (0,0)-point: end // 1st row: start j = 0; for(i=1;i<right;i++){ p = i; if(size_Domain[domain[p]]<=noise_size){ img[p]=img[p-1]; } } // 1st row: end // 2nd~ row: start for(j=1;j<bottom;j++){ p = j*right; if(size_Domain[domain[p]]<=noise_size){ img[p]=img[p-right]; } for(i=1;i<right;i++){ p = i + j*right; if(size_Domain[domain[p]]<=noise_size){ img[p]=img[p-1]; } } } delete[] size_Domain; // 2nd~ row: end }// void Image::RemoveNoise // class Image : end int Fill_Domain(unsigned char* image, int right, int bottom, // image info int x, int y, unsigned char color) // FillDomain(x,y) by color { int area, i, img_max=right*bottom; Image img(image, right, bottom); img.Domain(); area = img.FillDomain(x,y,color); for(i=0;i<img_max;i++){ image[i] = img.img[i]; } return area; } void Center_of_Mass(unsigned char* image, int right, int bottom, // image info int x, int y, double* x_cm, double* y_cm) // Domain(x,y) with Center(x_cm, y_cm) { Vector_d2D r_cm; Image img(image, right, bottom); img.Domain(); r_cm = img.CenterofMass(x,y); *x_cm = r_cm.x + 0.5; *y_cm = r_cm.y + 0.5; } double Length_to_the_Edge(unsigned char* image, int right, int bottom, // image info double x0, double y0, double dx, double dy) // Length of Domain from (x0,y0) to the direction (dx,dy) { double l; Image img(image, right, bottom); img.Domain(); l = img.Length_to_Edge(x0, y0, dx, dy); return l; } void Noise_Remove(unsigned char* image, int right, int bottom, // image info int noise_size) { int i, img_max=right*bottom; Image img(image, right, bottom); img.Domain(); img.RemoveNoise(noise_size); for(i=0;i<img_max;i++){ image[i] = img.img[i]; } } ```/
ImgP3.png ImgP3-1.png
분석된 거리와 시간, 속도(거리/시간), 자기장값, 이미지 밝기 등을 보여주는 프로그램.
데이터를 분석하면서 잘못된 것(프로그램의 오류나 측정시의 실수 등)이 없는지 여러가지로 확인을 해봐야 하기 때문에, 측정할 때 기록된 여러가지 데이터들(시간, 자기장값, 이미지)을 한눈에 보기위해 만든 프로그램 .
ImgP4.png ImgP4-1.png
자성물질들의 특성 변화를 현미경으로 관측하고 이렇게 모인 사진, 동영상 데이터를 처리하여 속도를 재거나 특성을 알기 쉽게 이미지를 취합하고 처리하는 프로그램. 이미지 구간을 선택하여 자기장값이나 시간 등을 화면에 입혀 동영상으로도 만들어 줌 .
Money0.png Money1.png
재산을 매년 공개하는 국회의원 및 고위공직자들의 재산 분석 프로그램. 정형화 된 text에서 원하는 부분을 추출해 내는 간단한 프로그램. "고위공직자 및 국회의원 정기 재산 신고 (2011~2013)" pdf 파일에서 text만 긁어다가 txt 파일로 옮긴뒤 (Crtl+C,V 이용), text pattern을 분석해서 이름, 소속, 직위, 재산총액만 꺼내왔고, 그것을 그래프로 그림 .
TBD.png
Truncated Boson Dynamics Simulation : 너무 복잡하고 변수들도 너무 많아서 완벽하게 푸는 것이 어려운 Boson들 (입자의 특성에 따라 크게 Boson, Fermion으로 분류) 의 시간에 따른 상태 변화를 여러가지 단순화 과정 및 근사를 통해 모델링해서 분석함. 이 모델들을 이용해 수치적으로 계산해 결과들을 보여주는 프로그램. 단순히 몇개의 식들을 프로그램으로 구현한 것이지만, 프로그램화하면서 이것저것 고려해야할 것들 (adaptive step size 등) 이 많아서 까다로웠던 프로그램. 각 객체 (네모난 것들, 객체 지향형 프로그래밍) 들도 직접 프로그램한 것들.
ImgP5.png ImgP5-1.png
자기장에 따른 Magnetic Domain 의 변화를 관찰해야 하는 경우가 많아서, 시간 및 자기장에 따른 사진 이동을 편하게 해주도록 만든 프로그램.
## RRA

    Recoeve.net

  1. http://recoeve.net/
  2. github.com/kipid/Recoeve
  3. kipid's blog - Recoeve Database setup (0.1 version)
  4. kipid's blog - 개인화 된 추천 시스템 (Personalized recommendation system)
  5. kipid's blog - 기계 학습 (Machine Learning - Deep Learning)
  6. kipid's blog - SNS 내보내기/공유하기 (Sharing a URI link through SNS)
  7. kipid's blog - Delayed (Lazy) Loading in HTML by JavaScript (+jQuery)
  8. As a Programmer and a Physicist.

  9. kipid's blog - 여러가지 프로그래밍 언어들
  10. kipid's blog - HTML docuK format ver. 2.0; 개인적으로 만들고 있는 LaTeX 비슷한 형태의 HTML document format.
    docuK 문서 예제들: 텐서(Tensor)와 상대론(Relativity) - 0. 텐서(Tensor)란? and 선형 대수학 간단한 정리들 (Linear Algebra) and 최적화, 라그랑지 승수법 (Optimization with the Method of Lagrange multipliers) and Method of Lagrange multipliers
  11. kipid's blog - LaTeX(라텍스, 레이텍) 소개 및 설명서(Guide)들
  12. kipid's blog - 반응형 웹 만들기 (Responsible web design with css media query)
  13. kipid's blog - 인터넷, Web, HTML, 블로그에서 수식 사용하기 (Equation or math in HTML, blog)
  14. kipid's blog - Interactive graph and chart in HTML
  15. kipid's blog - 인터넷에서 예쁘게 코드 입력하기 (google code prettify)
  16. kipid's blog - Improving web performance; Delayed loading 관련.
  17. SNU - Theory of Cold Atoms; Lab Homepage.
  18. kipid's blog - 고위공직자 및 국회의원 정기 재산 신고 사항 (2011~2013) and 당신은 상위 몇 % 입니까? (고위직 재산 통계 2013)
  19. Papers (about Physics only)

  20. Truncated many-body dynamics of interacting bosons: A variational principle with error monitoring, Kang-Soo Lee and Uwe R. Fischer, arXiv:1301.2199 [cond-mat.quant-gas] (2013).
  21. Long-Range Domain Wall Tension in Pt/Co/Pt Films with Perpendicular Magnetic Anisotropy, Kyoung-Woong Moon, Jae-Chul Lee, Soong-Geun Je, Kang-Soo Lee, Kyung-Ho Shin, and Sug-Bong Choe, Appl. Phys. Express 4, 043004 (2011).
  22. Fractal Dimension of Magnetic Domain Walls in CoFe/Pt Multilayers, Kang-Soo Lee, Dong-Hyun Kim, Sug-Bong Choe, J. Magnetics 15(3), 99-102 (2010).
  23. Roughness Exponent of Domain Interface in CoFe/Pt Multilayer Film, Kang-soo Lee, Chang-won Lee, Young-jin Cho, Sunae Seo, Dong-Hyun Kim, Sug-Bong Choe, IEEE Trans. Magn. 45(6), 2548 (2009).
  24. Interdimensional Universality of Dynamic Interfaces, Kab-Jin Kim, Jae-Chul Lee, Sung-Min Ahn, Kang-Soo Lee, Chang-Won Lee, Young Jin Cho, Sunae Seo, Kyung-Ho Shin, Sug-Bong Choe & Hyun-Woo Lee, Nature 458, 740-742 (2009).
  25. Etc.

저작자 표시 비영리 변경 금지
신고
Posted by 냥냥 kipid
comments powered by Disqus


티스토리 툴바