Main Content

La traducción de esta página aún no se ha actualizado a la versión más reciente. Haga clic aquí para ver la última versión en inglés.

Ajustar un modelo a datos de valores complejos

Este ejemplo muestra cómo realizar el ajuste no lineal de datos con valores complejos. Mientras que la mayoría de los algoritmos y solvers de Optimization Toolbox™ solo funcionan con datos de valores reales, los solvers de mínimos cuadrados y fsolve pueden funcionar tanto con datos de valores reales como de valores complejos en problemas sin restricciones. La función objetivo debe ser analítica en el sentido de una función compleja.

No establezca la opción FunValCheck en 'on' cuando use datos complejos. El solver da error. No utilice el algoritmo 'interior-point' con lsqcurvefit o lsqnonlin, porque se utiliza principalmente para gestionar restricciones y no se ha validado para trabajar con datos complejos.

Modelo de datos

El modelo de datos es una exponencial simple:

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

$x$ son los datos de entrada, $y$ es la respuesta y $v$ es un vector de coeficientes de valor complejo. El objetivo es estimar $v$ a partir de $x$ y observaciones ruidosas $y$. El modelo de datos es analítico, por lo que lo puede utilizar en una solución compleja.

Datos artificiales con ruido

Genere datos artificiales para el modelo. Tome el vector de coeficientes complejos $v$ como [2;3+4i;-.5+.4i]. Tome las observaciones $x$ como exponencialmente distribuidas. Añada ruido de valor complejo a las respuestas $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;

Ajustar el modelo para recuperar el vector de coeficientes

La diferencia entre la respuesta predicha por el modelo de datos y una observación (xdata para $x$ y respuesta cplxydata para $y$) es:

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

Utilice lsqnonlin o lsqcurvefit para ajustar el modelo a los datos. Este ejemplo usa primero 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 recupera el vector de coeficientes complejos hasta aproximadamente un dígito significativo. La norma del valor residual es considerable, lo que indica que el ruido impide que el modelo se ajuste a todas las observaciones. El indicador de salida es 3 y no 1, que es el preferible, porque la medida de optimalidad de primer orden está alrededor de 1e-3, no por debajo de 1e-6.

Alternativa: usar lsqcurvefit

Para realizar el ajuste utilizando lsqcurvefit, escriba el modelo para obtener solo las respuestas, no las respuestas menos los datos de respuesta.

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

Utilice la sintaxis y las opciones de 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

Los resultados coinciden con los de lsqnonlin, porque los algoritmos subyacentes son idénticos. Use el solver que le resulte más cómodo.

Alternativa: dividir partes reales e imaginarias

Para incluir límites, o simplemente para mantenerse totalmente dentro de los valores reales, puede dividir las partes reales y complejas de los coeficientes en variables separadas. Para este problema, divida los coeficientes de la siguiente manera:

$$ \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}$$

Escriba la función de respuesta para 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);

Guarde este código como el archivo cplxreal.m en la ruta de MATLAB®.

Divida los datos de respuesta en sus partes real e imaginaria.

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

El vector de coeficientes v tiene ahora seis dimensiones. Inicialícelo como todo unos y resuelva el problema usando 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

Interprete el vector de seis elementos vestimated como un vector complejo de tres elementos y verá que la solución es prácticamente la misma que las anteriores.

Temas relacionados