0

I have an analytical model of an electrical circuit, the output of which is a transfer function in the s-domain, I am using LMFIT to fit the values of the components of the circuit to get the resulting TF to best fit a measured data-set.

I want to make my code more modular, and I thought a good way to do it would be something like the following;

import lmfit as lm

z1 = lm.models.ExpressionModel('r1 + l1 * x')

z2 = lm.models.ExpressionModel('1 / (c1 * x)')

rlc = z1 * z2 / (z1 + z2)

where x in this case is s, the complex independent variable of the form; s = 2 * pi * j * f

I know that in order to fit complex data you need to wrap the function in one which produces a real output, but in the end when fitting the resulting CompositeModel I will be taking the magnitude (abs()) of the TF, I just want to know;

Question 1:

Can lmfit.models.ExpressionModel handle complex expressions? (as in containing a complex variable)

..and;

Question 2 (optional):

If not, can I do this with lmfit.Model instead? ie. just defining an objective function which returns a complex value and then feeding it to lmfit.Model like so;

def _z1(s, r1, l1):
    return r1 + l1 * s

z1 = lm.Model(_z1)

It says in the documentation for lmfit.Model that it automatically generates the residual function, but does this ever get used if I only ever fit the resulting composite model using my own residual function?

and also;

Question 3:

Would this be ill-advised? ie. would it result in significant overhead?

Vinzent
  • 1,070
  • 1
  • 9
  • 14

1 Answers1

1

I believe that ExpressionModel() would work with complex values. But I would still recommend your approach in Q2: define a function that does the work, as it will be easier to trouble-shoot and expand when needed.

And, yes, the independent data and calculation done can definitely include complex values. But, while your calculation may be complex, the returned residual needs to be purely real. The simplest way to do this is to return real/imag pairs using the view method of the numpy array:

return complex_array_for_residual.view(np.float)

You could consider returning mag/phase pairs, though it is slightly more complicated, as you have to deal with phase jumps in phase.

Just to be clear, I regularly fit using Fourier transforms that give complex results, and just turn that into "real/imag" pairs with ndarray.view.

M Newville
  • 7,486
  • 2
  • 16
  • 29
  • Thanks for the answer, I still don't understand though from your answer if I can return complex data from the models and have that complex data from each model be added, multiplied etc. without problems?, I can't convert the result to magnitude and phase before returning it because that ruins the whole concept of just being able to do algebra on the impedances I create models of, the data each of the models return has to be complex, I can only convert it to magnitude/phase before fitting/ before taking the residual.. – Vinzent Jun 24 '20 at 08:30
  • @Vinzent I updated the answer to more explicitly describe using `ndarray.view` to get the real and imaginary pairs into an array that is purely float - and yes, the model function does need to return a float (64-bit) array. – M Newville Jun 24 '20 at 11:39