Main Content

이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.

복소수 값 데이터에 모델 피팅하기

이 예제에서는 복소수 값 데이터의 비선형 피팅을 수행하는 방법을 보여줍니다. 대부분의 Optimization Toolbox™ 솔버 및 알고리즘은 실수 값 데이터에서만 작동하는 반면, 최소제곱 솔버와 fsolve는 제약 조건이 없는 문제에 대해 실수 값 데이터와 복소수 값 데이터 모두에서 작동할 수 있습니다. 목적 함수가 복소 함수 측면에서 해석적이어야 합니다.

복소수 데이터 사용 시 FunValCheck 옵션을 'on'으로 설정하지 마십시오. 솔버에서 오류가 발생합니다. 'interior-point' 알고리즘을 lsqcurvefit 또는 lsqnonlin과 함께 사용하지 마십시오. 이 알고리즘은 주로 제약 조건을 처리하기 위한 것이며, 복소수 데이터와 함께 사용하는 것에 대해서는 검증되지 않았습니다.

데이터 모델

데이터 모델은 다음과 같이 단순한 지수입니다.

$$y(x) = v_1 + v_2 e^{v_3 x}.$$

$x$는 입력 데이터이고, $y$는 응답 변수이고, $v$는 계수로 구성된 복소수 값 벡터입니다. $x$와 잡음 있는 관측값 $y$에서 $v$를 추정하는 것이 목적입니다. 데이터 모델은 해석적이므로 이를 복소수 해에서 사용할 수 있습니다.

잡음이 있는 인위적인 데이터

모델에 사용할 인위적인 데이터를 생성합니다. 복소수 계수 벡터 $v$[2;3+4i;-.5+.4i]로 지정합니다. 관측값 $x$를 지수 분포로 지정합니다. 응답 변수 $y$에 복소수 값 잡음을 추가합니다.

rng default % for reproducibility
N = 100; % number of observations
v0 = [2;3+4i;-.5+.4i]; % coefficient vector
xdata = -log(rand(N,1)); % exponentially distributed
noisedata = randn(N,1).*exp((1i*randn(N,1))); % complex noise
cplxydata = v0(1) + v0(2).*exp(v0(3)*xdata) + noisedata;

계수 벡터를 복구하기 위해 모델 피팅하기

데이터 모델이 예측한 응답 변수와 관측값($x$에 해당하는 xdata$y$에 해당하는 응답 변수 cplxydata) 간의 차이는 다음과 같습니다.

objfcn = @(v)v(1)+v(2)*exp(v(3)*xdata) - cplxydata;

lsqnonlin 또는 lsqcurvefit를 사용하여 데이터에 모델을 피팅합니다. 이 예제에서는 먼저 lsqnonlin을 사용합니다.

opts = optimoptions(@lsqnonlin,'Display','off');
x0 = (1+1i)*[1;1;1]; % arbitrary initial guess
[vestimated,resnorm,residuals,exitflag,output] = lsqnonlin(objfcn,x0,[],[],opts);
vestimated,resnorm,exitflag,output.firstorderopt
vestimated =

   2.1582 + 0.1351i
   2.7399 + 3.8012i
  -0.5338 + 0.4660i


resnorm =

  100.9933


exitflag =

     3


ans =

    0.0018

lsqnonlin은 복소수 계수 벡터를 약 하나의 유효 자릿수로 복구합니다. 잔차에 대한 노름은 상당한 크기인데, 이는 잡음으로 인해 모델이 모든 관측값을 피팅하지는 못함을 나타냅니다. 종료 플래그는 3인데(1이 바람직하지만), 그 이유는 1차 최적성 측정값이 1e-6 미만이 아니라 약 1e-3이기 때문입니다.

대안: lsqcurvefit 사용

lsqcurvefit를 사용하여 피팅하려면, 응답 변수에서 응답 변수 데이터를 빼는 것이 아니라 응답 변수만 제공하도록 모델을 작성합니다.

objfcn = @(v,xdata)v(1)+v(2)*exp(v(3)*xdata);

lsqcurvefit 옵션 및 구문을 사용합니다.

opts = optimoptions(@lsqcurvefit,opts); % reuse the options
[vestimated,resnorm] = lsqcurvefit(objfcn,x0,xdata,cplxydata,[],[],opts)
vestimated =

   2.1582 + 0.1351i
   2.7399 + 3.8012i
  -0.5338 + 0.4660i


resnorm =

  100.9933

기본 알고리즘이 동일하기 때문에 결과는 lsqnonlin의 결과와 일치합니다. 더 편리하다고 생각되는 솔버를 사용하십시오.

대안: 실수부와 허수부 분리

범위를 포함하려면 또는 단순히 실수 값 내에 온전히 유지하려면, 계수의 실수부와 허수부를 별도의 변수로 분리할 수 있습니다. 이 문제에서 계수를 다음과 같이 분리합니다.

$$ \begin{array}{l}
y = {v_1} + i{v_2} + ({v_3} + i{v_4})\exp \left( {({v_5} + i{v_6})x} \right)\\
\ \ = \left( {{v_1} + {v_3}\exp ({v_5}x)\cos ({v_6}x) - {v_4}\exp ({v_5}x)\sin ({v_6}x)} \right)\\
\ \ + i \left( {{v_2} + {v_4}\exp ({v_5}x)\cos ({v_6}x) + {v_3}\exp ({v_5}x)\sin ({v_6}x)} \right).
\end{array}$$

lsqcurvefit에 대한 응답 함수를 작성합니다.

function yout = cplxreal(v,xdata)

yout = zeros(length(xdata),2); % allocate yout

expcoef = exp(v(5)*xdata(:)); % magnitude
coscoef = cos(v(6)*xdata(:)); % real cosine term
sincoef = sin(v(6)*xdata(:)); % imaginary sin term
yout(:,1) = v(1) + expcoef.*(v(3)*coscoef - v(4)*sincoef);
yout(:,2) = v(2) + expcoef.*(v(4)*coscoef + v(3)*sincoef);

이 코드를 MATLAB® 경로에 파일 cplxreal.m으로 저장합니다.

응답 변수 데이터를 실수부와 허수부로 분리합니다.

ydata2 = [real(cplxydata),imag(cplxydata)];

계수 벡터 v는 이제 6개 차원을 가집니다. 이를 모두 1로 초기화하고 lsqcurvefit를 사용하여 문제를 풉니다.

x0 = ones(6,1);
[vestimated,resnorm,residuals,exitflag,output] = ...
    lsqcurvefit(@cplxreal,x0,xdata,ydata2);
vestimated,resnorm,exitflag,output.firstorderopt
Local minimum possible.

lsqcurvefit stopped because the final change in the sum of squares relative to 
its initial value is less than the value of the function tolerance.


vestimated =

    2.1582
    0.1351
    2.7399
    3.8012
   -0.5338
    0.4660


resnorm =

  100.9933


exitflag =

     3


ans =

    0.0018

요소를 6개 가진 벡터 vestimated를 요소를 3개 가진 복소수형 벡터로 해석합니다. 해가 이전 해와 사실상 동일함을 알 수 있습니다.

관련 항목