개인적으로 MATLAB의 가장 큰 장점 중 하나는 강력한 그래프 출력 기능이라고 생각한다. 

실제로 나를 포함한 많은 대학원생들 및 연구자들이 매트랩을 이용해서 지금 이 순간에도 이쁜 그래프를 얻기 위해 편집과 수정을 반복하고 있을 것이다. 

 

 하지만, 그럼에도 불구하고 종종 내 모니터에서 보던 이쁜 그래프는 온데간데 사라지고 저장해뒀던 그래프를 불러면 일주일 넘게 가출했다가 거지몰골로 돌아온 행색처럼 보인다. 분명히 선도 깔끔하고 마커 사이즈도 적당하고 폰트도 모든것이 완벽했는데 EPS 포맷의 그래프는 그 모든것을 부정해버리는 것 같다. 

 

 실제로 구글을 해보면 이러한 문제에 대해 호소하는 전 세계 유저들의 글을 쉽게 찾아 볼 수 있다. 

그럼 도대체 왜 이런 현상이 벌어지는 거고 우리가 원하는 이쁜 그래프는 어떻게 그릴수 있고 얻을 수 있는걸까?

 

 일단 이러한 차이가 발생하는 가장 큰 이유는 '그림의 크기를 고려하는 단위(관점)의 차이'이다.

즉, 자신의 모니터 해상도에 따른 픽셀의 수를 기준으로 그림의 크기를 조정하기 때문에 위와 같은 문제가 발생하는 것이다. 매트랩은 기본적으로 그림 파일을 출력할 때 그림의 크기를 기본적으로 A4로 지정하고 있기 때문에 figure의 크기를 A4의 물리적 사이즈에 맞춰서 설정해줘야 한다. 

 

 위에서 언급한 문제들에 대해서 정확한 원인과 해결 방법을 상세하게 설명해 둔 'AureaGenus'님의 글이 있으니 참고하면 좋을 것 같다. [링크]

나 또한 비슷한 내용으로 고민했는데 해당 글을 참고하여 원하는 사이즈와 형태의 EPS 그래프를 얻을 수 있었다. 

 

 매트랩에서는 하나의 figure안에 여러개의 그래프를 그리기위해 subplot 함수를 종종 이용하는데, 문제는 subplot내의 여백이 꽤나 크다는 점이다. 따라서 subplot을 이용하여 EPS 포맷으로 그대로 저장하게 되면 각 subfigure의 그림들이 매우 작아 보이게 되어 가독성이 떨어지는 그래프가 만들어지게 된다. 

 

아래의 코드는 subplot 2X2에 대한 예제이다. 

위에서 참고한 방법과는 조금 다르게 접근한 방식인데, 전체 figure(not subplot)의 사이즈만 정해주고, 

subplot들의 사이즈를 늘이거나 줄이는 방식을 통해 전체 figure의 사이즈에 딱 맞게 조절하였다. 

물론 이 경우엔 약간의 노가다가 필요하지만, 그래프나 텍스트의 사이즈 및 특성에 따라 자유롭게 조절이 가능하여 subplot을 EPS 포맷으로 저장할 때 원하는 사이즈에 맞춰서 저장할 수 있다. 

Subplot_example.m
0.00MB

clear all, close all, clc;

%%
fig_width = 8;  		% Figure width size [inch]
fig_height = 7; 		% Figure height size[inch]

hFig = figure(1);
set(hFig,'renderer','painters');
set(hFig,'units','inches');
set(hFig,'position',[3 2 fig_width fig_height]);
set(hFig,'PaperUnits','inches');			% Figure의 사이즈 단위를 'inch'로 설정
set(hFig,'PaperSize', [fig_width fig_height]);
set(hFig,'PaperPositionMode', 'manual');
set(hFig,'PaperPosition',[0 0 fig_width fig_height]);
set(hFig,'Color','w');

fontname = 'times new roman';
set(0,'defaultaxesfontname',fontname);
set(0,'defaulttextfontname',fontname);
fontsize = 9; % pt
set(0,'defaultaxesfontsize',fontsize);
set(0,'defaulttextfontsize',fontsize);
set(0,'fixedwidthfontname','times');

%%
Line_Style = {'-d', '-h', '-s', '-.>', '--v'};
Line_Color = [ {'[1 0 0]'}, {'[0 0.4470 0.7410]'}, {'[0.4660 0.6740 0.1880]'}, {'[0 0 0]'}, {'[0.72, 0.27, 1.00]'}];
Legend_List = {'A-scheme', 'B-scheme', 'C-scheme', 'D-scheme' };
Size_Marker = 4;
Line_Size = [0.5 0.5 0.5 0.5 0.5];
label_FontSize = 10;

%%
x = linspace(0, 1, 50);
y(1,:) = sin(2*pi*x);
y(2,:) = cos(2*pi*x);
y(3,:) = 1.5*sin(2*pi*x);
y(4,:) = 1.5*cos(2*pi*x);

sub_pos = [0.06 0.53 0.42 0.33 ; ...
                0.56 0.53 0.42 0.33 ; ...
                0.06 0.09 0.42 0.33 ; ...
                0.56 0.09 0.42 0.33];

for idx=1:4
  subFig=subplot(2,2,idx); 
  plot(x, y(idx,:) , Line_Style{idx}, 'MarkerSize', Size_Marker, ...
      'Color', Line_Color{idx}, 'LineWidth', Line_Size(idx) ), grid on, hold on;
   xlabel('Time [s]', 'FontSize', label_FontSize, 'FontName', 'times');
   ylabel('Voltage [V]', 'FontSize', label_FontSize, 'FontName', 'times');
   legend(Legend_List(idx), 'FontSize', 7, 'FontName', 'times', 'NumColumns', 2);
   set(subFig, 'position', sub_pos(idx,:));
end


 매트랩은 기본적으로 벡터와 행렬 연산을 기반으로(주로) 동작합니다. 

따라서 매트랩 프로그래밍을 하는 과정중에 알고리즘에 의해 행렬이나 벡터의 원소 위치를 랜덤하게 바꾸어야(섞거나)하는 상황이 생기기도 합니다. 


 사실 포스팅 하기에는 매우 단순한 함수를 사용하지만 간혹 모르시는 분들이 계셔서 올려봅니다. 


그럼 간단한 예제와 함께 살펴보겠습니다.


예제 1) 


%일단 3x3 행렬을 만들어 보도록 하겠습니다. 

>> A=[1 2 3 ; 4 5 6 ; 7 8 9]

A= 

     1     2     3 
     4     5     6 
     7     8     9 

%이때, 행렬 A의 특정 위치의 원소값을 행과 열을 위치로 확인이 가능하지만 행렬의 전체 원소의 개수에 따라서 확인이 가능합니다. 

%매트랩은 기본적으로 열(column)벡터를 기준으로 연산하기 때문에 A(1)=1, A(3)=7, A(4)=2, etc., 와 같은 순서대로 배치가 됩니다.

%그럼 이어서 A 행렬의 첫번째 열의 순서를 랜덤하게 재배치 해보도록 하겠습니다.

>>idx = randperm(3)

idx = 

      3 1 2 

% randperm(n) 함수는 1에서 n(구간의 끝점 포함)까지의 정수로 구성된 난수 순열을 행 벡터로 

% 반환합니다. 즉, 내가 재배치하고 싶은 벡터의 길이(n)에 맞춰 난수를 생성하여 사용하면 됩니다.

>> A( : , 1 ) = A( idx, 1)

A = 

     7     2     3

     1     5     6

     4     8     9 

% A 행렬의 첫번째 열벡터의 원소 순서가 바뀐걸 확인할 수 있습니다. 

예제 2)


% 예제1을 응용하면 아까 말씀드린 행렬 원소 전체를 랜덤하게 재배치할 수 있습니다.

>> A=[1 2 3 ; 4 5 6 ; 7 8 9]

A= 

     1     2     3 
     4     5     6 
     7     8     9 

>>idx2 = randperm( numel(A) )

% randperm함수를 이용해서 A 행렬의 원소 개수에 맞춰 난수를 생성해봅시다. 이때 numel(A) 함수는 A의 전체 원소개수를 출력해줍니다. 

%즉, 여기서는 A행렬의 원소가 9개이니 numel(A)의 값은 9가 되겠죠? 

idx2 =

     5     1     8     2     9     7     3     4     6

>>A = A(idx2)

A = 

      5     1     6     4     9     3     7     2     8

% A(idx2) = A(5), A(1), A(8),... A(6) 을 의미하게 됩니다. 그러면 각각의 원소값을 확인해보면 A(5)=5, A(1)=1, A(8)=6,... 이 되니까 이 순서대로 재배치가 되겠죠?

% 하지만 우리가 원하는건 행벡터가 아닌 처음 3x3 행렬의 형태이니 다시 원래대로 돌려 놓습니다.

>>A = reshape(A,3,3)

A =
     5     4     7
     1     9     2
     6     3     8
% randperm 함수로 생성한 난수를 이용해 A 행렬의 원소를 랜덤하게 재배치 했습니다. 

예제 3)


%예제 1과 2에서 배운 내용을 한꺼번에 정리해서 아래와 같이 사용하시면 됩니다. 

A = reshape( A( randperm( numel(A) ) ), 3, 3);


이번 포스팅은 randperm 함수를 이용한 행렬 원소의 재배치에 대해서 알아보았습니다. 


 항상 느끼는 거지만 매트랩에는 정말 많은 함수들이 구현되어 있는 만큼 내가 모르는 함수도 많기 때문에 매트랩을 사용하시다가 막히시는 부분이 있으면 구글링을 먼저 해보시면 분명히 원하는 기능을 하는 함수나 혹은 기능 구현의 부분적인 함수를 찾으실 수 있습니다. 


 매트랩에는 기본적으로 optimization toolbox가 제공되어 사용할 수 있습니다. 

하지만 개인적으로 사용법이 직관적이지 않아 처음 사용하는데 애를 많이 먹었습니다. 

그러던 중 전에 들었던 최적화 이론 수업 교수님이 말씀해주신 CVX tool이 생각나서 찾아서 사용해봤는데 아직까지는 매트랩에서 제공되는 optimization toolbox 보다는 훨씬 더 사용하기 편하고 직관적인 것 같습니다. 


 CVX guide book에 있는 소개는 간단하게 다음과 같습니다.

CVX is a modeling system for constructing and solving disciplined convex programs (DCPs). CVX supports a number of standard problem types, including linear and quadratic programs (LPs/QPs), second-order cone programs (SOCPs), and semidefinite programs (SDPs). CVX can also solve much more complex convex optimization problems, including many involving nondifferentiable functions, such as `1 norms. You can use CVX to conveniently formulate and solve constrained norm minimization, entropy maximization, determinant maximization, and many other convex programs. 

As of version 2.0, CVX also solves mixed integer disciplined convex programs (MIDCPs) as well, with an appropriate integer-capable solver. 


 CVX 및 CVX 가이드 다운로드는 공식홈페이지에서 가능합니다.

다운로드 파일은 아래의 표를 참조하셔서 자신의 OS에 맞는 파일을 선택하시면 됩니다. 

(가이드북CVX_guide book.pdf



 다운로드 후 설치 방법은 매우 간단합니다. 해당 다운로드 파일의 압축을 푸신 후 아래의 그림과 같이 해당 폴더를 평소에 사용하시는 matlab path로 이동시키신 후에 그 폴더에서 'cvx_setup' 이라고 커맨드 명령어를 치시기만 하면 됩니다. 




Generate random points inside a circle with radius R





  이번 포스팅은 매트랩을 이용해 반지름이 R인 임의의 원을 생성하고 그 내부에 임의의 점(point)을 생성하는 방법에 대해 소개하겠습니다. 

 

 내용 및 과정 자체는 매우 심플하여 어렵지 않으나 이러한 구현은 다양한 연구분야에서 시스템 환경으로 활용됩니다. 실제로 제가 연구하고 있는 cognitive radio 시스템이나 localization에서 시뮬레이션을 위해 사용하고 있으며 이 외에 다른 여러 분야에서도 응용가능합니다. 



그림 1. 반지름이 10인 원



 그림 1과 같이 반지름(radius, r)이 10인 원을 먼저 그려보도록 하겠습니다. 일단 원을 그리기 위해선 기본적으로 원의 중점과 반지름을 설정해야 합니다. 


%% 원 그리기 

x1 = 0;  % 원 중심의 x좌표

y1 = 0;  % 원 중심의 y좌표

rc = 10; % 원의 반지름

[x,y] = cylinder(rc,200);  % z축의 파라미터를 입력할 경우 3차원의 원통형이 생성되지만 여기서는
                               % 2차원의 원만 표기하기 위해 z축 파라미터는 사용하지 않습니다. 

                               % 총 200개의 요소로 이루어진 원의 바운더리 좌표가 x, y에 각각 저장

figure(1)

plot(x(1,:)+x1, y(1,:)+y1, 'b', 'LineWidth', 2), hold on, grid on;

%앞에서 설정한 원의 중심값을 각 x, y좌표에 더해줌으로써 (x1,y1)을 중점으로 하는 반지름 10인 원을 그려주게 됩니다.'

title(['\fontsize{15}Radius=',num2str(rc)]);

xlabel('[m]'), ylabel('[m]');

코드 1. 반지름이 rc인 원 생성하기


위 코드대로 입력하시면 그림 1과 동일한 원을 그리실 수 있습니다. 

그러면 이제 그 원 안에 임의의 점(point)를 생성해보도록 하겠습니다. 



먼저 해당 코드를 짜기 전에 간단하게 어떤 방식으로 임의의 점을 생성시킬지 생각해봅시다.


1) 원의 중심을 기준으로 가장 멀리 떨어진 점의 거리(길이)를 반지름 이하가 되도록 한다. 

  -> rc값 이하의 임의의 숫자를 생성( r = rc*sqrt(rand) )

2) 원의 중심을 기준으로 임의의 라디안을 생성한다.

  -> gen_rad = 2*pi*rand;

3) 1)과 2)에서 생성한 값을 이용해 원의 중점(x1, y1)으로부터 임의의 위치에 point를 생성한다.

  -> x = r*cos(a)+x1, y = r*sin(a)+y1;


그러면 위에서 설명하 내용을 바탕으로 코딩을 진행해보도록 하죠. 


%% 반지름이 rc인 원 생성

x1 = 0;  % 원 중심의 x좌표

y1 = 0;  % 원 중심의 y좌표

rc = 10; % 원의 반지름

[x,y] = cylinder(rc,200);  % z축의 파라미터를 입력할 경우 3차원의 원통형이 생성되지만 여기서는 
                               % 2차원의 원만 표기하기 위해 z축 파라미터는 사용하지 않습니다. 

                               % 총 200개의 요소로 이루어진 원의 바운더리 좌표가 x, y에 각각 저장

figure(1)

plot(x(1,:)+x1, y(1,:)+y1, 'b', 'LineWidth', 2), hold on, grid on;

%앞에서 설정한 원의 중심값을 각 x, y좌표에 더해줌으로써 (x1,y1)을 중점으로 하는 반지름 10인 원을 그려주게 됩니다.'

title(['\fontsize{15}Radius=',num2str(rc)]);

xlabel('[m]'), ylabel('[m]');

%% 임의의 점 생성

a = 2*pi*rand( 1, length(x) );

r = sqrt( rand( 1, length(x) ) );

x11 = rc.*r.*cos(a) + x1;

y11 = rc.*r.*sin(a) + y1;

plot(x11, y11, '.r')

코드 2. 반지름이 rc인 원 생성 후 내부에 임의의 점 생성 


코드 2와 같이 코드 1의 뒤에 해당 부분을 추가해주면 모든 코딩이 끝나고 그림 2와 같이 나타나게 됩니다.


그림 2. 반지름이 rc인 원 내부에 임의의 포인트 생성


 

 또한 여기서 생성하는 임의의 포인트 숫자를 줄이거나 늘릴 수 있는데요, 코드 2부분에서 변수 ar의 길이를 생성할때 length(x)로 정의 했기 때문에 코드 1에서 생성한 원 바운더리의 포인트 갯수 (201개)와 동일하게 생성했습니다. 따라서, 임의의 점 개수를 늘리고 싶으시다면 해당 부분의 숫자를 조절해주시면 됩니다. 

 

다음번 포스팅은 위 예제를 이용한 푸아송 점 과정(Poisson point process) 예제를 진행해보도록 할게요 : )


Homework2.pdf


//첨부된 pdf 파일에 몇 가지 예제가 포함되어 있습니다//



<1-a~e>


첫번째 실습 예제에 관련된 코딩입니다.

물론 저도 학기 중에 배우면서 한거라 코드가 최적화되지 않았을 수도 있고, 중간중간 불필요한 코드가 들어있을 수 있으므로 

적당히 자체 필터링 하셔서 보시면 됩니다. ㅋㅋㅋㅋㅋㅋ 


저는 이때 당시 (2012) Matlab 2008 버전을 사용했는데, 어둠의 경로로 구한 프로그램이여서 그런지 혹은 원래 그런건지는 

모르겠지만 제 매틀랩에는 impulse function과 step function이 존재하지 않았습니다.

하지만 부끄럽게도 매틀랩이란 걸 처음 써봤기에 이때 당시 함수의 유무 조차도 몰랐기 때문에 당연히 

코딩 할때부터 첫줄부터 에러가..... 하하하하하


혹시나 저같은 분이 있을까봐 가지런히 파일 첨부 해놓았습니다. 


impseq.m


stepseq.m


파일 그대로 다운 받으셔서 매틀랩에서 m 파일 불러오기 하셔서 추가하시면 바로 사용 가능합니다 !! 



위 예제를 위와 같은 코딩 후 컴파일 하게 되면 바로 위와 같은 그래프가 나오게 됩니다. 






<2-a>


코드를 보시게 되면 ' stepseq(1,-10,10)'와 같은 형태로 3개의 변수를 적어 넣게 되는데, 첫번째 변수는 함수의 시작점,

 step function이 '1'이라는 값에서 시작되게 됩니다. 그리고 '-10'과 '10'이 의미하는 숫자는 boundary(경계선)를 지정해 주는 겁니다. 

그렇다면 -10부터 0까지는 '0'이라는 값이 생기고 1부터 10까지는 '1'이라는 값을 갖게 됩니다.

'impseq'도 마찬가지로 같은 방법으로 사용하시면 됩니다. 





아까 위 예제와는 조금 다른 그래프가 나왔는데요, 첫번째 그래프에는 'stem'이라는 명령어만 사용하여 discrete(이산)형태로만

나타내었고 지금 이 그래프는 'stem'과 'plot' 두가지를 사용하여 discrete뿐 만 아니라 continuous 형태도 같이 나타내었습니다. 

예제를 보시면 아시겠지만 예제에선 서로 다른 형태의 식을 주었지만 결국 그 각각의 결과값을 나타낸 두개의 그래프를 비교해보면 

그 값은 정확히 일치 합니다. 

Convolution의 특징을 이해하기 위한 예제겠죠 ?


+ Recent posts