/// <summary> /// Generate a mutual inductance /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> protected ICircuitObject GenerateMut(CircuitIdentifier name, List <Token> parameters, Netlist netlist) { MutualInductance mut = new MutualInductance(name); switch (parameters.Count) { case 0: throw new ParseException($"Inductor name expected for mutual inductance \"{name}\""); case 1: throw new ParseException(parameters[0], "Inductor name expected", false); case 2: throw new ParseException(parameters[1], "Coupling factor expected", false); } // Read two inductors if (!ReaderExtension.IsName(parameters[0])) { throw new ParseException(parameters[0], "Component name expected"); } mut.MUTind1 = new CircuitIdentifier(parameters[0].image); if (!ReaderExtension.IsName(parameters[1])) { throw new ParseException(parameters[1], "Component name expected"); } mut.MUTind2 = new CircuitIdentifier(parameters[1].image); mut.MUTcoupling.Set(netlist.ParseDouble(parameters[2])); return(mut); }
/// <summary> /// Generate a current source /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> protected ICircuitObject GenerateISRC(CircuitIdentifier name, List <Token> parameters, Netlist netlist) { Currentsource isrc = new Currentsource(name); isrc.ReadNodes(netlist.Path, parameters); // We can have a value or just DC for (int i = 2; i < parameters.Count; i++) { // DC specification if (i == 2 && parameters[i].image.ToLower() == "dc") { i++; isrc.ISRCdcValue.Set(netlist.ParseDouble(parameters[i])); } else if (i == 2 && ReaderExtension.IsValue(parameters[i])) { isrc.ISRCdcValue.Set(netlist.ParseDouble(parameters[i])); } // AC specification else if (parameters[i].image.ToLower() == "ac") { i++; isrc.ISRCacMag.Set(netlist.ParseDouble(parameters[i])); // Look forward for one more value if (i + 1 < parameters.Count && ReaderExtension.IsValue(parameters[i + 1])) { i++; isrc.ISRCacPhase.Set(netlist.ParseDouble(parameters[i])); } } // Waveforms else if (parameters[i].kind == BRACKET) { // Find the reader BracketToken bt = parameters[i] as BracketToken; Statement st = new Statement(StatementType.Waveform, bt.Name, bt.Parameters); isrc.ISRCwaveform = (IWaveform)netlist.Readers.Read(st, netlist); } else { throw new ParseException(parameters[i], "Unrecognized parameter"); } } return(isrc); }
/// <summary> /// Generate a CCCS /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> protected ICircuitObject GenerateCCCS(CircuitIdentifier name, List <Token> parameters, Netlist netlist) { CurrentControlledCurrentsource cccs = new CurrentControlledCurrentsource(name); cccs.ReadNodes(netlist.Path, parameters); switch (parameters.Count) { case 2: throw new ParseException(parameters[1], "Voltage source expected", false); case 3: throw new ParseException(parameters[2], "Value expected", false); } if (!ReaderExtension.IsName(parameters[2])) { throw new ParseException(parameters[2], "Component name expected"); } cccs.CCCScontName = new CircuitIdentifier(parameters[2].image); cccs.CCCScoeff.Set(netlist.ParseDouble(parameters[3])); return(cccs); }
/// <summary> /// Read /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // Only assignments are possible for (int i = 0; i < st.Parameters.Count; i++) { switch (st.Parameters[i].kind) { case ASSIGNMENT: AssignmentToken at = st.Parameters[i] as AssignmentToken; switch (at.Name.kind) { case BRACKET: BracketToken bt = at.Name as BracketToken; if (bt.Name.image.ToLower() == "v" && bt.Parameters.Length == 1 && ReaderExtension.IsNode(bt.Parameters[0])) { netlist.Circuit.Nodes.Nodeset.Add(new CircuitIdentifier(bt.Parameters[0].image), netlist.ParseDouble(at.Value)); } else { throw new ParseException(st.Parameters[i], "Invalid format, v(<node>)=<ic> expected"); } break; default: if (ReaderExtension.IsNode(at.Name)) { netlist.Circuit.Nodes.Nodeset.Add(new CircuitIdentifier(at.Name.image), netlist.ParseDouble(at.Value)); } else { throw new ParseException(st.Parameters[i], "Invalid format, <node>=<ic> expected"); } break; } break; } } return(true); }
/// <summary> /// Read subcircuit definitions /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { if (st.Parameters.Count < 2) { throw new ParseException(st.Name, "Subcircuit name expected", false); } // Create the identifier of the subcircuit definition CircuitIdentifier name = new CircuitIdentifier(st.Parameters[0].image); if (netlist.Path.DefinitionPath != null) { name = netlist.Path.DefinitionPath.Grow(name); } // Extract the subcircuit definition statements StatementsToken body = (StatementsToken)st.Parameters[st.Parameters.Count - 1]; SubcircuitDefinition definition = new SubcircuitDefinition(name, body); // Parse nodes and parameters bool mode = true; // true = nodes, false = parameters for (int i = 1; i < st.Parameters.Count - 1; i++) { if (mode) { // After this, only parameters will follow if (st.Parameters[i].image.ToLower() == "params:") { mode = false; } // Parameters have started, so we will keep reading parameters else if (st.Parameters[i].kind == ASSIGNMENT) { mode = false; AssignmentToken at = st.Parameters[i] as AssignmentToken; definition.Defaults.Add(new CircuitIdentifier(at.Name.image), at.Value); } // Still reading nodes else if (ReaderExtension.IsNode(st.Parameters[i])) { definition.Pins.Add(new CircuitIdentifier(st.Parameters[i].image)); } } else if (st.Parameters[i].kind == ASSIGNMENT) { AssignmentToken at = st.Parameters[i] as AssignmentToken; definition.Defaults.Add(new CircuitIdentifier(at.Name.image), at.Value); } } // Create a new subcircuit path SubcircuitPath orig = netlist.Path; netlist.Path = new SubcircuitPath(orig, definition); foreach (var s in definition.Body.Statements(StatementType.Subcircuit)) { netlist.Readers.Read(s, netlist); } // Restore netlist.Path = orig; // Return values netlist.Definitions.Add(definition.Name, definition); Generated = definition; return(true); }
/// <summary> /// Read /// </summary> /// <param name="type">Type</param> /// <param name="st">Statement</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // Initialize List <CircuitIdentifier> instancepins = new List <CircuitIdentifier>(); Dictionary <CircuitIdentifier, Token> instanceparameters = new Dictionary <CircuitIdentifier, Token>(); CircuitIdentifier definition = null; // Get the name CircuitIdentifier name; if (netlist.Path.InstancePath != null) { name = netlist.Path.InstancePath.Grow(st.Name.image); } else { name = new CircuitIdentifier(st.Name.image); } // Format: <NAME> <NODES>* <SUBCKT> <PAR1>=<VAL1> ... // Or: <NAME> <NODES>* <SUBCKT> params: <PAR1>=<VAL1> ... bool mode = true; // true = nodes, false = parameters for (int i = 0; i < st.Parameters.Count; i++) { // Reading nodes if (mode) { if (ReaderExtension.IsNode(st.Parameters[i])) { instancepins.Add(definition = new CircuitIdentifier(st.Parameters[i].image)); } else { instancepins.RemoveAt(instancepins.Count - 1); mode = false; } } // Reading parameters // Don't use ELSE! We still need to read the last parameter if (!mode) { if (st.Parameters[i].kind == ASSIGNMENT) { AssignmentToken at = st.Parameters[i] as AssignmentToken; switch (at.Name.kind) { case WORD: case IDENTIFIER: instanceparameters.Add(new CircuitIdentifier(at.Name.image), at.Value); break; default: throw new ParseException(at.Name, "Parameter name expected"); } } } } // If there are only node-like tokens, then the last one is the definition by default if (mode) { instancepins.RemoveAt(instancepins.Count - 1); } // Modify the instancepins to be local or use the nodemap for (int i = 0; i < instancepins.Count; i++) { if (netlist.Path.NodeMap.TryGetValue(instancepins[i], out CircuitIdentifier node)) { instancepins[i] = node; } else if (netlist.Path.InstancePath != null) { instancepins[i] = netlist.Path.InstancePath.Grow(instancepins[i].Name); } } // Find the subcircuit definition if (netlist.Path.DefinitionPath != null) { definition = netlist.Path.DefinitionPath.Grow(definition); } SubcircuitDefinition subcktdef = netlist.Path.FindDefinition(netlist.Definitions, definition) ?? throw new ParseException(st.Parameters[st.Parameters.Count - 1], "Cannot find subcircuit definition"); Subcircuit subckt = new Subcircuit(subcktdef, name, instancepins, instanceparameters); SubcircuitPath orig = netlist.Path; netlist.Path = new SubcircuitPath(netlist, orig, subckt); // Read all control statements foreach (var s in subcktdef.Body.Statements(StatementType.Control)) { netlist.Readers.Read(s, netlist); } // Read all model statements foreach (var s in subcktdef.Body.Statements(StatementType.Model)) { netlist.Readers.Read(s, netlist); } // Read all component statements foreach (var s in subcktdef.Body.Statements(StatementType.Component)) { netlist.Readers.Read(s, netlist); } // Restore netlist.Path = orig; Generated = subckt; return(true); }