TL;DR: Why does the (pseudo-)code below produce a different output than a proper simulation software? Edit: -> Answer: The program (RFSim99) displays only abs, not squared (which is what I plotted). Hadn't even considered that as an option.

Full problem description: I want to be able to simulate simple (idealized) RF circuits, such as resonators, filters etc, in a self-written program (I currently use python). The first circuit I attempted the simplest example of just a capacitor:

(Port1)-(27pF capacitor)-(Port2)

The way I implemented this is the following (pseudocode):

Z0 = 50
func YC(f,C) = 1j*2𝜋*f*C
func ZR(f) = 1/YC(C=27e-12) + Z0
func s11(f) = (ZR(f) - Z0)/(ZR(f) + Z0)
func s21(f) = ZR(f)/Z0
plot(abs(s21(x))^2, abs(s11(x))^2, x={1,...,10e9})

This gave me something which is very similar to what I'd expect: Result of this simple simulation

But if I compare that with a very simple software (RFsim99, all ideal models) Result of the RFsim99 simulation

This small, but not negligible discrepancy can also be seen in slightly more complicated circuits, like a simple resonator circuit (see below). I am wondering where the discrepancy could come from.

What I've tried so far: I tried several things like adding series 50𝛺 'resistors' to emulate the admittance of the ports; I checked weather my chosen language (python) handles the inversion of complex numbers well and it does. I checked time and again if the RFsim-Software has some 'more physical' model for it's components, but since you can explicitly turn these off and on (and I have them turned off) and the manual doesn't say anything, I strongly believe, that it should be an 'ideal' model. I tried using more physical models for the capacitor (by adding inductive and resistive elements), but to no avail.

Question: Does anyone have any new (see above) ideas or suggestions?

Here are the 5GHz resonator's results:

Simple 5Ghz resonator circuit My simple simulation's result RFsim99's result

P.S.: If you have a more accurate title, please feel free to change it!

  • \$\begingroup\$ P.P.S.: I didn't use log-scale, because the discrepancies can be seen more clearly like this. \$\endgroup\$ – 3244611user Sep 22 '17 at 15:29
  • \$\begingroup\$ Can you export results from the simulator and then plot them in Python on the same charts as your results? Given the simulator plot doesn't label the output scales, etc., it's hard to see exactly how your result is different from theirs. \$\endgroup\$ – The Photon Sep 22 '17 at 18:26
  • \$\begingroup\$ For example, are you sure the simulator is plotting \$|S_{11}|^2\$ and not just \$|S_{11}|\$? \$\endgroup\$ – The Photon Sep 22 '17 at 18:27
  • \$\begingroup\$ Yes, plotting both of them in the same graph would be possible, but quite a hassle. I did compare certain points though and are positive on the fact, that they are different. I just tried plotting it not squared an in fact it looks way more similar. I'm too tired to check if it fits exactly now, but it looks promising. Will update tomorrow. That'd be a stupid mistake :o \$\endgroup\$ – 3244611user Sep 22 '17 at 22:18
  • \$\begingroup\$ Oh, this is so embarrassing :o I actually did what you just suggested, exported it as s2p and plotted it together - et voilà; the program displays only abs, not squared. Hadn't even considered that. Thanks a lot! \$\endgroup\$ – 3244611user Sep 24 '17 at 12:08

func s11(f) = ZR(f)/Z0

This is not correct. You should be using something that computes $$S_{11}(f) = \frac{Z_L - Z_0}{Z_L + Z_0}$$ where \$Z_L\$ is the cascade of the filter and the load connected on its port 2.

What the error is in your \$S_{21}\$ calculation, I didn't notice with a quick look.

Edit: the error in your \$S_{21}\$ calculation is that you calculate \$S_{11}\$ and call it s21.

  • \$\begingroup\$ Ups, I accidentally mixed s21 and s11 up (but only in the pseudo-code). But unfortunately that doesn't change the outcome. \$\endgroup\$ – 3244611user Sep 22 '17 at 16:14

I have numerically calculated both examples using octave/matlab and LTspice, and both show at first sight the same results:

Example 1 : DC Block

f=logspace(1,9, 100);
ZL=1./(2*pi.*f*i*C) + Z0;
semilogx(f,abs(s11.^2), '-', f,abs(s21.^2),'-');
grid on;


and with LTSpice:


For the second example (resonator):

f=linspace(4.9e9, 5.1e9 , 10000);
ZL=L*2*pi.*f*i*Z0./(Z0*C*L.*(2*pi.*f*i).^2 + L*2*pi.*f*i + Z0);
plot(f,abs(s11.^2), '-', f,abs(s21.^2),'-');
grid on;


and with LTSpice:


As you can see they have a very good match. As for the discrepancies in the original question, I could think of the following ones:

  1. Simulation and mathematical method do not use the same amount of sampling points.
  2. Sampling points are too small, meaning that the points in between are interpolated.
  3. Not sure about other Spice simulators, but LTSpice add as default series resistances to inductors, which at this high frequency can make a difference due to its lower quality factor.
  • 1
    \$\begingroup\$ Thank you for your answer, I appreciate the effort you went through.. some time after I started the bounty I actually found a small mistake in my own math, and after sorting it out I was able to get my own model working, this was long before you posted this answer, but I didn't know what to do about the bounty, and besides I was busy.. So I realized already that the OP simply, just like me, has made a small error in the math.. That said I hope you got something out of it yourself :) at least the bounty is yours. \$\endgroup\$ – Vinzent May 25 '20 at 17:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.