Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot set Value2 with AscEditor #46

Closed
hb020 opened this issue May 19, 2024 · 18 comments
Closed

Cannot set Value2 with AscEditor #46

hb020 opened this issue May 19, 2024 · 18 comments

Comments

@hb020
Copy link
Collaborator

hb020 commented May 19, 2024

There is an incoherence between SpiceEditor and AscEditor:

  • SpiceEditor handles all components of the values of a component as one value, and they can be set via set_component_value.
  • AscEditor has properties "Value" and "Value2". The latter has no possibility to be set.

Example: "V3 0 AC 2": that is a Voltage source of 0 volt, but with AC small signal analysis voltage of 2.

With SpiceEditor, the value of V3 = "V3 0 AC 2". If I do set_component_value({"V3":"0"}), the AC part disappears.

With AscEditor, the value of V3 = "0", and Value2 = "AC 2". If I do set_component_value({"V3":"0"}), the AC part remains intact, and there is no possibility to modify it.

Question:

  • would it be possible to let AscEditor.set_component_value() set all sections of a value, just like SpiceEditor.set_component_value()?
  • If not, is it possible to make modifications to "Value2" possible?
@nunobrum
Copy link
Owner

Hello @hb020,

This one is a tricky one. This requires some code updates.
I think the best is to do what LTspice does. When it generates a netlist it concatenates the two values into a one single value.

I'll let you know when I have a solution for it.

Best Regards,
Nuno

@hb020
Copy link
Collaborator Author

hb020 commented May 26, 2024

There is a comparable functionality mismatch with the setting of the model of a device, like an opamp.

With SpiceEditor, I can say set_component_value("XU1", "OPAx189")
But with AscEditor "XU1" is not found, because the X is in another property. Haven't checked yet which property, but it must be there somewhere.

I think the best is to do what LTspice does.

There are 2 options: make asceditor and spiceeditor having the same interface, or make asceditor follow the LTSpice model closely.

I am making a tool that uses the 2 editors interchangeably, so I selfishly would prefer the first option. But I do understand the rationale behind the second option: it is the most clean, provided the other simulators behave like ltspice.

@nunobrum
Copy link
Owner

I have committed into the branch v1.1.3 a version that tackles this problem. The Value and Value 2 are joined together into a single parameter. This works because when writing back to the .asc file, the LTspice is smart enough to redistribute the values again between Value and Value2. It suffices to read the file and save it.

Regarding the comment of having the consistency between all editors. That has been my goals since I've started supporting more than one simulation tool. However, I must draw a line in some cases. In order to achieve that, some assumptions need to be made, and they may not always be correct.
I, myself hate when I have to fight against supposedly smart interfaces. Ex: Autocorrects.

I have also introduced two new methods. set_component_parameters() and get_component_parameters().
You can use Value2, SpiceLine, SpiceModel or SpiceLine2 to access these values.
These are supported in all editors and are intended to use with parameters. For this, I had to refactor many of the regular expressions. This may cause some code to break. This is why I will only merge this to the trunk when I have a bit more confidence that it works.

Cheers,
Nuno

@nunobrum
Copy link
Owner

nunobrum commented Jun 2, 2024

Closing this issue since 1.1.3 is already the current version.

@nunobrum nunobrum closed this as completed Jun 2, 2024
@xEverth
Copy link
Contributor

xEverth commented Jun 8, 2024

Hello @nunobrum

I updated to the latest version 1.1.3 of spicelib

In my schematic, I use the generic OpAmp (level 2) schematic included with LTSpice.

The Schematic contains these lines:

SYMBOL OpAmps\\UniversalOpAmp2 736 416 R0
SYMATTR InstName U1

When the asc file is read with AscEditor, the symbol is read and parsed correctly

INFO:spicelib.AscEditor:Searching for symbol OpAmps\UniversalOpAmp2.asy...
INFO:spicelib.AsyReader:Parsing ASY file C:\Users\Everth-Laptop\Documents\LtspiceXVII\lib\sym\OpAmps\UniversalOpAmp2.asy

I would like to edit the "Value2" attribute of the schematic to change the Avol, GBW and Slew parameters, like it's possible to do by using CTRL+A in the Symbol Editor:
image

The component associated with the InstName "U1" however is read in as a subcircuit:

print(opamp_circuit.get_component_info("U1"))
_SUBCKT <spicelib.editor.spice_editor.SpiceCircuit object at 0x000001A052CE30D0>

And I can list the subcircuits' components individually:

print([opamp_circuit.get_subcircuit("U1").get_component_info(elem) for elem in opamp_circuit.get_subcircuit("U1").get_components()])
[{'designator': 'S1', 'nodes': ' 5 3 X 5', 'value': 'Q', 'line': 1},
 {'designator': 'S2', 'nodes': ' 4 5 5 X', 'value': 'Q', 'line': 2},
 {'line': 3},
 {'designator': 'C3',
  'nodes': ' 5 4',
  'model': None,
  'value': '1p',
  'formula': None,
  'params': '',
  'line': 4},
 {'designator': 'C4',
  'nodes': ' 3 5',
  'model': None,
  'value': '1p',
  'formula': None,
  'params': '',
  'line': 5},
 {'designator': 'R2',
  'nodes': ' X 4',
  'model': None,
  'value': '{2*Rout}',
  'formula': '{',
  'params': ' noiseless\n',
  'line': 6},
 {'designator': 'R1',
  'nodes': ' 3 X',
  'model': None,
  'value': '{2*Rout}',
  'formula': '{',
  'params': ' noiseless\n',
  'line': 7},
 {'designator': 'R3',
  'nodes': ' 3 1',
  'model': None,
  'value': '{2*Rin}',
  'formula': '{',
  'params': ' noiseless\n',
  'line': 8},
 {'designator': 'R4',
  'nodes': ' 3 2',
  'model': None,
  'value': '{2*Rin}',
  'formula': '{',
  'params': ' noiseless\n',
  'line': 9},
 {'designator': 'R5',
  'nodes': ' 2 4',
  'model': None,
  'value': '{2*Rin}',
  'formula': '{',
  'params': ' noiseless\n',
  'line': 10},
 {'designator': 'R6',
  'nodes': ' 1 4',
  'model': None,
  'value': '{2*Rin}',
  'formula': '{',
  'params': ' noiseless\n',
  'line': 11},
 {'designator': 'B1',
  'nodes': ' X 0',
  'value': 'I=if(V(x,3)<0,0,({2*slew*Cout}*V(x,3))**2)',
  'line': 12},
 {'designator': 'B2',
  'nodes': ' 0 X',
  'value': 'I=if(V(x,4)>0,0,({2*slew*Cout}*V(4,x))**2)',
  'line': 13},
 {'designator': 'D1', 'nodes': ' 5 3', 'value': 'X', 'params': '', 'line': 14},
 {'designator': 'D2', 'nodes': ' 4 5', 'value': 'X', 'params': '', 'line': 15}]

But I cannot see the "Value2" of that OpAmp model and the new method get_component_parameters returns an empty dict:

print(f'{opamp_circuit.get_component_parameters("U1")}')

{}

For reference, using LTSpice, I am able to see those parameters in the generated netlist that is available after running the simulation:

* C:\Labo23\2023-10-18\SPICE\2_Opamp_invert_AC.asc
V1 V+ 0 15.09
V2 V- 0 -15.12
V3 IN 0 SINE(0 100m 1000 0 0 0 200) AC 1 0 Rser=49.8
R1 N001 IN 3.247k
R2 OUT N001 17.85k
XU1 0 N001 V+ V- OUT level2 Avol=1Meg GBW=10Meg Slew=10Meg Ilimit=25m Rail=0 Vos=0 En=0 Enk=0 In=0 Ink=0 Rin=500Meg
.ac dec 10 1k 100Meg
.lib UniversalOpAmp2.lib
.backanno
.end

Am I misunderstanding the usage of the AscEditor class?
Is there a way to edit these "Value2" parameters for the OpAmp or other more complicated components using AscEditor or other spicelib classes?

Thank you Nuno

@hb020
Copy link
Collaborator Author

hb020 commented Jun 9, 2024

On a non modified subcircuit, asc_editor.get_component_parameters() returns an empty object, because the attributes of the original symbol apply to the component in the schematic. They appear in the GUI editor, but not in the .ASC file.

Once you modified some of the attributes, you should in theory be able to see something like this in the ASC file:

SYMBOL UniversalOpAmp2 208 160 R0
SYMATTR InstName U1
SYMATTR Value2 Avol=2Meg GBW=10Meg Slew=10Meg
SYMATTR SpiceLine Ilimit=35m Rail=0 Vos=0
SYMATTR SpiceLine2 En=0 Enk=0 In=0 Ink=0 Rin=501Meg

and this when you call asc_editor.get_component_parameters("U1"):

{
  "Value2": "Avol=2Meg GBW=10Meg Slew=10Meg",
  "SpiceLine": "Ilimit=35m Rail=0 Vos=0",
  "SpiceLine2": "En=0 Enk=0 In=0 Ink=0 Rin=501Meg",
  "Ilimit": "35m",
  "Rail": 0,
  "Vos": 0,
  "En": 0,
  "Enk": 0,
  "In": 0,
  "Ink": 0,
  "Rin": "501Meg"
}

Asc files use 4 groups of parameters: "Value","Value2,"SpiceLine","SpiceLine2".

asc_editor.get_component_parameters shows the 4 prime keys, plus an expansion of "SpiceLine" and "SpiceLine2". The reason for that is

  1. most components only use Value and SpiceLine
  2. The format of Value/Value2 is highly variable: you can have a simple single value, or complex single values, or space separated pairs, or key/value pairs separated by '='. SpiceLine/SpiceLine2 only has 1 format.
  3. During simulation or when exporting to a netlist, those concepts disappear. There, there is only 1 list of parameters.

So:

  • if you want to precisely play with those parameters, it may be best to use the netlist editor.
  • or you can use asc_editor.set_component_parameters("U1", Value2="Avol=2Meg GBW=10Meg Slew=10Meg")

Note that if you use asc_editor.set_component_parameters("U1", Avol="2Meg"), it will by default modify SpiceLine, since we haven't yet decided where in "Value","Value2,"SpiceLine","SpiceLine2" and in what format those parameters should be placed. It might work though, as all that is simply concatenated when you create the netlist.

@hb020
Copy link
Collaborator Author

hb020 commented Jun 9, 2024

There are 2 possible improvements here:

  1. let asc_editor.get_component_parameters() return all the values, even when not changed from the default values. Right now, only once the parameters are changed from the default value, they become visible.
  2. separate the get/set of the component parameters (Avol, GBW,...) from the symbol attributes (InstName, Prefix, Value, Value2, SpiceLine, SpiceLine2, SpiceModel, ModelFile, Description)

@nunobrum, what do you think of that?

@nunobrum nunobrum reopened this Jun 9, 2024
@hb020
Copy link
Collaborator Author

hb020 commented Jun 9, 2024

Imagine this circuit:

Version 4
SHEET 1 880 680
SYMBOL UniversalOpAmp2 208 160 R0
SYMATTR InstName U1
SYMBOL res 288 96 R0
SYMATTR InstName R1

The problem is that I can find GBW in the opamp (lib/sym/OpAmps/UniversalOpAmp2.asy:SYMATTR Value2 Avol=1Meg GBW=10Meg Vos=0), but where is PWR and TOL for the resistor?

@nunobrum
Copy link
Owner

nunobrum commented Jun 9, 2024

Hello All,

The analysis done by @hb020 is correct. AscEditor as of today identify the parameters that do not yet exist on the .asc file.
I think the asc_editor.set_component_parameters("U1", Value2="Avol=2Meg GBW=10Meg Slew=10Meg") suggestion will circumvent the problem very well.

On the improvement propositions @hb020, I think they came as a natural consequence of the having the AscEditor return a SpiceSubcircuit instance. However, I do think that the implementation as it is today, kind of violates the very basic design principle of encapsulation.
This project started from the need of quickly solving a itch I had. Which was to manipulate netlists, and it made sense to have a set_component_value() that interacted with a netlist, without having the notion that a component could be an object as it own right. As more and more functionality was added into the project the same principle was kept.

Now we are going in the direction of having components, inside sub-circuits inside a non sub-circuit object. In my view this obliges us to take a look back into the structure of classes we have in place. Moving forward, I think this pushes the design in the direction of having components as an object on its own.

Instead of asc_editor.set_component_value('R1', 55) I am now envisioning something of the kind
asc_editor.get_component('X1').set_value(55)

or instead of asc_editor.set_component_parameter("U1", param1=55) it would become asc_editor.get_component('U1').set_parameter(param1=55) or in a more pythonic way, using the [ ] operator for getting a component and overriding the attribute set to set a parameter.

asc_editor['R1'].value = 55
asc_editor['U1'].param1=55

I have reopened this issue, so we can discuss these ideas. Since this is a very huge step away from the current concept, this needs to be very well thought of.

@nunobrum
Copy link
Owner

nunobrum commented Jun 9, 2024

Imagine this circuit:

Version 4
SHEET 1 880 680
SYMBOL UniversalOpAmp2 208 160 R0
SYMATTR InstName U1
SYMBOL res 288 96 R0
SYMATTR InstName R1

The problem is that I can find GBW in the opamp (lib/sym/OpAmps/UniversalOpAmp2.asy:SYMATTR Value2 Avol=1Meg GBW=10Meg Vos=0), but where is PWR and TOL for the resistor?

In what regards AscEditor, I think we should limit ourselves to what we can find on the netlists. We can create an interface to the user to set not known attributes, but, it should ultimately up to the user to manage it.

@hb020
Copy link
Collaborator Author

hb020 commented Jun 9, 2024

In what regards AscEditor, I think we should limit ourselves to what we can find on the netlists. We can create an interface to the user to set not known attributes, but, it should ultimately up to the user to manage it.

Agree, as this risks taking us down a deep rabbit hole. What about ngspice compatibility for example? The main goal was to make netlists modifiable. If we want to maintain GUI functionality compatibility, then that is entirely other goal.

To me, it is entirely justifiable to say "You can use the AscEditor for simple things, but full functionality is only available with the netlist editor that is SpiceEditor.". We will have to make it explicit and explain what the limitations are.

We can of strive to make these limitations minimal, but there will be.

@nunobrum
Copy link
Owner

nunobrum commented Jun 9, 2024

Totally agree. The AscEditor came out of the fact that LTSpice didn't create a netlist on the mac platform. Since I had experience with .asc files(**) , it seemed a fun thing to do to be able to also modify schematics. This would allow adding Montecarlo or Worst Case Analysis testbenches to a schematic, and still enjoy the benefits of the LTSpice GUI to analyse data.
This objective is achieved, and I am not planning in putting much more effort into it. The idea is to just leave the foundations and to keep the project extensible for the users that might want to add features on top of it.

(**) another project I have which exports and imports .asc to Altium Designer.

@hb020
Copy link
Collaborator Author

hb020 commented Jun 9, 2024

Coming week I plan to work a bit more on Linux/MacOS compatibility (and logging of that), and I can add some explanations of the limitations of AscEditor (will do in another branch, and that will be mainly in readme.md).

@nunobrum
Copy link
Owner

nunobrum commented Jun 9, 2024

This is what I have in mind for a next version.
image

nunobrum added a commit that referenced this issue Jun 12, 2024
@nunobrum
Copy link
Owner

I have just pushed a new branch called component-object where a new Component Class is introduced and makes all the manipulations that are related with components.

This now allows this
print(netlist['R1'].value) -> 1000
print(netlist['R1'].value_str) -> "1k"
netlist['R1'].value_str = "2R2"
print(netlist['R1'].value_str) -> "2R2"
print(netlist['R1'].value) -> 2.2
print(netlist['R1'].params) -> {}
netlist['R1'].set_params(tc=0)

I'll merge this back to the main when this approach is also implemented on the remaining Editors.

@hb020
Copy link
Collaborator Author

hb020 commented Jun 23, 2024

looks good. Just afraid that doing it for AscEditor is going to be complicated.

@nunobrum
Copy link
Owner

Holidays and a lot of work slows this implementation.

@nunobrum
Copy link
Owner

nunobrum commented Sep 8, 2024

This was finally integrated in v1.2.0

@nunobrum nunobrum closed this as completed Sep 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants