prcngspice.cpp
来自「gspiceui电子CAD仿真程序.用于电路参数模拟仿真」· C++ 代码 · 共 989 行 · 第 1/2 页
CPP
989 行
//*****************************************************************************// PrcNgSpice.cpp *// ---------------- *// Started : 07/05/2004 *// Last Update : 09/06/2005 *// Copyright : (C) 2004 by M.S.Waters *// Email : M.Waters@bom.gov.au *//*****************************************************************************//*****************************************************************************// *// This program is free software; you can redistribute it and/or modify *// it under the terms of the GNU General Public License as published by *// the Free Software Foundation; either version 2 of the License, or *// (at your option) any later version. *// *//*****************************************************************************#include "PrcNgSpice.hpp"//*****************************************************************************// Constructor.PrcNgSpice::PrcNgSpice( void ) : PrcSimrBase( ){ // Set the simulator binary file name if it can be found bSetBinary( wxT("ngspice") );}//*****************************************************************************// Destructor.PrcNgSpice::~PrcNgSpice( ){}//*****************************************************************************// Parse a OPTIONS command and put the data in a simulation object.// eg.s .OPTIONS TEMP=27.00 TNOM=27.00//// Argument List:// rosCmd - The command line to be parsed// roSim - The simulation object//// Return Values:// TRUE - Success// FALSE - Failurebool PrcNgSpice::bParseCmdOPT( wxString & rosCmd, Simulation & roSim ){ wxStringTokenizer ostk1( rosCmd, wxT(" =\t\n\r") ); wxString os1; bool bRtn=TRUE; double df1; // Basic argument checks if( ostk1.CountTokens( ) < 3 ) return( FALSE ); // Check command type os1 = ostk1.GetNextToken( ); if( os1.Upper( ) != wxT(".OPTIONS") ) return( FALSE ); // Extract the analysis temperature os1 = ostk1.GetNextToken( ); os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetTempC( (float) df1 ) ) bRtn = FALSE; return( bRtn );}//*****************************************************************************// Parse a FOURIER command and put the data in a simulation object.//// Argument List:// rosCmd - The command line to be parsed// roSim - The simulation object//// Return Values:// TRUE - Success// FALSE - Failurebool PrcNgSpice::bParseCmdOP( wxString & rosCmd, Simulation & roSim ){ return( FALSE );}//*****************************************************************************// Parse a FOURIER command and put the data in a simulation object.//// Argument List:// rosCmd - The command line to be parsed// roSim - The simulation object//// Return Values:// TRUE - Success// FALSE - Failurebool PrcNgSpice::bParseCmdIC( wxString & rosCmd, Simulation & roSim ){ return( FALSE );}//*****************************************************************************// Parse a DC command and put the data in a simulation object.// Eg.s: .DC Vin 0.00 200.00m 25.00m// .DC TEMP 0.00 200.00 25.00//// Argument List:// rosCmd - The command line to be parsed// roSim - The simulation object//// Return Values:// TRUE - Success// FALSE - Failurebool PrcNgSpice::bParseCmdDC( wxString & rosCmd, Simulation & roSim ){ wxStringTokenizer ostk1; wxString os1; bool bRtn=TRUE; double df1; // Basic argument checks ostk1.SetString( rosCmd ); if( ostk1.CountTokens( ) != 5 ) return( FALSE ); // Check command type os1 = ostk1.GetNextToken( ); if( os1.Upper( ) != wxT(".DC") ) return( FALSE ); // Extract the sweep type: linear or log os1 = ostk1.GetNextToken( ); if( os1.Upper( ) == wxT("TEMP") ) roSim.bSetSwpScale( 1 ); else { os1 = roSim.rosGetCpnt( os1 ); if( ! os1.IsEmpty( ) && roSim.bSetSrcCpnt( os1 ) ) roSim.bSetSwpScale( 0 ); else bRtn = FALSE; } // Extract the start value os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStart( (float) df1 ) ) bRtn = FALSE; // Extract the stop value os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStop( (float) df1 ) ) bRtn = FALSE; // Extract the step increment os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStep( (float) df1 ) ) bRtn = FALSE; return( bRtn );}//*****************************************************************************// Parse a AC command and put the data in a simulation object.// Eg.s: .AC LIN 30 1.00K 300.00K// .AC DEC 30 1.00K 300.00K// .AC OCT 30 1.00K 300.00K//// Argument List:// rosCmd - The command line to be parsed// roSim - The simulation object//// Return Values:// TRUE - Success// FALSE - Failurebool PrcNgSpice::bParseCmdAC( wxString & rosCmd, Simulation & roSim ){ wxStringTokenizer ostk1; wxString os1; bool bRtn=TRUE; double df1; long li1; // Basic argument checks ostk1.SetString( rosCmd ); if( ostk1.CountTokens( ) != 5 ) return( FALSE ); // Check command type os1 = ostk1.GetNextToken( ); if( os1.Upper( ) != wxT(".AC") ) return( FALSE ); // Extract the sweep type: linear or log os1 = ostk1.GetNextToken( ); os1.MakeUpper( ); if( os1 == wxT("LIN") ) roSim.bSetSwpScale( 0 ); else if( os1 == wxT("DEC") ) roSim.bSetSwpScale( 2 ); else if( os1 == wxT("OCT") ) roSim.bSetSwpScale( 3 ); else bRtn = FALSE; // Extract the step count os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToInt( os1, &li1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStep( (float) li1 ) ) bRtn = FALSE; // Extract the start frequency os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStart( (float) df1 ) ) bRtn = FALSE; // Extract the stop frequency os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStop( (float) df1 ) ) bRtn = FALSE; return( bRtn );}//*****************************************************************************// Parse a TRANSIENT command and put the data in a simulation object.// Eg.s: .TRAN 10.00m 100.00m 0.00 10.00m//// Argument List:// rosCmd - The command line to be parsed// roSim - The simulation object//// Return Values:// TRUE - Success// FALSE - Failurebool PrcNgSpice::bParseCmdTR( wxString & rosCmd, Simulation & roSim ){ wxStringTokenizer ostk1; wxString os1; bool bRtn=TRUE; double df1; // Basic argument checks ostk1.SetString( rosCmd ); if( ostk1.CountTokens( ) != 5 ) return( FALSE ); // Check command type os1 = ostk1.GetNextToken( ); if( os1.Upper( ) != wxT(".TRAN") ) return( FALSE ); // Extract the step size os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStep( (float) df1 ) ) bRtn = FALSE; // Extract the stop time os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStop( (float) df1 ) ) bRtn = FALSE; // Extract the start time os1 = ostk1.GetNextToken( ); if( ! ConvertType::bStrToFlt( os1, &df1 ) ) bRtn = FALSE; if( ! roSim.bSetSwpStart( (float) df1 ) ) bRtn = FALSE; return( bRtn );}//*****************************************************************************// Parse a PRINT command and put the data in a simulation object.//// Argument List:// rosCmd - The command line to be parsed// roSim - The simulation object//// Return Values:// TRUE - Success// FALSE - Failurebool PrcNgSpice::bParseCmdPR( wxString & rosCmd, Simulation & roSim ){ wxStringTokenizer ostk1; wxString os1; bool bRtn=TRUE; size_t szt1, szt2; // Basic argument checks ostk1.SetString( rosCmd ); if( ostk1.CountTokens( ) < 3 ) return( FALSE ); // Check command type os1 = ostk1.GetNextToken( ).Left( 6 ); if( os1.Upper( ) != wxT(".PRINT") ) return( FALSE ); // Extract the start temperature os1 = ostk1.GetNextToken( ); os1.MakeUpper( ); if( os1 == wxT("DC") ) roSim.bSetAnaType( Simulation::eANA_DC ); else if( os1 == wxT("AC") ) roSim.bSetAnaType( Simulation::eANA_AC ); else if( os1 == wxT("TRAN") ) roSim.bSetAnaType( Simulation::eANA_TR ); else return( FALSE ); // Extract the parameters to derive, any complex parts and the test component // and/or test node labels while( ostk1.HasMoreTokens( ) ) { // Extract the next field os1 = ostk1.GetNextToken( ); if( os1.Length( ) < 4 ) { bRtn = FALSE; continue; } // Extract the parameter specifier switch( wxToupper( os1.GetChar( 0 ) ) ) { case wxT('V'): roSim.bSetOutPar( Simulation::ePAR_VLT, TRUE ); break; case wxT('I'): roSim.bSetOutPar( Simulation::ePAR_CUR, TRUE ); break; case wxT('P'): roSim.bSetOutPar( Simulation::ePAR_PWR, TRUE ); break; case wxT('R'): roSim.bSetOutPar( Simulation::ePAR_RES, TRUE ); break; default: bRtn = FALSE; break; } // Extract the complex part if( roSim.eGetAnaType( ) == Simulation::eANA_AC ) { switch( wxToupper( os1.GetChar( 1 ) ) ) { case wxT('M'): roSim.bSetOutCpx( Simulation::eCPX_MAG, TRUE ); break; case wxT('P'): roSim.bSetOutCpx( Simulation::eCPX_PHASE, TRUE ); break; case wxT('R'): roSim.bSetOutCpx( Simulation::eCPX_REAL, TRUE ); break; case wxT('I'): roSim.bSetOutCpx( Simulation::eCPX_IMAG, TRUE ); break; case wxT('D'): if( os1.Mid( 1, 2 ).Upper( ) == wxT("DB") ) { roSim.bSetOutCpx( Simulation::eCPX_MAG, TRUE ); roSim.bSetOutCpx( Simulation::eCPX_MAGDB, TRUE ); break; } default: bRtn = FALSE; break; } } // Extract the component or node label szt1 = os1.Index( wxT('(') ); szt2 = os1.Index( wxT(')') ); if( (int)szt1==wxNOT_FOUND || (int)szt2==wxNOT_FOUND || (szt1+1)>=szt2 ) { bRtn = FALSE; continue; } os1 = os1.Mid( szt1+1, szt2-szt1-1 ); if( roSim.roasGetNodeLbls( ).Index( os1 ) != wxNOT_FOUND ) roSim.bAddTstNode( os1 ); else if( bMatchCpnt( roSim, os1 ) ) roSim.bAddTstCpnt( os1 ); else bRtn = FALSE; } return( bRtn );}//*****************************************************************************// Match a component to a set of node labels. Component voltages cannot be// specified using the component label in the Ng-Spice print statement. The two// node labels connected to the component must be specified. When parsing the// print statement the component label must be derived from the node labels.// This may not work where components are connected in parallel. The nodes are// specified in the form "<Node1>,<Node2>" eg. "1,2".//// Argument List:// rosToNodes - The nodes to match, also used to return the component label//// Return Values:// TRUE - Success (A component with the specified nodes was found)// FALSE - Failurebool PrcNgSpice::bMatchCpnt( Simulation & roSim, wxString & rosToNodes ){ const wxArrayString & roasCpnts=roSim.roasGetCpnts( ); wxArrayString oasNodes; Component oCpnt; wxString os1; size_t szt1; // Argument validity checks if( rosToNodes.IsEmpty( ) ) return( FALSE ); if( roasCpnts.GetCount( ) <= 0 ) return( FALSE ); if( rosToNodes.Freq( wxT(',') ) != 1 ) return( FALSE ); // Extract the node labels oasNodes.Add( rosToNodes.BeforeFirst( wxT(',') ) ); oasNodes.Add( rosToNodes.AfterLast( wxT(',') ) ); // Attempt to match the nodes with a component for( szt1=0; szt1<roasCpnts.GetCount( ); szt1++ ) { os1 = roasCpnts.Item( szt1 ); oCpnt.bSetLine( os1 ); if( oCpnt.roasGetNodes( ) == oasNodes ) break; oCpnt.Clear( ); } // Was a match found? if( ! oCpnt.bIsOk( ) ) return( FALSE ); // A match was found rosToNodes = oCpnt.rosGetName( ); return( TRUE );}//*****************************************************************************// Create the simulator command sequence for a DC analysis.//// Argument List:// roSim - Simulation objectvoid PrcNgSpice::MakeCmdDC( Simulation & roSim ){ wxString osCmdOPT; wxString osCmdPR; wxString osCmdDC; wxString osPar, os1; uint uiPar; // Clear the field list m_osFieldLst.Empty( ); // Create the OPTIONS command if( roSim.iGetSwpScale( ) == PnlNgSpiceDC::eSWEEP_SRC ) { os1 = roSim.rosGetTempC( ); osCmdOPT << wxT(".OPTIONS TEMP=") << os1 << wxT(" TNOM=") << os1; os1 = roSim.rosGetSrcCpnt( ); } else os1.Empty( ); // Create the DC command osCmdDC = wxT(".DC "); if( ! os1.IsEmpty( ) ) osCmdDC << os1 << wxT(' '); else osCmdDC << wxT("TEMP "); osCmdDC << roSim.rosGetSwpStart( ) << wxT(' ') << roSim.rosGetSwpStop ( ) << wxT(' ') << roSim.rosGetSwpStep ( ); roSim.bSetSrcCpnt( wxT("") ); // Create the PRINT command osCmdPR = wxT(".PRINT DC"); for( uiPar=Simulation::ePAR_FST; uiPar<=Simulation::ePAR_LST; uiPar++ ) { if( ! roSim.bGetOutPar( (Simulation::eParType) uiPar ) ) continue; switch( uiPar ) { case Simulation::ePAR_VLT: osPar = wxT("V("); break; case Simulation::ePAR_CUR: osPar = wxT("I("); break; case Simulation::ePAR_PWR: osPar = wxT("P("); break; case Simulation::ePAR_RES: osPar = wxT("R("); break; default: continue; } // Add any components and/or nodes to derivation list for this parameter os1 = rosMakeArgsPR( roSim, osPar ); if( ! os1.IsEmpty( ) ) osCmdPR << os1; } // Add simulation commands to Simulation object roSim.bAddSimCmd( osCmdOPT ); roSim.bAddSimCmd( osCmdPR ); roSim.bAddSimCmd( osCmdDC );}//*****************************************************************************// Create the simulator command sequence for a AC analysis.//// Argument List:// roSim - Simulation objectvoid PrcNgSpice::MakeCmdAC( Simulation & roSim ){ wxString osCmdOPT; wxString osCmdPR; wxString osCmdOP; wxString osCmdAC; wxString osPar, osCpx, os1; uint uiPar, uiCpx; // Clear the field list m_osFieldLst.Empty( ); // Create the OPTIONS command os1 = roSim.rosGetTempC( ); osCmdOPT << wxT(".OPTIONS TEMP=") << os1 << wxT(" TNOM=") << os1; // Create the AC command osCmdAC = wxT(".AC "); switch( roSim.iGetSwpScale( ) ) { case 0: osCmdAC << wxT("LIN "); break; case 2: osCmdAC << wxT("DEC "); break; case 3: osCmdAC << wxT("OCT "); break; } osCmdAC << ( (int) roSim.fGetSwpStep( ) ) << wxT(' ') << roSim.rosGetSwpStart( ) << wxT(' ')
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?