We must infer a pinMap when inferring other fields for RLC passives.

Fixes https://gitlab.com/kicad/code/kicad/issues/13162
This commit is contained in:
Jeff Young 2022-12-14 23:21:35 +00:00
parent 93879532f7
commit b2e512bfab
5 changed files with 116 additions and 62 deletions

View File

@ -136,29 +136,32 @@ template <typename T_symbol, typename T_field>
bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
{
wxCommandEvent dummyEvent;
T_field* valueField = m_symbol.FindField( wxT( "Value" ) );
// Infer RLC models if they aren't specified
if( !m_symbol.FindField( SIM_MODEL::DEVICE_TYPE_FIELD )
&& !m_symbol.FindField( SIM_MODEL::PARAMS_FIELD ) )
{
// std::pair<wxString, wxString> [ Sim.Type, Sim.Params ]
auto inferredModel = SIM_MODEL::InferSimModel( m_symbol.GetPrefix(), valueField->GetText(),
SIM_VALUE_GRAMMAR::NOTATION::SI );
wxString modelType;
wxString modelParams;
wxString pinMap;
if( !inferredModel.second.IsEmpty() )
if( SIM_MODEL::InferPassiveSimModel( m_symbol, false, SIM_VALUE_GRAMMAR::NOTATION::SI,
&modelType, &modelParams, &pinMap ) )
{
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
m_fields.back().SetText( m_symbol.GetPrefix() );
m_fields.back().SetText( m_symbol.GetPrefix().Left( 1 ) );
if( !inferredModel.first.IsEmpty() )
if( !modelType.IsEmpty() )
{
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::TYPE_FIELD );
m_fields.back().SetText( inferredModel.first );
m_fields.back().SetText( modelType );
}
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::PARAMS_FIELD );
m_fields.back().SetText( inferredModel.second );
m_fields.back().SetText( modelParams );
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::PINS_FIELD );
m_fields.back().SetText( pinMap );
m_fields[ VALUE_FIELD ].SetText( wxT( "${SIM.PARAMS}" ) );
}

View File

@ -235,24 +235,28 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
if( !symbol->FindField( SIM_MODEL::DEVICE_TYPE_FIELD, false )
&& !symbol->FindField( SIM_MODEL::PARAMS_FIELD, false ) )
{
// std::pair<wxString, wxString> [ Sim.Type, Sim.Params ]
auto inferredModel = SIM_MODEL::InferSimModel( symbol->GetPrefix(),
symbol->GetValueFieldText( true ),
SIM_VALUE_GRAMMAR::NOTATION::SPICE );
wxString modelType;
wxString modelParams;
wxString pinMap;
if( !inferredModel.second.IsEmpty() )
if( SIM_MODEL::InferPassiveSimModel( *symbol, true,
SIM_VALUE_GRAMMAR::NOTATION::SPICE,
&modelType, &modelParams, &pinMap ) )
{
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
spiceItem.fields.back().SetText( symbol->GetPrefix().Left( 1 ) );
if( !inferredModel.first.IsEmpty() )
if( !modelType.IsEmpty() )
{
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::TYPE_FIELD );
spiceItem.fields.back().SetText( inferredModel.first );
spiceItem.fields.back().SetText( modelType );
}
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::PARAMS_FIELD );
spiceItem.fields.back().SetText( inferredModel.second );
spiceItem.fields.back().SetText( modelParams );
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::PINS_FIELD );
spiceItem.fields.back().SetText( pinMap );
}
}

View File

@ -183,24 +183,27 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S
if( !aSymbol.FindField( SIM_MODEL::DEVICE_TYPE_FIELD, false )
&& !aSymbol.FindField( SIM_MODEL::PARAMS_FIELD, false ) )
{
// std::pair<wxString, wxString> [ Sim.Type, Sim.Params ]
auto inferredModel = SIM_MODEL::InferSimModel( aSymbol.GetPrefix(),
aSymbol.GetValueFieldText( true ),
SIM_VALUE_GRAMMAR::NOTATION::SI );
wxString modelType;
wxString modelParams;
wxString pinMap;
if( !inferredModel.second.IsEmpty() )
if( SIM_MODEL::InferPassiveSimModel( aSymbol, true, SIM_VALUE_GRAMMAR::NOTATION::SI,
&modelType, &modelParams, &pinMap ) )
{
fields.emplace_back( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
fields.back().SetText( aSymbol.GetPrefix() );
fields.back().SetText( aSymbol.GetPrefix().Left( 1 ) );
if( !inferredModel.first.IsEmpty() )
if( !modelType.IsEmpty() )
{
fields.emplace_back( &aSymbol, -1, SIM_MODEL::TYPE_FIELD );
fields.back().SetText( inferredModel.first );
fields.back().SetText( modelType );
}
fields.emplace_back( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
fields.back().SetText( inferredModel.second );
fields.back().SetText( modelParams );
fields.emplace_back( &aSymbol, -1, SIM_MODEL::PINS_FIELD );
fields.back().SetText( pinMap );
}
}

View File

@ -1033,13 +1033,18 @@ bool SIM_MODEL::requiresSpiceModelLine() const
}
// Returns [ Sim.Type, Sim.Params ]
std::pair<wxString, wxString> SIM_MODEL::InferSimModel( const wxString& aPrefix,
const wxString& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
template <class T>
bool SIM_MODEL::InferPassiveSimModel( T& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aModelType,
wxString* aModelParams, wxString* aPinMap )
{
wxString spiceModelType;
wxString spiceModelParams;
wxString aPrefix = aSymbol.GetPrefix();
wxString aValue;
if( aResolve )
aValue = aSymbol.FindField( VALUE_FIELD )->GetShownText();
else
aValue = aSymbol.FindField( VALUE_FIELD )->GetText();
if( !aValue.IsEmpty() )
{
@ -1047,18 +1052,18 @@ std::pair<wxString, wxString> SIM_MODEL::InferSimModel( const wxString& aPrefix,
|| aPrefix.StartsWith( wxT( "L" ) )
|| aPrefix.StartsWith( wxT( "C" ) ) )
{
wxRegEx passiveVal( wxT( "^"
"([0-9\\. ]+)"
"([fFpPnNuUmMkKgGtTμµ𝛍𝜇𝝁 ]|M(e|E)(g|G))?"
"([fFhHΩΩ𝛀𝛺𝝮]|ohm)?"
"([-1-9 ]*)"
"$" ) );
wxRegEx idealVal( wxT( "^"
"([0-9\\. ]+)"
"([fFpPnNuUmMkKgGtTμµ𝛍𝜇𝝁 ]|M(e|E)(g|G))?"
"([fFhHΩΩ𝛀𝛺𝝮]|ohm)?"
"([-1-9 ]*)"
"$" ) );
if( passiveVal.Matches( aValue ) )
if( idealVal.Matches( aValue ) ) // Ideal
{
wxString valuePrefix( passiveVal.GetMatch( aValue, 1 ) );
wxString valueUnits( passiveVal.GetMatch( aValue, 2 ) );
wxString valueSuffix( passiveVal.GetMatch( aValue, 6 ) );
wxString valuePrefix( idealVal.GetMatch( aValue, 1 ) );
wxString valueUnits( idealVal.GetMatch( aValue, 2 ) );
wxString valueSuffix( idealVal.GetMatch( aValue, 6 ) );
if( aNotation == SIM_VALUE_GRAMMAR::NOTATION::SPICE )
{
@ -1071,25 +1076,62 @@ std::pair<wxString, wxString> SIM_MODEL::InferSimModel( const wxString& aPrefix,
valueUnits = wxT( "M" );
}
spiceModelParams = wxString::Format( wxT( "%s=\"%s%s\"" ),
aPrefix.Left(1).Lower(),
valuePrefix,
valueUnits );
aModelParams->Printf( wxT( "%s=\"%s%s\"" ),
aPrefix.Left(1).Lower(),
valuePrefix,
valueUnits );
}
else // Behavioral
{
*aModelType = wxT( "=" );
aModelParams->Printf( wxT( "%s=\"%s\"" ),
aPrefix.Left(1).Lower(),
aValue );
}
std::vector<LIB_PIN*> pins = aSymbol.GetLibPins();
if( pins.size() == 2 )
{
aPinMap->Printf( wxT( "%s=+ %s=-" ),
pins[0]->GetNumber(),
pins[1]->GetNumber() );
}
else
{
spiceModelType = wxT( "=" );
spiceModelParams = wxString::Format( wxT( "%s=\"%s\"" ),
aPrefix.Left(1).Lower(),
aValue );
*aPinMap = wxEmptyString;
for( unsigned ii = 0; ii < pins.size(); ++ii )
{
if( ii > 0 )
aPinMap->Append( wxS( " " ) );
aPinMap->Append( wxString::Format( wxT( "%s=%u" ),
pins[ii]->GetNumber(),
ii ) );
}
}
return true;
}
}
return std::make_pair( spiceModelType, spiceModelParams );
return false;
}
template bool SIM_MODEL::InferPassiveSimModel<SCH_SYMBOL>( SCH_SYMBOL& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation,
wxString* aModelType,
wxString* aModelParams,
wxString* aPinMap );
template bool SIM_MODEL::InferPassiveSimModel<LIB_SYMBOL>( LIB_SYMBOL& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation,
wxString* aModelType,
wxString* aModelParams,
wxString* aPinMap );
template <typename T_symbol, typename T_field>
void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
{
@ -1180,7 +1222,12 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
|| netlistEnabled.StartsWith( wxT( "n" ) )
|| netlistEnabled.StartsWith( wxT( "f" ) ) )
{
T_field enableField( &aSymbol, aSymbol.GetFieldCount(), SIM_MODEL::ENABLE_FIELD );
netlistEnabledField->SetName( SIM_MODEL::ENABLE_FIELD );
netlistEnabledField->SetText( wxT( "0" ) );
}
else
{
aSymbol.RemoveField( netlistEnabledField );
}
}
@ -1212,10 +1259,9 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
if( T_field* legacyPins = aSymbol.FindField( wxT( "Sim_Pins" ) ) )
{
// std::pair<wxString, wxString> [ Sim.Type, Sim.Params ]
auto inferredModel = SIM_MODEL::InferSimModel( prefix, valueField->GetText(),
SIM_VALUE_GRAMMAR::NOTATION::SI );
bool isPassive = !inferredModel.second.IsEmpty();
bool isPassive = prefix.StartsWith( wxT( "R" ) )
|| prefix.StartsWith( wxT( "L" ) )
|| prefix.StartsWith( wxT( "C" ) );
// Migrate pins from array of indexes to name-value-pairs
wxArrayString pinIndexes;

View File

@ -522,12 +522,10 @@ public:
}
bool IsStoredInValue() const { return m_isStoredInValue; }
/**
* Returns std::pair of [ Sim.Type, Sim.Params ]
*/
static std::pair<wxString, wxString> InferSimModel( const wxString& aPrefix,
const wxString& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation );
template <class T>
static bool InferPassiveSimModel( T& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aModelType,
wxString* aModelParams, wxString* aPinMap );
template <class T_symbol, class T_field>
static void MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject );