Is there a way to determine an equivalent circuit for Nyquist diagrams (I have the data set) using Matlab (or Simulink)?

I am working on gathering some Nyquist diagrams experimentally and facing some difficulties on simulating equivalent circuits for my data. What I have done so far is simply trying to come up with an idea of an equivalent circuit and seen if it fits the case. Well this is obscure and it is not always representative of what has been going on. So is it possible to use Matlab to construct/simulate equivalent circuits from experimental data?

 채택된 답변

I am not certain what you want witth respect to an equivalent circuit. I believe you intend circuit synthesis or circuit realisation. If so, this may do what you want
First, using your data, identify the system using the System Identification Toolbox, specifically using the iddata and tfest functions to return a transdfer function.
When you have the transfer funciton that gives an appropriate fit to your data (check this using the using the compare function) you can then use circuit synthesis to identify the component values.
Illustrating that with a Cauer expansion (you will probably need to extract the transfer function numerator and denominator polynomials from the identified transfer function and then use the poly2sym function on each of them first) —
syms s
H = (2*s^5+40*s^3+128*s)/(s^4+10*s^2+9)
[Hn1,Hd1] = numden(H)
T1 = quorem(Hn1,Hd1)
H2 = Hn1/Hd1 - T1
[Hn2,Hd2] = numden(H2)
T2 = quorem(Hd2,Hn2)
H3 = Hd2/Hn2 - T2
[Hn3,Hd3] = numden(H3)
T3 = quorem(Hd3,Hn3)
H4 = Hd3/Hn3 - T3
[Hn4,Hd4] = numden(H4)
T4 = quorem(Hd4,Hn4)
H5 = Hd4/Hn4 - T4
[Hn5,Hd5] = numden(H5)
T5 = quorem(Hd5,Hn5)
That can be coded as a loop —
denpoly = [1 1]; % Define First (Used To Terminate The ‘while’ Loop)
syms s
H = (2*s^5+40*s^3+128*s)/(s^4+10*s^2+9)
k = 0;
H = 1/H;
while numel(denpoly) > 1 % Loop Version (Can Be A Function)
k = k + 1;
% disp("k = "+k)
[Hn,Hd] = numden(1/H);
denpoly = sym2poly(Hd);
Comp(k) = quorem(Hn,Hd);
H = Hn/Hd - Comp(k);
if k > 50 % Fail-Safe To Prevent Infinite Recursion
disp("Exiting loop (k = "+k+" )")
break
end
end
fprintf(['Component Values: \n',repmat('\t\t\t%s\n',1, numel(Comp)), '\n'], Comp)
Component Values: 2*s s/20 (40*s)/9 (9*s)/140 (70*s)/9
These would be configured as:
>---- 2 H ----- 40/9 H ---- 70/9 H ---->
| |
1/20 F 9/40 F
| |
>-------------------------------------->
This is a textbook example, and gives the same result as in W-K Chen, Passive and Active Filters Wiley 1986 (ISBN 0-471-82352-X), P. 113. There are other approaches that may also be appropriate, such as the Foster expansion.
This may not always work as desired in ‘real world’ transfer functions, in that the component (‘Comp’ vector) values may not be simple functions of s as they are here, and may instead be vectors. Those results would not be valid.
(There is some sort of bug in Answers such that the results of symbolic calculations do not appear in the posted results, although they appear in the results while being run or edited. This has been reported, although apparently not yet fixed.)
.

댓글 수: 5

I did not see the .txt file previously.
T1 = readtable('EIS_Data.txt')
T1 = 81x7 table
Var1 Var2 Var3 Var4 Var5 Var6 Var7 ____ ______ ______ _________ ______ ________ ______ 1 1e+05 24.849 -1.6686 24.905 -3.8417 3613.3 2 79433 25.23 -1.1891 25.258 -2.6984 3614.5 3 63096 25.487 -0.83996 25.501 -1.8875 3615.8 4 50119 25.646 -0.57313 25.652 -1.2802 3617.1 5 39811 25.746 -0.35511 25.748 -0.79022 3618.3 6 31623 25.828 -0.16443 25.828 -0.36477 3619.5 7 25119 25.889 0.0061794 25.889 0.013676 3620.7 8 19953 25.933 0.16953 25.933 0.37455 3621.9 9 15849 25.991 0.34144 25.993 0.75264 3623.1 10 12589 26.024 0.51434 26.029 1.1322 3624.3 11 10000 26.079 0.70367 26.088 1.5456 3626.4 12 7943.3 26.137 0.9182 26.153 2.012 3627.5 13 6309.6 26.199 1.1643 26.225 2.5445 3628.7 14 5011.9 26.268 1.4509 26.308 3.1615 3629.8 15 3981.1 26.346 1.7956 26.407 3.8989 3631 16 3162.3 26.447 2.1982 26.538 4.7514 3632.2
figure
semilogy(T1{:,1}, T1{:,2:end})
grid
Warning: Negative data ignored
It would help significantly to know what the variable names are.
Their names are:
Var1: index Var2: frequency (Hz) Var3: Z’ Var4: -Z’’ Var5: Z Var6: Phase Var7: Time(s)
I doubt that it is possible to do what you want.
The System Identification Toolbox will not permit impropeer transfer functions (more zeros than poles), however the invfreqz funciton will, and that allows the use of the example loop in my original answer. Plotting the imaginary part of thee response function, there are two obvious polees and two obvious zeros, however eveene allowing for three of each, the result is not good, and it is likely not poossible to estimate the equivalent circuit compnent values.
T1 = readtable('EIS_Data.txt');
T1.Properties.VariableNames = {'Index','Frequency (Hz)','Z’','-Z’’','Z','Phase (°)','Time(s)'};
T1 = flipud(T1)
T1 = 81x7 table
Index Frequency (Hz) Z’ -Z’’ Z Phase (°) Time(s) _____ ______________ ______ ______ _____ _________ _______ 81 0.001 28835 11433 31018 21.628 7636.7 80 0.0012589 26376 9182.4 27928 19.195 6839.6 79 0.0015849 24259 7888.8 25509 18.014 6205.8 78 0.0019953 22567 6806.4 23571 16.784 5701.8 77 0.0025119 21247 5966.4 22069 15.685 5300.9 76 0.0031623 21018 5269.1 21668 14.074 4981.9 75 0.0039811 20385 5367.1 21080 14.75 4727.9 74 0.0050119 19767 5629.1 20553 15.895 4525.6 73 0.0063096 18763 6286.7 19788 18.524 4364.3 72 0.0079433 17404 6722.3 18657 21.119 4235.6 71 0.01 16146 7079 17630 23.674 4132.8 70 0.012589 14836 7368.7 16565 26.412 4050.6 69 0.015849 13401 7457.6 15337 29.095 3984.7 68 0.019953 11978 7367.8 14063 31.596 3931.8 67 0.025119 10643 7178.7 12838 34 3889.3 66 0.031623 9459.9 6926.2 11724 36.21 3854.8
Zz = T1.Z .* exp(1j*deg2rad(T1.('Phase (°)')))
Zz =
1.0e+04 * 2.8835 + 1.1433i 2.6376 + 0.9182i 2.4259 + 0.7889i 2.2567 + 0.6806i 2.1247 + 0.5966i 2.1018 + 0.5269i 2.0385 + 0.5367i 1.9767 + 0.5629i 1.8763 + 0.6287i 1.7404 + 0.6722i 1.6146 + 0.7079i 1.4836 + 0.7369i 1.3401 + 0.7458i 1.1978 + 0.7368i 1.0643 + 0.7179i 0.9460 + 0.6926i 0.8441 + 0.6590i 0.7491 + 0.6132i 0.6538 + 0.5697i 0.5724 + 0.5334i 0.4984 + 0.4901i 0.4280 + 0.4536i 0.3672 + 0.4117i 0.3119 + 0.3740i 0.2625 + 0.3370i 0.2182 + 0.3009i 0.1815 + 0.2671i 0.1494 + 0.2352i 0.1220 + 0.2053i 0.0993 + 0.1782i 0.0806 + 0.1536i 0.0652 + 0.1314i 0.0528 + 0.1119i 0.0428 + 0.0949i 0.0347 + 0.0801i 0.0283 + 0.0674i 0.0232 + 0.0565i 0.0191 + 0.0472i 0.0158 + 0.0394i 0.0132 + 0.0328i 0.0111 + 0.0273i 0.0095 + 0.0227i 0.0081 + 0.0188i 0.0071 + 0.0155i 0.0062 + 0.0129i 0.0056 + 0.0106i 0.0050 + 0.0088i 0.0046 + 0.0072i 0.0042 + 0.0060i 0.0039 + 0.0049i 0.0037 + 0.0041i 0.0035 + 0.0034i 0.0033 + 0.0028i 0.0032 + 0.0023i 0.0031 + 0.0019i 0.0030 + 0.0016i 0.0029 + 0.0013i 0.0029 + 0.0011i 0.0028 + 0.0009i 0.0028 + 0.0007i 0.0027 + 0.0006i 0.0027 + 0.0005i 0.0027 + 0.0004i 0.0027 + 0.0003i 0.0027 + 0.0003i 0.0026 + 0.0002i 0.0026 + 0.0002i 0.0026 + 0.0001i 0.0026 + 0.0001i 0.0026 + 0.0001i 0.0026 + 0.0001i 0.0026 + 0.0001i 0.0026 + 0.0000i 0.0026 + 0.0000i 0.0026 + 0.0000i 0.0026 - 0.0000i 0.0026 - 0.0000i 0.0026 - 0.0001i 0.0025 - 0.0001i 0.0025 - 0.0001i 0.0025 - 0.0002i
[pks,plocs] = findpeaks(imag(Zz))
pks = 7.4576e+03
plocs = 13
[vys,vlocs] = findpeaks(-imag(Zz))
vys = -5.2691e+03
vlocs = 6
figure
semilogx(T1.('Frequency (Hz)'), imag(Zz))
xline(T1{vlocs,2}, "--", "Zero at "+T1{vlocs,2}+" Hz")
xline(T1{end,2}, "--", "Zero at \infty")
xline(T1{1,2}, "--", "Pole at "+0+" Hz")
xline(T1{plocs,2}, "--", "Pole at "+T1{plocs,2}+" Hz")
grid
Ts = 1/(2*T1{end,2})
Ts = 5.0000e-06
FRD = idfrd(Zz, T1{:,2}, 0, FrequencyUnit="Hz")
FRD = IDFRD model. Contains Frequency Response Data for 1 output(s) and 1 input(s). Response data is available at 81 frequency points, ranging from 0.001 Hz to 1e+05 Hz. Status: Created by direct construction or transformation. Not estimated.
H = tfest(FRD, 3, 3)
H = 135.5 s^3 - 9894 s^2 + 3461 s - 33.78 -------------------------------------- s^3 - 1.516 s^2 + 0.1741 s - 0.0009052 Continuous-time identified transfer function. Parameterization: Number of poles: 3 Number of zeros: 3 Number of free coefficients: 7 Use "tfdata", "getpvec", "getcov" for parameters and their uncertainties. Status: Estimated using TFEST on frequency response data "FRD". Fit to estimation data: 93.18% FPE: 3.7e+05, MSE: 3.111e+05
figure
compare(FRD, H)
[n,d] = invfreqz(T1.Z, pi*T1{:,2}/max(T1{:,2}), 3, 2)
n =
25.5393 + 0.0000i -19.3942 + 0.0000i -6.2018 + 0.0000i 0.0414 + 0.0000i
d = 1×3
1.0000 -0.7675 -0.2325
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
syms s
H = poly2sym(n, s) / poly2sym(d, s);
H = vpa(H, 5)
denpoly = [1 1]; % Define First (Used To Terminate The ‘while’ Loop)
% H = (2*s^5+40*s^3+128*s)/(s^4+10*s^2+9)
k = 0;
H = 1/H;
while numel(denpoly) > 1 % Loop Version (Can Be A Function)
k = k + 1;
% disp("k = "+k)
[Hn,Hd] = numden(1/H);
denpoly = sym2poly(Hd);
Comp(k,:) = quorem(Hn,Hd);
H = Hn/Hd - Comp(k);
if k > numel(n) % Fail-Safe To Prevent Infinite Recursion
disp("Exiting loop (k = "+k+" )")
break
end
end
Exiting loop (k = 5 )
Comp
fprintf(['Component Values: \n',repmat('\t\t\t%s\n',1, numel(Comp)), '\n'], Comp)
Component Values: 25.539328994993411470204591751099*s + 0.20731612002625994524526597373373 -2.0251778048585542304637838241455e+33 0.84088068659373764250606804836843 -3.7342879783753092480919040857715e+33 1.0416026769877003014621786628326
[n,d] = invfreqz(T1.Z, pi*T1{:,2}/max(T1{:,2}), 4, 3)
n =
25.7373 + 0.0000i -10.6290 + 0.0000i -56.4978 + 0.0000i 40.9715 + 0.0000i 0.4071 + 0.0000i
d = 1×4
1.0000 -0.4015 -2.2181 1.6196
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
syms s
H = poly2sym(n, s) / poly2sym(d, s);
H = vpa(H, 5)
denpoly = [1 1]; % Define First (Used To Terminate The ‘while’ Loop)
% H = (2*s^5+40*s^3+128*s)/(s^4+10*s^2+9)
k = 0;
H = 1/H;
while numel(denpoly) > 1 % Loop Version (Can Be A Function)
k = k + 1;
% disp("k = "+k)
[Hn,Hd] = numden(1/H);
denpoly = sym2poly(Hd);
Comp(k,:) = quorem(Hn,Hd);
H = Hn/Hd - Comp(k);
if k > numel(n) % Fail-Safe To Prevent Infinite Recursion
disp("Exiting loop (k = "+k+" )")
break
end
end
Exiting loop (k = 6 )
Comp
fprintf(['Component Values: \n',repmat('\t\t\t%s\n',1, numel(Comp)), '\n'], Comp)
Component Values: 25.737341071715491125360131263733*s - 0.29468450204495539471168568198593 0 0.000000000000000000000000000000011794331925250881809574821090791 - 0.00000000000000000000000000000002*s -2.5e+64 4.0e-65 - 3.3995677546215990365035307866664e-129*s 0
This is the best I can do with these data.
(I initially began this comment yesterday, however Windows 11 crashed — again — so I lost everytthing and had to start over. My apologies for the delay.)
.
Wow! @Star Strider Thank you so much! I didn't reply to you before because I've just seen your answer. Now I will study your code and try to apply to other cases I encountered.
Eventhough it is not possible to estimate an equivalent circuit directly, it gives me a way to work on that.
As always, my pleasure!
This is not exactly a straightforward problem. I am not certain how best to solve it, however hypothesizing a two-pole and two-zero equivalent ciircuit of some sort (there are likely several ways to configure it) and then doing nonlinear parameter estimation to identify the component values would likely be the way to go. The pole at the origin is likely close to it (so the negative real component is likely very small). however the zero at 0.0032 Hz and the pole at 0.015 Hz have much larger (greater magnitude) negative real parts, since the zero value does not go to zero and the pole does not go to infinity, so they are relatively far away from the imaginary axis.
The fun lies in estimating them! Fortunately, MATLAB has a number of nonlinear parameter estimation and optimisation algorithms (including Global Optimization Toolbox functions such as ga) that make that task much easier.
No worries about the time — we all have lives away from MATLAB Answers!
.

댓글을 달려면 로그인하십시오.

추가 답변 (3개)

I'm unfamiliar with your circuit system. However, if you have the data in the form of frequency-response, then you can apply the frd() and nyquistplot() commands
data = [
0.0010 1.562e+01-1.9904i
0.0018 1.560e+01-2.0947i
0.0034 1.513e+01-3.3670i
0.0062 1.373e+01-5.4306i
0.0113 1.047e+01-7.5227i
0.0207 5.829e+00-7.6529i
0.0379 2.340e+00-5.6271i
0.0695 7.765e-01-3.4188i
0.1274 2.394e-01-1.9295i
0.2336 7.216e-02-1.0648i
0.4281 2.157e-02-0.5834i
0.7848 6.433e-03-0.3188i
1.4384 1.916e-03-0.1740i
2.6367 5.705e-04-0.0950i
4.8329 1.698e-04-0.0518i
8.8587 5.055e-05-0.0283i
16.2378 1.505e-05-0.0154i
29.7635 4.478e-06-0.0084i
54.5559 1.333e-06-0.0046i
100.0000 3.967e-07-0.0025i
];
freq = data(:,1);
resp = data(:,2);
sys = frd(resp, freq);
figure
np = nyquistplot(sys); grid on
figure
bd = bodeplot(sys); grid on, grid minor
Yes you can. The experimental data needed for Nyquist and Bode plots is the same: a set of magnitudes and phases, or (equivalently) real and imaginary parts, at a set of frequencies, f. The Bode plot shows the frequencies on the plot. The frequencies are not explicit on the Nyquist plot, but I assume you have the frequencies in your experimental data.
You make a guess, based on experience and the appearance of th Bode plot or Nyquist plot, of the circuit type (high pass, low pass, etc) and number of components. Then you compute the expected theoretical frequency response , which will be a complex function involving the values of R. C, L, etc. in your circuit. Then you compare it to the measured frequency response, , which is also complex, and which you have measured in your experiment at a set of frequencies. Then you adjust the values of R, C, L, etc., in order to minimize the error between and . The error is the sum of the squared distances in the complex plane between and at the measured frequencies. You can use Matlab's fmincon() to find the values of the unknown parameters (R, L, C,...) that minimize the error.
If the system is a filter, where the input and output have the same units (typically volts), then you have no informatopn about the overal circuit impedance because you don;t know what current is flowing. Then there may be many equivalent solutions that give the same frequency response. If this is true, then there is no unique solution forr the component values. So you fix one of the component values (for example, you specify that you want impedance Z=100 Ω at DC, which fixes one of the R values in the circuit). Then you solve for the other unknown parameters.
If your best-fit model response does not look like the experimental data, then try a different theoretical circuit.

댓글 수: 1

Here is an example of what I meant in my answer above.
Files simulatedFilterResponse{0,1,2}.txt contains Nyquist plot data from three simulated experiments. Each file has 3 columns: frequency (rad/s), real part of Gmeas, imaginary part of Gmeas, where Gmeas is the measured frequency response. The measurement noise has relative amplitude 0, 1, 2 on files 0, 1, 2 respectively.
The main script, fitFreqResponse.m, minimizes the error between a model and the data, by adjusting the values of R, L, and C for a second order filter circuit. After finding the best-fit values, the script displays the best-fit values, and plots the measured and best-fit transfer functions. The script calls external function sumsqerr(p,w,Gmeas), where p=[R;L;C] are the adjustable parameters, w is the vector of frequencies, and Gmeas is the experimental data: a complex vector of measured frequency responses. Function sumsqerr() calculates the model transfer function and the sum squared error betwen the model and the measured data.
If your experimental data does not look like a second order lowpass filter, then adjust the line Gmodel=..., in function file sumsqerr1.m. Also change the line Gfit=... in the main script, so that Gfit and Gmodel match. (Gfit is used to plot the best-fit transfer function after the best fit circuit component values have been found.)
The simulated Nyquist plot data is from the circuit below, with R=100 Ω, L=0.1125 H, C=22.51 .
When I estimate R, L, C from the noise-free Nyquist plot data (simulatedFilterResponse0.txt), I get exactly correct estimates for R, L, C. When I edit the main script so that it reads a file of noisy Nyquist plot data (simulatedFilterResponse1.txt), the estimated R, L, C values are not quite the same. See below.
fitFreqResponse
Local minimum possible. Constraints satisfied. fmincon stopped because the size of the current step is less than the value of the step size tolerance and constraints are satisfied to within the value of the constraint tolerance. R=100.0 ohm, L=1.992e-01 H, C=1.424e-05 F, RMSE=0.131.

댓글을 달려면 로그인하십시오.

Thank you for your responses. This is new to me, my they are widening my mind. Some of you said you are unfamiliar with my data. So here it goes as attachment. What I am trying to do is to propose a circuit that represents it. This kind of data is from electrochemical phenomena and I usually try to guess the circuit and evaluate some reports about errors to decide if I can accept my guess or if I should reject it and propose another circuit. This is my first attempt at doing it numerically so I would really appreciate it if you could help me out by using my experimental data. The Nyquist Diagram and the Bode Plot are as follows.
Nyquist Diagram
Bode Plot

댓글 수: 2

It would be helpful to have your actual data. The best option is time-domain data, however if all you have is frequency-domain data, that could also work.
With time-domain data we can simulate time-domain and frequency-domain results, however with only frequency-domain data, we can only simulate frequency-domain results.
Oh, okay! All I have is the data I attached before as a .txt document. I'm also attaching it as .xlsx. One of the seven columns is time(s); i'm just not sure if it helps it work.

댓글을 달려면 로그인하십시오.

카테고리

도움말 센터File Exchange에서 Simscape Electrical에 대해 자세히 알아보기

질문:

2024년 10월 4일

댓글:

2024년 10월 15일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by