SPICE: Add support for transmission lines

This commit is contained in:
Fabien Corona 2022-01-23 17:23:22 +00:00 committed by Seth Hillbrand
parent 2dbc89e5f2
commit 58e167013d
7 changed files with 2887 additions and 65 deletions

View File

@ -252,21 +252,25 @@ bool DIALOG_SPICE_MODEL::TransferDataFromWindow()
// Passive
if( page == m_passive )
{
if( !m_disabled->GetValue() && !m_passive->Validate() )
return false;
switch( m_pasType->GetSelection() )
{
case 0: m_fieldsTmp[SF_PRIMITIVE] = (char) SP_RESISTOR; break;
case 1: m_fieldsTmp[SF_PRIMITIVE] = (char) SP_CAPACITOR; break;
case 2: m_fieldsTmp[SF_PRIMITIVE] = (char) SP_INDUCTOR; break;
default:
wxASSERT_MSG( false, "Unhandled passive type" );
return false;
break;
}
bool checkValue = m_fieldsTmp[SF_PRIMITIVE] == (char) SP_RESISTOR
|| m_fieldsTmp[SF_PRIMITIVE] == (char) SP_CAPACITOR
|| m_fieldsTmp[SF_PRIMITIVE] == (char) SP_INDUCTOR;
if( checkValue && !m_disabled->GetValue() && !m_passive->Validate() )
return false;
m_fieldsTmp[SF_MODEL] = m_pasValue->GetValue();
}
else if( page == m_model ) // Model
@ -294,6 +298,34 @@ bool DIALOG_SPICE_MODEL::TransferDataFromWindow()
m_fieldsTmp[SF_PRIMITIVE] = (char)( m_pwrType->GetSelection() ? SP_ISOURCE : SP_VSOURCE );
m_fieldsTmp[SF_MODEL] = model;
}
else if( page == m_tline )
{
wxWindow* subpage = m_tlineNotebook->GetCurrentPage();
wxString model;
if( subpage == m_tlineLossless )
{
m_fieldsTmp[SF_PRIMITIVE] = (char) SP_TLINE;
if( !generateTlineLossless( model ) )
return false;
m_fieldsTmp[SF_MODEL] = model;
}
else if( subpage == m_tlineLossy )
{
m_fieldsTmp[SF_PRIMITIVE] = (char) SP_TLINE_LOSSY;
if( !generateTlineLossy( model ) )
return false;
m_fieldsTmp[SF_MODEL] = model;
}
else
{
wxASSERT_MSG( false, "Unhandled transmission line type" );
}
}
else
{
wxASSERT_MSG( false, "Unhandled model type" );
@ -388,13 +420,26 @@ bool DIALOG_SPICE_MODEL::TransferDataToWindow()
case SP_CAPACITOR:
case SP_INDUCTOR:
m_notebook->SetSelection( m_notebook->FindPage( m_passive ) );
m_pasType->SetSelection( primitive == SP_RESISTOR ? 0
: primitive == SP_CAPACITOR ? 1
: primitive == SP_INDUCTOR ? 2
: -1 );
m_pasType->SetSelection( primitive == SP_RESISTOR ? 0
: primitive == SP_CAPACITOR ? 1
: primitive == SP_INDUCTOR ? 2
: -1 );
m_pasValue->SetValue( m_fieldsTmp[SF_MODEL] );
break;
case SP_TLINE:
m_notebook->SetSelection( m_notebook->FindPage( m_tline ) );
m_tlineNotebook->SetSelection( m_tlineNotebook->FindPage( m_tlineLossless ) );
if( !parseLosslessTline( m_fieldsTmp[SF_MODEL] ) )
return false;
break;
case SP_TLINE_LOSSY:
m_notebook->SetSelection( m_notebook->FindPage( m_tline ) );
m_tlineNotebook->SetSelection( m_tlineNotebook->FindPage( m_tlineLossy ) );
if( !parseLossyTline( m_fieldsTmp[SF_MODEL] ) )
return false;
break;
case SP_DIODE:
case SP_BJT:
case SP_MOSFET:
@ -480,6 +525,88 @@ void DIALOG_SPICE_MODEL::showPinOrderNote( int aModelType )
m_stInfoNote->SetLabel( msg );
}
bool DIALOG_SPICE_MODEL::parseLosslessTline( const wxString& aModel )
{
if( aModel.IsEmpty() )
return false;
wxStringTokenizer tokenizer( aModel, " " );
while( tokenizer.HasMoreTokens() )
{
// Get the next token now, so if any of the branches catches an exception, try to
// process it in another branch
wxString tkn = tokenizer.GetNextToken().Lower();
if( tkn.SubString( 0, 2 ) == "z0=" )
{
m_tlineLosslessImpedance->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
}
else if( tkn.SubString( 0, 2 ) == "td=" )
{
m_tlineLosslessDelay->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
m_tlineLosslessDelayMode->SetSelection( 0 );
}
else if( tkn.SubString( 0, 1 ) == "f=" )
{
m_tlineLosslessFrequency->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
m_tlineLosslessDelayMode->SetSelection( 1 );
}
else if( tkn.SubString( 0, 2 ) == "nl=" )
{
m_tlineLosslessWavelength->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
m_tlineLosslessDelayMode->SetSelection( 1 );
}
}
return true;
}
bool DIALOG_SPICE_MODEL::parseLossyTline( const wxString& aModel )
{
if( aModel.IsEmpty() )
return false;
wxStringTokenizer tokenizer( aModel, " " );
wxString extraParam = "";
while( tokenizer.HasMoreTokens() )
{
// Get the next token now, so if any of the branches catches an exception, try to
// process it in another branch
wxString tkn = tokenizer.GetNextToken().Lower();
if( tkn.SubString( 0, 1 ) == "r=" )
{
m_tlineLossyR->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
}
else if( tkn.SubString( 0, 1 ) == "l=" )
{
m_tlineLossyL->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
}
else if( tkn.SubString( 0, 1 ) == "c=" )
{
m_tlineLossyC->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
}
else if( tkn.SubString( 0, 1 ) == "g=" )
{
m_tlineLossyG->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
}
else if( tkn.SubString( 0, 3 ) == "len=" )
{
m_tlineLossyLen->SetValue( tkn.AfterFirst( wxUniChar( '=' ) ) );
}
else
{
extraParam += tkn + " ";
}
}
m_tlineLossyParams->SetValue( extraParam );
return true;
}
bool DIALOG_SPICE_MODEL::parsePowerSource( const wxString& aModel )
{
@ -661,6 +788,139 @@ bool DIALOG_SPICE_MODEL::parsePowerSource( const wxString& aModel )
}
bool DIALOG_SPICE_MODEL::generateTlineLossless( wxString& aTarget )
{
wxString result = "";
try
{
if( !empty( m_tlineLosslessImpedance ) )
result += wxString::Format(
"Z0=%s ", SPICE_VALUE( m_tlineLosslessImpedance->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid Impedance value" ) );
return false;
}
if( m_tlineLosslessDelayMode->GetSelection() == 0 )
{
try
{
if( !empty( m_tlineLosslessDelay ) )
result += wxString::Format(
"TD=%s ", SPICE_VALUE( m_tlineLosslessDelay->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid delay value" ) );
return false;
}
}
else if( m_tlineLosslessDelayMode->GetSelection() == 1 )
{
try
{
if( !empty( m_tlineLosslessFrequency ) )
result += wxString::Format(
"F=%s ",
SPICE_VALUE( m_tlineLosslessFrequency->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid frequency value" ) );
return false;
}
try
{
if( !empty( m_tlineLosslessWavelength ) )
result += wxString::Format(
"NL=%s ",
SPICE_VALUE( m_tlineLosslessWavelength->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid length in wavelength value" ) );
return false;
}
}
else
{
return false;
}
aTarget += result;
return true;
}
bool DIALOG_SPICE_MODEL::generateTlineLossy( wxString& aTarget )
{
wxString result;
try
{
if( !empty( m_tlineLossyR ) )
result += wxString::Format( "r=%s ",
SPICE_VALUE( m_tlineLossyR->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid resistance value" ) );
return false;
}
try
{
if( !empty( m_tlineLossyC ) )
result += wxString::Format( "c=%s ",
SPICE_VALUE( m_tlineLossyC->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid capacitance value" ) );
return false;
}
try
{
if( !empty( m_tlineLossyL ) )
result += wxString::Format( "l=%s ",
SPICE_VALUE( m_tlineLossyL->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid inductance value" ) );
return false;
}
try
{
if( !empty( m_tlineLossyG ) )
result += wxString::Format( "g=%s ",
SPICE_VALUE( m_tlineLossyG->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid conductance value" ) );
return false;
}
try
{
if( !empty( m_tlineLossyLen ) )
result += wxString::Format(
"len=%s ", SPICE_VALUE( m_tlineLossyLen->GetValue() ).ToSpiceString() );
}
catch( ... )
{
DisplayError( this, _( "Invalid length value" ) );
return false;
}
result += m_tlineLossyParams->GetValue();
aTarget += result;
return true;
}
bool DIALOG_SPICE_MODEL::generatePowerSource( wxString& aTarget )
{
wxString acdc, trans;

View File

@ -55,6 +55,23 @@ private:
*/
bool parsePowerSource( const wxString& aModel );
/**
* Parse a string describing a lossless transmission line, so appropriate settings are checked in the dialog.
*
* @param aModel contains the string to be parse (e.g. "Z0=50 td=10n")
* @return True if the input string was parsed without errors.
*/
bool parseLosslessTline( const wxString& aModel );
/**
* Parse a string describing a lossy transmission line, so appropriate settings are checked in the dialog.
*
* @param aModel contains the string to be parse (e.g. "R=50 C=10 LEN=1")
* @return True if the input string was parsed without errors.
*/
bool parseLossyTline( const wxString& aModel );
/**
* Generate a string to describe power source parameters, basing on the current selection.
*
@ -65,6 +82,26 @@ private:
*/
bool generatePowerSource( wxString& aTarget );
/**
* Generate a string to describe a transmission line model, basing on the current selection.
*
* If there are missing fields, it will not modify the target string.
*
* @param aTarget is the destination for the generated string.
* @return True if the string was saved successfully.
*/
bool generateTlineLossless( wxString& aTarget );
/**
* Generate a string to describe a transmission line model, basing on the current selection.
*
* If there are missing fields, it will not modify the target string.
*
* @param aTarget is the destination for the generated string.
* @return True if the string was saved successfully.
*/
bool generateTlineLossy( wxString& aTarget );
/**
* Load a list of components (.model and .subckt) from a spice library file and add them to
* a combo box.

View File

@ -928,6 +928,187 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
m_power->Layout();
bSizer4->Fit( m_power );
m_notebook->AddPage( m_power, _("Source"), false );
m_tline = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_tline->SetMinSize( wxSize( 650,-1 ) );
wxBoxSizer* bSizer42;
bSizer42 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizer31;
sbSizer31 = new wxStaticBoxSizer( new wxStaticBox( m_tline, wxID_ANY, _("Line model") ), wxVERTICAL );
m_tlineNotebook = new wxNotebook( sbSizer31->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_tlineLossless = new wxPanel( m_tlineNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxFlexGridSizer* fgSizer131;
fgSizer131 = new wxFlexGridSizer( 0, 1, 0, 0 );
fgSizer131->AddGrowableCol( 1 );
fgSizer131->SetFlexibleDirection( wxBOTH );
fgSizer131->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
wxFlexGridSizer* fgSizer1311;
fgSizer1311 = new wxFlexGridSizer( 4, 3, 0, 0 );
fgSizer1311->AddGrowableCol( 1 );
fgSizer1311->SetFlexibleDirection( wxBOTH );
fgSizer1311->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText2671111 = new wxStaticText( m_tlineLossless, wxID_ANY, _("Characteristic impedance"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2671111->Wrap( -1 );
fgSizer1311->Add( m_staticText2671111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLosslessImpedance = new wxTextCtrl( m_tlineLossless, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1311->Add( m_tlineLosslessImpedance, 0, wxALL|wxEXPAND, 5 );
m_staticText26211111 = new wxStaticText( m_tlineLossless, wxID_ANY, _("ohm"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText26211111->Wrap( -1 );
fgSizer1311->Add( m_staticText26211111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText26711111 = new wxStaticText( m_tlineLossless, wxID_ANY, _("Propagation delay"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText26711111->Wrap( -1 );
fgSizer1311->Add( m_staticText26711111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLosslessDelay = new wxTextCtrl( m_tlineLossless, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1311->Add( m_tlineLosslessDelay, 0, wxALL, 5 );
m_staticText262111111 = new wxStaticText( m_tlineLossless, wxID_ANY, _("s"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText262111111->Wrap( -1 );
fgSizer1311->Add( m_staticText262111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText267111111 = new wxStaticText( m_tlineLossless, wxID_ANY, _("Frequency"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText267111111->Wrap( -1 );
fgSizer1311->Add( m_staticText267111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLosslessFrequency = new wxTextCtrl( m_tlineLossless, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1311->Add( m_tlineLosslessFrequency, 1, wxALL, 5 );
m_staticText2621111111 = new wxStaticText( m_tlineLossless, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2621111111->Wrap( -1 );
fgSizer1311->Add( m_staticText2621111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText2671111111 = new wxStaticText( m_tlineLossless, wxID_ANY, _("Length in wavelength"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2671111111->Wrap( -1 );
fgSizer1311->Add( m_staticText2671111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLosslessWavelength = new wxTextCtrl( m_tlineLossless, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1311->Add( m_tlineLosslessWavelength, 1, wxALL, 5 );
fgSizer1311->Add( 0, 0, 1, wxEXPAND, 5 );
fgSizer131->Add( fgSizer1311, 100, wxEXPAND, 5 );
wxString m_tlineLosslessDelayModeChoices[] = { _("Use time delay"), _("Use frequency and number of wavelength") };
int m_tlineLosslessDelayModeNChoices = sizeof( m_tlineLosslessDelayModeChoices ) / sizeof( wxString );
m_tlineLosslessDelayMode = new wxRadioBox( m_tlineLossless, wxID_ANY, _("Delay / Electrical length"), wxDefaultPosition, wxDefaultSize, m_tlineLosslessDelayModeNChoices, m_tlineLosslessDelayModeChoices, 1, wxRA_SPECIFY_COLS );
m_tlineLosslessDelayMode->SetSelection( 0 );
fgSizer131->Add( m_tlineLosslessDelayMode, 0, wxALL, 5 );
m_tlineLossless->SetSizer( fgSizer131 );
m_tlineLossless->Layout();
fgSizer131->Fit( m_tlineLossless );
m_tlineNotebook->AddPage( m_tlineLossless, _("Lossless"), true );
m_tlineLossy = new wxPanel( m_tlineNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxFlexGridSizer* fgSizer1312;
fgSizer1312 = new wxFlexGridSizer( 0, 1, 0, 0 );
fgSizer1312->AddGrowableCol( 1 );
fgSizer1312->SetFlexibleDirection( wxBOTH );
fgSizer1312->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
wxFlexGridSizer* fgSizer13111;
fgSizer13111 = new wxFlexGridSizer( 0, 3, 0, 0 );
fgSizer13111->AddGrowableCol( 1 );
fgSizer13111->SetFlexibleDirection( wxBOTH );
fgSizer13111->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText26711112 = new wxStaticText( m_tlineLossy, wxID_ANY, _("Resistance per unit length"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText26711112->Wrap( -1 );
fgSizer13111->Add( m_staticText26711112, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLossyR = new wxTextCtrl( m_tlineLossy, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer13111->Add( m_tlineLossyR, 0, wxALL|wxEXPAND, 5 );
m_staticText262111112 = new wxStaticText( m_tlineLossy, wxID_ANY, _("ohm / unit"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText262111112->Wrap( -1 );
fgSizer13111->Add( m_staticText262111112, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText267111112 = new wxStaticText( m_tlineLossy, wxID_ANY, _("Inductance per unit length"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText267111112->Wrap( -1 );
fgSizer13111->Add( m_staticText267111112, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLossyL = new wxTextCtrl( m_tlineLossy, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer13111->Add( m_tlineLossyL, 0, wxALL|wxEXPAND, 5 );
m_staticText2621111112 = new wxStaticText( m_tlineLossy, wxID_ANY, _("henry / unit"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2621111112->Wrap( -1 );
fgSizer13111->Add( m_staticText2621111112, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText2671111112 = new wxStaticText( m_tlineLossy, wxID_ANY, _("Capacitance per unit length"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2671111112->Wrap( -1 );
fgSizer13111->Add( m_staticText2671111112, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLossyC = new wxTextCtrl( m_tlineLossy, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer13111->Add( m_tlineLossyC, 1, wxALL|wxEXPAND, 5 );
m_staticText26211111111 = new wxStaticText( m_tlineLossy, wxID_ANY, _("farad / unit"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText26211111111->Wrap( -1 );
fgSizer13111->Add( m_staticText26211111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText26711111111 = new wxStaticText( m_tlineLossy, wxID_ANY, _("Conductance per unit length"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText26711111111->Wrap( -1 );
fgSizer13111->Add( m_staticText26711111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLossyG = new wxTextCtrl( m_tlineLossy, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer13111->Add( m_tlineLossyG, 1, wxALL|wxEXPAND, 5 );
m_staticText262111111111 = new wxStaticText( m_tlineLossy, wxID_ANY, _("siemens / unit"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText262111111111->Wrap( -1 );
fgSizer13111->Add( m_staticText262111111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText267111111111 = new wxStaticText( m_tlineLossy, wxID_ANY, _("Length"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText267111111111->Wrap( -1 );
fgSizer13111->Add( m_staticText267111111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLossyLen = new wxTextCtrl( m_tlineLossy, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer13111->Add( m_tlineLossyLen, 0, wxALL|wxEXPAND, 5 );
m_staticText262111111112 = new wxStaticText( m_tlineLossy, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText262111111112->Wrap( -1 );
fgSizer13111->Add( m_staticText262111111112, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_staticText2671111111111 = new wxStaticText( m_tlineLossy, wxID_ANY, _("Extra parameters"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText2671111111111->Wrap( -1 );
fgSizer13111->Add( m_staticText2671111111111, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_tlineLossyParams = new wxTextCtrl( m_tlineLossy, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer13111->Add( m_tlineLossyParams, 0, wxALL|wxEXPAND, 5 );
fgSizer1312->Add( fgSizer13111, 1, wxALL|wxEXPAND, 5 );
m_staticline21 = new wxStaticLine( m_tlineLossy, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgSizer1312->Add( m_staticline21, 0, wxEXPAND | wxALL, 5 );
m_staticText1812 = new wxStaticText( m_tlineLossy, wxID_ANY, _("The following types of lines have been implemented so far:\n\n- RLC\n- RC\n- LC\n- RG\n\nAny other combination will yield erroneous results and should not be tried."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1812->Wrap( -1 );
fgSizer1312->Add( m_staticText1812, 0, wxALL|wxEXPAND, 5 );
m_tlineLossy->SetSizer( fgSizer1312 );
m_tlineLossy->Layout();
fgSizer1312->Fit( m_tlineLossy );
m_tlineNotebook->AddPage( m_tlineLossy, _("Lossy"), false );
sbSizer31->Add( m_tlineNotebook, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
bSizer42->Add( sbSizer31, 0, wxALL|wxEXPAND, 5 );
m_tline->SetSizer( bSizer42 );
m_tline->Layout();
bSizer42->Fit( m_tline );
m_notebook->AddPage( m_tline, _("Transmission Line"), true );
bSizer1->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );

File diff suppressed because it is too large Load Diff

View File

@ -230,6 +230,41 @@ class DIALOG_SPICE_MODEL_BASE : public DIALOG_SHIM
wxTextCtrl* m_rnParam2;
wxPanel* m_pwrExtData;
wxRadioBox* m_pwrType;
wxPanel* m_tline;
wxNotebook* m_tlineNotebook;
wxPanel* m_tlineLossless;
wxStaticText* m_staticText2671111;
wxTextCtrl* m_tlineLosslessImpedance;
wxStaticText* m_staticText26211111;
wxStaticText* m_staticText26711111;
wxTextCtrl* m_tlineLosslessDelay;
wxStaticText* m_staticText262111111;
wxStaticText* m_staticText267111111;
wxTextCtrl* m_tlineLosslessFrequency;
wxStaticText* m_staticText2621111111;
wxStaticText* m_staticText2671111111;
wxTextCtrl* m_tlineLosslessWavelength;
wxRadioBox* m_tlineLosslessDelayMode;
wxPanel* m_tlineLossy;
wxStaticText* m_staticText26711112;
wxTextCtrl* m_tlineLossyR;
wxStaticText* m_staticText262111112;
wxStaticText* m_staticText267111112;
wxTextCtrl* m_tlineLossyL;
wxStaticText* m_staticText2621111112;
wxStaticText* m_staticText2671111112;
wxTextCtrl* m_tlineLossyC;
wxStaticText* m_staticText26211111111;
wxStaticText* m_staticText26711111111;
wxTextCtrl* m_tlineLossyG;
wxStaticText* m_staticText262111111111;
wxStaticText* m_staticText267111111111;
wxTextCtrl* m_tlineLossyLen;
wxStaticText* m_staticText262111111112;
wxStaticText* m_staticText2671111111111;
wxTextCtrl* m_tlineLossyParams;
wxStaticLine* m_staticline21;
wxStaticText* m_staticText1812;
wxStaticLine* m_staticline2;
wxCheckBox* m_disabled;
wxCheckBox* m_nodeSeqCheck;

View File

@ -27,6 +27,7 @@
#include <build_version.h>
#include <confirm.h>
#include <algorithm>
#include <map>
#include <search_stack.h>
@ -296,6 +297,18 @@ wxString NETLIST_EXPORTER_PSPICE::GetSpiceFieldDefVal( SPICE_FIELD aField, SCH_S
}
}
wxString modelLine( wxString aName, wxString aParams )
{
wxString result;
result = aName;
result += "\n.model ";
result += aName;
result += " ";
result += aParams;
return result;
}
bool NETLIST_EXPORTER_PSPICE::ProcessNetlist( unsigned aCtl )
{
@ -304,7 +317,10 @@ bool NETLIST_EXPORTER_PSPICE::ProcessNetlist( unsigned aCtl )
std::set<wxString> refNames; // Set of reference names, to check for duplication
m_netMap.clear();
m_netMap["GND"] = 0; // 0 is reserved for "GND"
int refNet = 0;
const char* refNetString = "0";
m_netMap["GND"] = refNet; // 0 is reserved for "GND"
int netIdx = 1;
m_libraries.clear();
@ -392,7 +408,53 @@ bool NETLIST_EXPORTER_PSPICE::ProcessNetlist( unsigned aCtl )
}
}
//Special case because we have a GUI to set a model.
if( spiceItem.m_primitive == SP_TLINE_LOSSY )
{
spiceItem.m_model =
modelLine( "LTRA_" + spiceItem.m_refName, "LTRA " + spiceItem.m_model );
}
m_spiceItems.push_back( spiceItem );
//Special case for lossline transmission lines ( TXXXX )
//From the ngspice doc:
// This element models only one propagating mode.
// If all four nodes are distinct in the actual circuit, then two modes may be excited.
// To simulate such a situation, two transmission-line elements are required.
// This is apparently also needed for lossy lines
if( spiceItem.m_primitive == SP_TLINE || spiceItem.m_primitive == SP_TLINE_LOSSY )
{
std::vector<wxString> pins = spiceItem.m_pins;
std::vector<wxString> pins2 = pins;
if( pins.size() == 4 ) // A transmission line as 4 pins in ngspice
{
std::sort( pins2.begin(), pins2.end(),
[]( wxString& a, wxString& b ) -> bool
{
return a.Cmp( b ) < 0;
} );
bool has_duplicate =
std::adjacent_find( pins2.begin(), pins2.end() ) != pins2.end();
if( !has_duplicate )
{
SPICE_ITEM spiceItem2 = spiceItem;
spiceItem2.m_refName += "_kicad_pair";
spiceItem2.m_pins.at( 0 ) = pins.at( 1 );
spiceItem2.m_pins.at( 1 ) = refNetString;
spiceItem2.m_pins.at( 2 ) = pins.at( 3 );
spiceItem2.m_pins.at( 3 ) = refNetString;
m_spiceItems.push_back( spiceItem2 );
}
}
}
}
}

View File

@ -54,6 +54,8 @@ enum SPICE_PRIMITIVE {
SP_RESISTOR = 'R',
SP_CAPACITOR = 'C',
SP_INDUCTOR = 'L',
SP_TLINE = 'T',
SP_TLINE_LOSSY = 'O',
SP_DIODE = 'D',
SP_BJT = 'Q',
SP_MOSFET = 'M',