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:
son los datos de entrada, es la respuesta y es un vector de coeficientes de valor complejo. El objetivo es estimar a partir de y observaciones ruidosas . 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 como [2;3+4i;-.5+.4i]
. Tome las observaciones como exponencialmente distribuidas. Añada ruido de valor complejo a las respuestas .
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 y respuesta cplxydata
para ) 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:
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.