Op-Amps and State Space Extraction

I’m trying to extract the state space of a filter containing an op-amp and I’m consistently getting a state space that is equivalent in offset but with a smaller amplitude. I used the state_space_matrices example to set up the script to get the A, B, C, D matrices. I copied these and corrected their syntax to paste into their appropriate fields in the State Space block. I separated the pre-filter and extracted its state space matrices to verify I was extracting the state space correctly, as well as to verify the error stems from the Op-Amp portion of the physical circuit.

The first thing I find odd is the inclusion of “VAMCin” and “VAMCout” in the state space. Especially since the Op-Amp block has a similar internal setup. I would’ve expected these blocks to be omitted the same as the Op-Amp internals.

The second thing I find odd is the gain block “AMC1301” is ignored by plecs('get', modelName, 'Topology'). The state space blocks required the gain block to be included externally, where I would’ve expected the gain to be incorporated into the matrix element values.

I’ve attached the schematic for reference. There are three systems being compared:

  1. The physical circuit, which is isolated using “VAMCin”, “AMC1301”, and “VAMCout”.
  2. The state space block “Full State Space” which contains the topology output, starting from controlled voltage source “V” and ending at voltmeter “Vo”. The output state for “VAMCin” is looped back through “AMC1301” to the input state for “VAMCout”.
  3. Two state space blocks “Pre-Amp” and “OpAmp” which was made by extracting the topology of the isolated circuit elements separately. “Pre-Amp” passes through “AMC1301” before arriving to “OpAmp”.
  • Both (2) and (3) use the constant block “[Vos Vref]” which contains the values of the constant voltage sources “Vos” and “Vref” respectively. These fill the additional inputs of the extracted state spaces.

What am I doing wrong? Should I be adjusting my script in some way? Should I be approaching this extraction differently with my schematic layout?

Voltmeter Van_TF Extract.plecs (62.6 KB)

Hi @HPI_GHunsicker

You did not really make a modeling error here. The discrepancy is mainly caused by numerical conditioning and by the limited precision of the values copied from the Octave Console.

Some of the resistances in the original model are set to 1e-9 With the other component values, this leads to entries on the order of 1e19 in the state-space matrices of the amplifier. This makes the system numerically ill-conditioned.
I therefore changed these resistances to 1e-3. This is still small enough to have essentially no influence on the circuit behavior, but it improves the numerical conditioning significantly.

The second issue is the precision of the matrices copied from the Octave Console. PLECS Standalone uses GNU Octave for simulation scripts, and the default console output does not show the full precision of the double values.
If the displayed matrix values are copied directly into the State Space block, this loss of precision is enough to produce the small offset you observed in the amplifier model.

Adding

format long g

to the extraction script prints the matrix coefficients with much higher precision. After copying these values into the State Space block, the state-space solution and the original circuit solution match.

For better readability, I also moved the state-space matrices into the model initialization script. This keeps the State Space blocks cleaner and makes the model easier to understand.

I also changed the solver to Radau, since the model is quite stiff, and increased the Refine factor to 5 so that the plotted sine waves appear smoother.

To inspect all changes made to the model, I recommend using the PLECS model comparison tool via:

File > Compare…

The Diff tool highlights modified, inserted, and deleted components and parameters:

Regarding your second question:

The second thing I find odd is the gain block “AMC1301” is ignored by plecs('get', modelName, 'Topology'). The state space blocks required the gain block to be included externally, where I would’ve expected the gain to be incorporated into the matrix element values.

This is expected behavior.

The command

t = plecs('get', modelName, 'Topology');

extracts the state-space matrices of the linear physical circuit for the selected switch configuration. The returned structure contains the corresponding (A), (B), (C), (D), and (I) matrices.

The AMC1301 in your model, however, is represented by a Gain block. A Gain block is part of the Control/Math signal-processing domain and is therefore not part of the physical circuit topology used by Topology to construct the state-space matrices.

Voltmeter Van_TF Extract_RC.plecs (65.5 KB)

Thank you for the help!

Is there a way to identify when a system is numerically ill-conditioned? I placed the 1e-9 resistors to eliminate state/source dependence, but the capacitors have values at a much smaller scale. Are the capacitors treated differently, such that they don’t cause a numerically ill-conditioned system? Or did you just omit them from your recommended changes because they will meaningfully change the system response, even though they also contribute to the ill-conditioning?

The Op-Amp block is essentially the same as the block combination “VAMCin”→“AMC1301”→“VAMCout”, when looking under the mask. Does plecs('get', modelName, 'Topology') interpret subsystems based on their ports (thus hiding the internal gain block)? Or is there another element involved in the interpretation? Would I be able to remove the need for an external gain for my subsystem block if I placed the block combination in a masked subsystem, similar to the way custom libraries interpret subsystems?

The relevant quantity here is the (RC) time constant, (\tau = RC) or equivalently the pole at (1/(RC)). The very small resistors, together with the capacitors, can therefore introduce extremely fast dynamics and a large separation of time scales. The capacitors contribute to this as well, but I suggested changing the resistors because they do not change the intended system behavior.

The Op-Amp block appears to be essentially equivalent to the combination VAMCin → AMC1301 → VAMCout when looking under the mask.

However, when I use plecs('get', modelName, 'Topology'), my custom implementation exposes VAMCout as an input and VAMCin as an output of the extracted state-space model. As a result, the gain of the AMC1301 is not included in the extracted (A) matrix. With the standard Op-Amp block, on the other hand, the gain is incorporated into the state-space model.
Voltmeter Van_TF Extract_RC2.plecs (56.5 KB)

Thank you for the explanation that the large separation of time scales causes the ill-conditioning. That’s something I can keep an eye on in my designs.

I also thought to use the Op-Amp block the same way you have shown. My question is: What is different about the Op-Amp block, compared to a custom subsystem block?

In my attached file, I recreated the Op-Amp block from scratch, starting in a Subsystem block and modifying the mask, including the Mask Type and Mask Description. From what I can tell, they are the same, with exception to the names of primitives, but running the script results in VAMCin and VAMCout being recognized again.

Voltmeter Van_TF Extract_GH.plecs (65.0 KB)

I had to look into this a bit more closely myself, since the relevant difference is not obvious from the subsystem mask.

The important difference lies in the settings of the Controlled Voltage Sources inside the subsystem. In the built-in Voltage Source (Controlled) block, Allow state-space inlining is enabled. If you enable this option in your recreated subsystem as well, VAMCin and VAMCout should no longer appear as independent inputs during state-space extraction.

With this option enabled, PLECS can eliminate the source input variable from the state-space equations and substitute it with the corresponding electrical measurement variables.

There is a reason why this option is marked “For expert use only” and is disabled by default: enabling it effectively makes the two circuits on either side of the signal connection dependent on each other in the state-space formulation. It should therefore be used with some caution, particularly when the intention is to keep parts of the model independent.

So, your recreated subsystem is essentially correct. The missing piece is the Allow state-space inlining setting rather than anything special in the mask itself.