(완성 예제 : 크롬, 파이어폭스, IE9에서 볼 수 있습니다)


글 : 인지심리 매니아


지각심리학은 자극의 움직임이 어떻게 뉴런의 발화로 이어지는지 연구해왔다. 이런 실험은 보통 두 가지 유형의 자극을 사용한다. 하나는 기울어진 막대처럼 생긴 자극이고, 다른 하나는 무선적인 방향으로 움직이는 점 자극이다.

 

오늘은 무선적으로 움직이는 점들을 구현한 예제를 소개하고자 한다이 예제는 Codeflow라는 블로그에서 소개되어 있으며필자가 목적에 맞게 약간의 수정을 가했다.


 


구조도 


이 코드는 네 개의 object를 갖고 있다. 먼저 main system을 불러온다. System은 여러 개의 점(particle)을 불러내서 해당 좌표에 그린다. Particle은 각각 고유한 좌표와 속도(velocity)를 갖고 있다. 각각의 좌표는 Vector로 표현된다. Vectorxy좌표를 변수로 가지고 있으며, 좌표를 계산할 때 사용할 사칙연산 메소드를 가지고 있다.

 


소스 코드


index.html

<!DOCTYPE HTML>

<!-- http://codeflow.org/entries/2010/aug/22/html5-canvas-and-the-flying-dots/ -->

<html lang="en"><head>

<style type="text/css">

html,body{width:200px;height:200px;margin:0;padding:0;border:0;outline:0}

body{background-color:#fff}

span{position:absolute;left:5px;top:2px}

a{font-family:sans-serif;color:#88ca0c;text-decoration:none;font-weight:bold;cursor:pointer}</style>

<script type="text/javascript" src="gravity.js"></script>

</head>


<body onload="main()">

<canvas id="particles" width="200" height="200"></canvas></a>

</body>

</html>


 

gravity.js

var Vector = function(x, y){

    this.x = x;

    this.y = y;


    this.sub = function(other){

        return new Vector(

            this.x - other.x,

            this.y - other.y

        );

    }

    this.isub = function(other){

        this.x -= other.x;

        this.y -= other.y;

    }

    this.iadd = function(other){

        this.x += other.x;

        this.y += other.y;

    }

    this.length = function(){

        return Math.sqrt(this.x*this.x + this.y*this.y);

    }

    this.idiv = function(scalar){

        this.x /= scalar;

        this.y /= scalar;

    }

    this.zero = function(){

        this.x = 0;

        this.y = 0;

    }

    this.validate = function(){

        if(isNaN(this.x+this.y)){

            this.x = 0;

            this.y = 0;

        }

    }

}

            

var Particle = function(canvas){

    var x_speed = Math.random()*2;

    var y_speed = Math.sqrt(16-x_speed^2); // y 값을 계산해서 속력이 4가 되도록 한다.


if(Math.random() <0.5){

x_speed=-x_speed;

}

if(Math.random() <0.5){

y_speed=-y_speed;

}

    var bounce_damping = 1;

    this.velocity = new Vector(x_speed, y_speed)

    this.position = new Vector(

        Math.random() * canvas.width,

        Math.random() * canvas.height

        

    )


    this.step = function(){

        this.position.iadd(this.velocity);


        // border bounce

        if(this.position.x < 0){

            this.position.x = 0;

            this.velocity.x *= -bounce_damping;

        }

        else if(this.position.x > canvas.width){

            this.position.x = canvas.width;

            this.velocity.x *= -bounce_damping;

        }


        if(this.position.y < 0){

            this.position.y = 0;

            this.velocity.y *= -bounce_damping;

        }

        else if(this.position.y > canvas.height){

            this.position.y = canvas.height;

            this.velocity.y *= -bounce_damping;

        }


    }

    this.draw = function(context){

        context.beginPath();

        context.arc(this.position.x, this.position.y, 2.5, 0, Math.PI*2, false);

        context.fill();

    }

}


var System = function(amount, milliseconds){

    var canvas = document.getElementById('particles');

    var context = canvas.getContext('2d');

        

    var particles = [];

    for(var i=0; i<amount; i++){

        particles.push(new Particle(canvas));

    }

       

    setInterval(function(){

       

        // dot drawing style

context.clearRect(0, 0, canvas.width, canvas.height);

        context.globalCompositeOperation = 'lighter'; 

        context.fillStyle = 'rgba(0,0,0,0.9)';


        // nbody code acceleration accumulation

        for(var i=0, il=amount; i<il; i++){

            var a = particles[i];

            a.step();

            a.draw(context);

        }

    }, milliseconds);

}


var main = function(){

    var system = new System(15, 40);

};





설명

 

참고: 이 자바스크립트 코드는 객체를 활용하고 있다. 자바스크립트에서 객체를 활용하는 방법은 인터넷에 많이 소개되어 있으므로 이를 참고하기 바란다.

 

Vector

var Vector = function(x, y){

    this.x = x;

    this.y = y;

 

    this.sub = function(other){

        return new Vector(

            this.x - other.x,

            this.y - other.y

        );

    }

    this.isub = function(other){

        this.x -= other.x;

        this.y -= other.y;

    }

    this.iadd = function(other){

        this.x += other.x;

        this.y += other.y;

    }

    this.length = function(){

        return Math.sqrt(this.x*this.x + this.y*this.y);

    }

    this.idiv = function(scalar){

        this.x /= scalar;

        this.y /= scalar;

    }

    this.zero = function(){

        this.x = 0;

        this.y = 0;

    }

    this.validate = function(){

        if(isNaN(this.x+this.y)){

            this.x = 0;

            this.y = 0;

        }

    }

}

 

Vector xy좌표라는 두 개의 변수를 가지고 있으며, 좌표를 계산할 때 사용할 사칙연산 메소드를 갖고 있다. 예를 들어, 아래와 같은 경우 vec3=vec1-vec2 (-2,-2)가 된다.

var vec1 = new Vector(1, 2);

var vec2 = new Vector(3, 4);

var vec3 = vec1.sub(vec2);

 


Particle

var Particle = function(canvas){

    var x_speed = Math.random()*2;

    var y_speed = Math.sqrt(16-x_speed^2);          // y 값을 계산해서 속력이 4가 되도록 한다.

 

           if(Math.random() <0.5){

                     x_speed=-x_speed;

                                }

           if(Math.random() <0.5){

                     y_speed=-y_speed;

                                }

          

    var bounce_damping = 1;

    this.velocity = new Vector(x_speed, y_speed)

    this.position = new Vector(

        Math.random() * canvas.width,

        Math.random() * canvas.height

       

    )

 

    this.step = function(){

        this.position.iadd(this.velocity);

 

        // border bounce

        if(this.position.x < 0){

            this.position.x = 0;

            this.velocity.x *= -bounce_damping;

        }

        else if(this.position.x > canvas.width){

            this.position.x = canvas.width;

            this.velocity.x *= -bounce_damping;

        }

 

        if(this.position.y < 0){

            this.position.y = 0;

            this.velocity.y *= -bounce_damping;

        }

        else if(this.position.y > canvas.height){

            this.position.y = canvas.height;

            this.velocity.y *= -bounce_damping;

        }

 

    }

    this.draw = function(context){

        context.beginPath();

        context.arc(this.position.x, this.position.y, 2.5, 0, Math.PI*2, false);

        context.fill();

    }

}

 

Particle() x_speed y_speed라는 변수를 가진다. 변수들의 값은 무선적으로 결정되지만, sqrt(x_speed^2+y_speed^2)=4. , 속도(velocity) 4가 되도록 만들었다. , 점의 최초 좌표를 생성한다.

 

Step 메소드는 좌표에 velocity를 더해줘서 점이 한 프레임당 4만큼 이동하도록 만든다. 점이 화면 바깥으로 나가는 것을 방지하기 위해 경계선에 부딪힐 때 velocitybounce_damping(=-1 or +1)변수를 곱해줘서 방향이 반대로 향하도록 만들었다.

 

Draw 메소드는 해당 좌표에 작은 원을 그린다.

 


System

var System = function(amount, milliseconds){

    var canvas = document.getElementById('particles');

    var context = canvas.getContext('2d');

        

    var particles = [];

    for(var i=0; i<amount; i++){

        particles.push(new Particle(canvas));

    }

       

    setInterval(function(){

        // fading

/*

        context.globalCompositeOperation = 'source-out'; //source-out으로 바꿔서 점들의 꼬리를 제거했다

        context.fillStyle = 'rgba(100,100,100)';

        context.fillRect(0, 0, canvas.width, canvas.height);

*/

        // dot drawing style

context.clearRect(0, 0, canvas.width, canvas.height);

        context.globalCompositeOperation = 'lighter'; 

        context.fillStyle = 'rgba(0,0,0,0.9)';


        // nbody code acceleration accumulation

        for(var i=0, il=amount; i<il; i++){

            var a = particles[i];

            a.step();

            a.draw(context);

        }

    }, milliseconds);

}


System은 캔버스에 particle을 그린다. 먼저 particle이라는 배열을 만들고 particle instance들을 모두 저장한다. 그 다음 setinterval 명령어로 각 점들의 step draw 메소드를 실행시켜서 점들을 화면에 그린다.

 

 

Main 

var main = function(){

    var system = new System(15, 40);

};


Main system의 인스턴스를 만든다. 15는 점의 개수, 40 setinterval 명령어가 실행되는 시간 간격을 말한다. 예제의 경우 각 점들은 40 밀리세컨드 단위로 움직이게 될 것이다.

 


글: 인지심리 매니아


필자는 실험 자극을 만들 때 주로 Matlab을 사용해왔다. 하지만 HTML5의 도입으로 인해 이제는 웹에서도 실험 자극을 쉽게 구현할 수 있게 되었다.  그래서 HTML5로 간단한 자극을 만드는 법을 소개하고자 한다. 


오늘은 원운동을 하는 작은 점을 만들고자 한다(필자가 실제로 실험에 사용했던 자극이다).




완성된 자극(IE8 이하 버젼에서는 예제가 보이지 않을 수 있습니다)



소스 코드

<!doctype html>

<html>

  <head>

    <meta charset="UTF-8" />

    <title>Canvas Test</title>

  </head>

<body>

  <section>


    <div>

        <canvas id="canvas" width="800" height="600">

         This text is displayed if your browser 

         does not support HTML5 Canvas.

        </canvas>

    </div>


<script type="text/javascript">

var canvas;  

var ctx;

var x = 100;

var y = 200;

var WIDTH = 400;

var HEIGHT = 400; 

var r=1;                               // 원운동 궤적의 반지름

var i=Math.PI/180;              // (라디안으로 변환한) 1도


function init() {

  canvas = document.getElementById("canvas");

  ctx = canvas.getContext("2d");

  return setInterval(draw, 20);

}



function draw() {

  clear();

  ctx.fillStyle = "#444444";

  circle(x, y, 10);


  x -= r*Math.cos(i);

  y -= r*Math.sin(i);

  i += Math.PI/180;

}


function clear() {

  ctx.clearRect(0, 0, WIDTH, HEIGHT);

}


function circle(x,y,r) {

  ctx.beginPath();

  ctx.arc(x, y, r, 0, Math.PI*2, true);

  ctx.fill();

}


init();


</script>

  </section>

</body>

</html>



이 코드는 Unknown Kadath에 소개된 코드를 필자가 수정한 것이다. 원래는 무선적으로 움직이는 점을 구현하고 있지만, 위 코드에선 점이 원운동을 하도록 수정되었다. 



이 코드의 개요는 다음과 같다.


먼저 init 함수가 실행되면 이 함수가 다시 draw 함수를 호출한다. 호출된 draw 함수는 이전 화면을 지운 다음 새 화면 위에 점을 그린다. Init 함수가 10밀리세컨드 단위로 draw 함수를 반복해서 호출하고, draw 함수는 매번 다른 위치에 점을 그리기 때문에 마치 점이 움직이는는 것처럼 보이게 된다. 




캔버스 지정하기

<canvas id="canvas" width="800" height="600">

This text is displayed if your browser does not support HTML5 Canvas.

</canvas>

먼저 도형을 그릴 캔버스를 지정한다. width는 넓이, height는 높이를 말한다.



초기 변수 지정

var canvas;  

var ctx;

var x = 100;

var y = 200;

var WIDTH = 400;

var HEIGHT = 400; 

var r=1;                               // 원운동 궤적의 반지름

var i=Math.PI/180;              // (라디안으로 변환한) 1도

x,y: 좌표를 의미한다

WIDTH와 HEIGHT: 캔버스의 크기를 의미한다

r: 원운동 궤적의 반지름을 의미한다.

i: 1도를 의미한다



init 함수

function init() {

  canvas = document.getElementById("canvas");

  ctx = canvas.getContext("2d");

  return setInterval(draw, 10);

}

Init 함수는 먼저 “canvas”의 element를 가져온다. 

그 다음 컨텍스트를 정의한다. 모든 캔버스는 컨텍스트를 가지고 있다. 우리가 그릴 그림이나 애니메이션은 모두 컨텍스트 안에서 표현된다. 여기서는 2d context를 선택했다. 

setInterval 함수는 draw 함수를 10 밀리세컨드 간격으로 반복 실행시킨다. 



draw 함수

function draw() {

  clear();

ctx.fillStyle = "#444444";

  circle(x, y, 10);


  i += Math.PI/90;

  x -= r*Math.cos(i);

  y -= r*Math.sin(i);

 

}


Draw 함수는 먼저 Clear 함수를 호출해서 이전 화면(점)을 지운다. 

function clear() {

  ctx.clearRect(0, 0, WIDTH, HEIGHT);

}


그 다음, 점의 색상을 #444444로 지정해 준다. 

그 다음, circle 함수로 작은 점을 그린다. x,y는 원의 좌표, 10은 반지름을 의미한다.

function circle(x,y,r) {

  ctx.beginPath();

  ctx.arc(x, y, r, 0, Math.PI*2, true);

  ctx.fill();

}


그 다음 각도 i의 값을 증가시킨다. 그리고 그 각도를 토대로 새 좌표 x,y를 만든다. 


여기까지가 한 사이클이다. 이후 10밀리세컨드가 지나면 init 함수가 draw 함수를 다시 호출하고, draw 함수는 점을 지운 다음 새 좌표에 점을 찍는다. 


근데, x, y를 계산하는 저 복잡한 공식은 무얼 의미할까?

우리의 목표는 점이 원모양으로 빙글빙글 돌게 만드는 것이다. 점이 원운동을 하려면 좌표가 원모양으로 변하도록 만들어야 한다.  그러려면 삼각 함수를 이용해서 좌표를 구해야 한다. 



단위원. 사진출처-위키피디아




따라서 x=cos(i), y=sin(i)가 된다. 


그럼 i를 구하는 저 복잡한 공식은 무얼 의미할까?

x와 y좌표가 원모양을 따라 변화하려면 각도 i가 증가해야 한다. 문제는 자바스크립트가 호도법의 각도 대신 ‘라디안’을 쓴다는 점이다. 따라서 i가 1도씩 늘어나게 해주려면 Math.PI/180(라디안으로 표현한 1도)을 더해주면 된다. 

'More'을 클릭하면 용어 해설을 볼 수 있습니다.


계산이론

공간 기반 주의(Space-based attention)

대상 기반 주의(Object-based attention)

병목 이론(Bottleneck Theory)

부적 점화 현상

분리 주의(Divided Attention)

세부특징분석모형(Feature Analysis)

세부특징통합이론(Feature Integration Theory)

실인증(Agnosia)

약화 모형(Attenuation Theory)

여과기 모형(Filter Model)

유도탐색이론(Guided Search Theory)

자동 처리

칵테일파티 현상(Cocktail Party Effect)

형판맞추기모형(Template Matching)

후기선택모형

Central Capacity Theory

Multitude Theory


'인지심리이론 > 개론' 카테고리의 다른 글

인지심리학  (0) 2011.10.31
인지과학 개론 - 이정모 교수님  (7) 2011.09.15

인지심리학은 심리학의 하위학문이며 인간 내부의 심적 과정을 탐구한다. 인지심리학은 인간의 지각, 기억, 사고, 언어, 문제 해결을 연구한다.

인지심리학은 기존의 심리학 접근방법과 두 가지 면에서 차이가 있다.

  • 인지심리학은 과학적 조사 방법을 사용하며 직관(내성)에 의한 관찰을 사용하지 않는다. 이는 프로이트 심리학과 다른 점이다.
  • 인지심리학은 인간 내부의 심적 상태가 존재함을 인정한다(예, 믿음, 욕구, 생각, 지식, 동기 등)

인지심리학은 경험적인 연구 방법이 내부의 심적 상태를 관찰하기에 적합하지 않다는 비판을 받기도 했다. 하지만 인지신경과학을 통해 뇌의 상태가 심적 상태와 직접적으로 상관이 있다는 증거를 얻게 되었다. 이를 통해 인지심리학의 가정이 지지를 받게 되었다.

이런 접근 방식을 채택한 학파를 인지주의라고 부른다.


역사

나이서(Ulric Neisser)는 1967년 그의 저서 '인지심리학'에서 인지심리는 인간을 역동적 정보처리시스템으로 규정하며 인간의 정신적 작동을 계산적 용어로 기술할 수 있다고 주장했다. 또 인지심리는 마음이 개념적 구조를 가지고 있다고 보는 관점이라고 강조했다. 나이서의 관점은 심리학의 연구 분야를 '사고'과 같은 상위 개념까지 확장했다. 나이서가 정의한 '인지' 개념은 이를 반영한다.

  • “인지”는 감각 정보가 변형, 축소, 정교화, 저장, 복구, 사용되는 모든 과정을 일컫는다. 또 인지는 이미지나 환각처럼 감각 정보가 없는 경우에 발생하는 현상과도 관련있다… 이런 정의를 고려할 때, 인지는 인간이 할 수 있는 모든 것과 관련있음이 분명하다. 모든 심리적 현상이 곧 인지적 현상이다. 하지만 인간의 모든 과정을 다룸에도 불구하고 인지심리학 역시 특정한 관점일 뿐이다. 다른 관점 또한 마찬가지로 타당하다. 감각 정보 대신 동기에서 출발하는 역동심리학을 예로 들 수 있다. 역동심리학은 인간이 보고, 기억하고, 믿는 것이 어떻게 행동을 만드는지 묻는 대신, 개인의 목표, 욕구, 본능을 묻는다.

인지심리학은 심리학 연구 분야에 가장 나중에 편입되었으며, 노암 촘스키가 행동주의와 경험주의를 비판하며 촉발된 '인지 혁명' 이후 독립된 학문으로 발전해왔다. 마음을 계산적 이론으로 설명하는 시도는 17세기 데카르트로 거슬러 올라가며, 1940년~50년 알란 튜링에 의해 계승되었다. 인지적 접근방식은 1958년 브로드벤트(Broadbent)의 'Perception and Communication'이 출판되면서 부각되었으며 당시 지배적인 패러다임이던 정보처리모델을 발전시켰다. 이 접근방식은 사고와 추론을 컴퓨터에서 동작하는 소프트웨어로 비유하며, 정보의 입력, 표상, 처리과정, 출력을 설명한다. 인지심리학은 언어가 정신적 지식 표상 체계로 이루어져 있다고 가정함으로써 network mental model을 만들었다. 그 결과 탄생한 의미망이라는 개념은 인공지능과 심리학 전반에 큰 기여를 했다. 인지심리학자 중 한 사람이었던 조지 밀러는 1985년부터 영어의 sementic network인 Wordnet을 개발하였으며, 후에 machine 온톨로지에 근간이 되었다.


주요 연구 분야


지각

    General perception

    정신물리학

    주의와 Filter 이론 (특정 자극에만 주의를 주고 나머지 자극은 무시하는 능력)

    패턴 인식 (불분명한 감각 정보를 바르게 해석하는 능력)

    물체 재인

    시간 감각 (시간 경과에 대한 인식이나 예측)

    형태 지각

 

범주 

    범주 추리와 습득

    범주 판단과 분류

    범주 표상과 구조

    유사성

 

기억

    노화와 기억

    자서전적 기억

    구성적 기억

    정서와 기억

    일화 기억

    목격자 기억

    오기억

    섬광 기억

    기억의 편향

    장기 기억

    의미 기억

    단기 기억

    작업 기억

 

지식표상 

    심상

    명제

    이중부호화 이론


언어

    문법과 언어학

    음성학과 음운론

    언어 습득


사고 

    선택

    개념 형성

    의사결정

    논리적 추론

    문제해결

 

'인지심리이론 > 개론' 카테고리의 다른 글

인지심리학 용어사전  (0) 2012.06.20
인지과학 개론 - 이정모 교수님  (7) 2011.09.15
성균관대 이정모 교수님이 배포용으로 제작하신 인지과학 개론 PDF입니다.

링크 바로가기

'인지심리이론 > 개론' 카테고리의 다른 글

인지심리학 용어사전  (0) 2012.06.20
인지심리학  (0) 2011.10.31

+ Recent posts