The AAA algorithm provides a natural way to identify LTI (linear time-invariant) system parameters such as poles, zeros and DC gain from Bode plots. For example, consider the 4th order system $$ G(s) = 2\frac{(1+105s)(1+\frac{1.4}{0.05}s+\frac{1}{0.05^2}s^2)}{(1+100s)(1+\frac{1.4}{0.04}s+\frac{1}{0.04^2}s^2)(1+s)} $$

Nc = [8.4e4 6.68e3 2.66e2 2];             % numerator coefficients
Dc = [6.25e4 6.6625e4 4.26e3 1.36e2 1];   % denominator coefficients
N = @(s) Nc*s.^[3:-1:0]';
D = @(s) Dc*s.^[4:-1:0]';
G = @(s) N(s(:))./D(s(:));                % system transfer function

for which we have the following:

pol = roots(Dc), zer = roots(Nc), DCgain = abs(G(0))
pol =
 -1.000000000000001 + 0.000000000000000i
 -0.028000000000000 + 0.028565713714171i
 -0.028000000000000 - 0.028565713714171i
 -0.010000000000000 + 0.000000000000000i
zer =
 -0.035000000000000 + 0.035707142142714i
 -0.035000000000000 - 0.035707142142714i
 -0.009523809523810 + 0.000000000000000i
DCgain =
     2

Let's sample some values in the frequency range $10^{-4}\leq \omega \leq 10^2$, and draw the Bode plots of magnitude and phase:

w = logspace(-4,2,3000);
mag = abs(G(i*w)); ph = -angle(G(i*w));
LW = 'linewidth'; LO = 'location'; SW = 'southwest';
subplot(211), semilogx(w,20*log10(mag),'b-'), grid on
title('Magnitude (dB)')
subplot(212), semilogx(w,ph*180/pi,'b-'), grid on
title('Phase (degrees)')

Given magnitude and phase, an approximation $H(s)$ for $G(s)$ is readily obtained by AAA approximation of the complex signal. Samples are mirrored in order to enforce symmetry.

wA = [-fliplr(w) w]; magA = [fliplr(mag) mag]; phA = [-fliplr(ph) ph];
GA = magA.*exp(i*phA);            % complex signal
[H,polA,resA,zerA] = aaa(GA,i*wA);
polA, zerA, DCgainA = abs(H(0))   % relevant parameters
subplot(211), hold on, semilogx(w,20*log10(abs(H(i*w))),'k--')
legend('G(s)','AAA',LO,SW)
subplot(212), hold on, semilogx(w,angle(H(i*w))*180/pi,'k--')
legend('G(s)','AAA',LO,SW)
polA =
 -0.999999999999993 + 0.000000000000045i
 -0.027999999999904 + 0.028565713714183i
 -0.009999999998222 - 0.000000000000566i
 -0.028000000001871 - 0.028565713713665i
zerA =
 -0.035000000000000 + 0.035707142142714i
 -0.035000000000000 - 0.035707142142714i
 -0.009523809523810 - 0.000000000000000i
DCgainA =
   1.999999999999999

Also, $H(s)$ shows negligible errors in initial data:

err_mag = norm(mag-abs(H(i*w)),inf)
err_ph = norm(ph-angle(H(i*w)),inf)
err_mag =
     4.884981308350689e-15
err_ph =
     2.569992829659640e-15

The following means of recomputing poles will play a key role in what follows. In the case when they aren't computed in complex conjugate pairs, which is a necessary condition for $H(s)$ to represent a physical model, we discard the imaginary parts of the corresponding polynomials and extract the new roots (poles). Here, poles and zeros do match:

[NcA,DcA] = residue(resA,polA,[]);
polA = roots(real(DcA)), zerA = roots(real(NcA))
polA =
 -0.999999999999993 + 0.000000000000000i
 -0.028000000000887 + 0.028565713713924i
 -0.028000000000887 - 0.028565713713924i
 -0.009999999998222 + 0.000000000000000i
zerA =
 -0.035000000000529 + 0.035707142142959i
 -0.035000000000529 - 0.035707142142959i
 -0.009523809523871 + 0.000000000000000i

Now let's complicate things a little bit. A reduced order approximation, useful in applications to simplify analysis and control design, is obtained by calling the AAA algorithm with a low degree. 20 Lawson iterations under the hood place our scarce resource (poles) at best, though not necessarily in complex conjugate pairs, hence we force a recomputation, and eventually solve a least-squares problem. This idea is a variant of the AAA-LS method introduced in [1].

Going back to our approximation problem, with a 2nd order reduction we expect two real distinct poles for the reduced $H_r(s)$. Note that in this case a straightforward zero-pole (over)simplification, leaving with $1/(1+s)$, wouldn't really be acceptable, and AAA-LS finds a decent compromise:

[~,polAr] = aaa(GA,i*wA,'degree',2);
polAr = roots(real(poly(polAr)));   % pole recomputation
d = min(abs(i*wA(:)-polAr.'),[],1);
Q = d./(i*wA(:)-polAr.');
c = Q\GA.';                         % solve LS problem, new residues c
Hr = @(s) [d./(s(:)-polAr.')]*c;
[NAr] = residue(c,polAr,[]);
zerAr = roots(real(NAr)), polAr, DCgainAr = abs(Hr(0))
subplot(211), semilogx(w,20*log10(abs(Hr(i*w))),'c-'), hold off
legend('G(s)','AAA','reduced order AAA',LO,SW)
subplot(212), semilogx(w,angle(Hr(i*w))*180/pi,'c-'), hold off
legend('G(s)','AAA','reduced order AAA',LO,SW)
zerAr =
  -0.294963170363907
polAr =
  -0.798508392918573
  -0.035811189966051
DCgainAr =
   2.036869044252427

To see how good AAA-LS actually is, consider the scalar example with noise found in [2], i.e. $$ f(s) = (s-1)/(s^2+s+2). $$ The function is sampled at 500 logarithmically spaced points in the interval [0.1,10], and then normally distributed noise with a standard deviation of $10^{-2}$ is added:

Nc = [1 -1]; Dc = [1 1 2];
N = @(s) Nc*s.^[1 0]';
D = @(s) Dc*s.^[2 1 0]';
f = @(s) N(s(:))./D(s(:));
w = logspace(-1,1,500); mag = abs(f(i*w)); ph = -angle(f(i*w));
mag = mag+0.01*randn(1,length(mag)); ph = ph+0.01*randn(1,length(ph));
subplot(211), semilogx(w,20*log10(mag),'r-'), grid on
title('Magnitude (dB)')
subplot(212), semilogx(w,ph*180/pi,'r-'), grid on
title('Phase (degrees)')

We compute a rational approximant of degree only 2 using the above method. The AAA-LS approximant shows no significant deviations from the measurements, at least in the eyeball norm. This time the number of Lawson iterations is increased, to enhance their filtering effect:

wn = [-fliplr(w) w]; magn = [fliplr(mag) mag]; phn = [-fliplr(ph) ph];
fn = magn.*exp(i*phn);
[~,poln] = aaa(fn,i*wn,'degree',2,'lawson',30);
poln(find(real(poln)>0)) ~= -1;   % force system stability
poln = roots(real(poly(poln)));
dn = min(abs(i*wn(:)-poln.'),[],1);
Qn = dn./(i*wn(:)-poln.');
cn = Qn\fn.';
Hn = @(s) [dn./(s(:)-poln.')]*cn;
subplot(211), hold on, semilogx(w,20*log10(abs(Hn(i*w))),'b-'), hold off
legend('Noisy data','AAA approximant',LO,SW)
subplot(212), hold on, semilogx(w,angle(Hn(i*w))*180/pi,'b-'), hold off
legend('Noisy data','AAA approximant',LO,SW)

The poles are decently approximated, even in these perturbed conditions, as shown by the coefficients of the denominator:

Dcn = poly(poln)
Dcn =
   1.000000000000000   1.001449519203945   1.998358534005181

The AAA-LS approximant effectively estimates the additive noise rather accurately, both in magnitude and in phase:

subplot(211), loglog(w,abs(mag(:)-abs(Hn(i*w))),'r-',LW,.5), grid on
title('Estimated noise in magnitude'), axis([min(w) max(w) 1e-5 1e-1]);
subplot(212), loglog(w,abs(ph(:)-angle(Hn(i*w))),'r-',LW,.5), grid on
title('Estimated noise in phase'), axis([min(w) max(w) 1e-5 1e-1]);

[1] S. Costa and L. N. Trefethen, AAA-least squares rational approximation and solution of Laplace problems, Proceedings of the 8ECM, 2021.

[2] I. V. Gosea and S. Güttel, Algorithms for the rational approximation of matrix-valued functions, arXiv:2003.06410v2, 2021.