Add simple VI model inference.

This commit is contained in:
Jeff Young 2022-12-18 22:53:53 +00:00
parent f8d2bdbdf9
commit 7192c565b8
5 changed files with 211 additions and 137 deletions

View File

@ -133,35 +133,31 @@ template <typename T_symbol, typename T_field>
bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
{
wxCommandEvent dummyEvent;
wxString deviceType;
wxString modelType;
wxString modelParams;
wxString pinMap;
// Infer RLC models if they aren't specified
if( !m_symbol.FindField( SIM_MODEL::DEVICE_TYPE_FIELD )
&& !m_symbol.FindField( SIM_MODEL::PARAMS_FIELD ) )
// Infer RLC and VI models if they aren't specified
if( SIM_MODEL::InferSimModel<T_symbol, T_field>( m_symbol, false, SIM_VALUE_GRAMMAR::NOTATION::SI,
&deviceType, &modelType, &modelParams, &pinMap ) )
{
wxString modelType;
wxString modelParams;
wxString pinMap;
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
m_fields.back().SetText( deviceType );
if( SIM_MODEL::InferPassiveSimModel( m_symbol, false, SIM_VALUE_GRAMMAR::NOTATION::SI,
&modelType, &modelParams, &pinMap ) )
if( !modelType.IsEmpty() )
{
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
m_fields.back().SetText( m_symbol.GetPrefix().Left( 1 ) );
if( !modelType.IsEmpty() )
{
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::TYPE_FIELD );
m_fields.back().SetText( modelType );
}
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::PARAMS_FIELD );
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}" ) );
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::TYPE_FIELD );
m_fields.back().SetText( modelType );
}
m_fields.emplace_back( &m_symbol, -1, SIM_MODEL::PARAMS_FIELD );
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}" ) );
}
std::string libraryFilename = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::LIBRARY_FIELD );
@ -264,10 +260,10 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
+ e.What() );
}
SIM_MODEL::DEVICE_T deviceType = SIM_MODEL::TypeInfo( type ).deviceType;
SIM_MODEL::DEVICE_T deviceTypeT = SIM_MODEL::TypeInfo( type ).deviceType;
if( !m_curModelTypeOfDeviceType.count( deviceType ) )
m_curModelTypeOfDeviceType[deviceType] = type;
if( !m_curModelTypeOfDeviceType.count( deviceTypeT ) )
m_curModelTypeOfDeviceType[deviceTypeT] = type;
}
m_saveInValueCheckbox->SetValue( curModel().IsStoredInValue() );

View File

@ -232,33 +232,31 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
spiceItem.fields.back().SetText( symbol->GetFields()[i].GetShownText( 0, false ) );
}
// Infer RLC models if they aren't specified
if( !symbol->FindField( SIM_MODEL::DEVICE_TYPE_FIELD, false )
&& !symbol->FindField( SIM_MODEL::PARAMS_FIELD, false ) )
wxString deviceType;
wxString modelType;
wxString modelParams;
wxString pinMap;
// Infer RLC and VI models if they aren't specified
if( SIM_MODEL::InferSimModel<SCH_SYMBOL, SCH_FIELD>( *symbol, true,
SIM_VALUE_GRAMMAR::NOTATION::SPICE,
&deviceType, &modelType,
&modelParams, &pinMap ) )
{
wxString modelType;
wxString modelParams;
wxString pinMap;
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
spiceItem.fields.back().SetText( deviceType );
if( SIM_MODEL::InferPassiveSimModel( *symbol, true,
SIM_VALUE_GRAMMAR::NOTATION::SPICE,
&modelType, &modelParams, &pinMap ) )
if( !modelType.IsEmpty() )
{
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
spiceItem.fields.back().SetText( symbol->GetPrefix().Left( 1 ) );
if( !modelType.IsEmpty() )
{
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::TYPE_FIELD );
spiceItem.fields.back().SetText( modelType );
}
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::PARAMS_FIELD );
spiceItem.fields.back().SetText( modelParams );
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::PINS_FIELD );
spiceItem.fields.back().SetText( pinMap );
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::TYPE_FIELD );
spiceItem.fields.back().SetText( modelType );
}
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::PARAMS_FIELD );
spiceItem.fields.back().SetText( modelParams );
spiceItem.fields.emplace_back( symbol, -1, SIM_MODEL::PINS_FIELD );
spiceItem.fields.back().SetText( pinMap );
}
try

View File

@ -197,32 +197,31 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S
fields.back().SetText( aSymbol.GetFields()[ i ].GetShownText( 0, false ) );
}
// Infer RLC models if they aren't specified
if( !aSymbol.FindField( SIM_MODEL::DEVICE_TYPE_FIELD, false )
&& !aSymbol.FindField( SIM_MODEL::PARAMS_FIELD, false ) )
wxString deviceType;
wxString modelType;
wxString modelParams;
wxString pinMap;
// Infer RLC and VI models if they aren't specified
if( SIM_MODEL::InferSimModel<SCH_SYMBOL, SCH_FIELD>( aSymbol, true,
SIM_VALUE_GRAMMAR::NOTATION::SI,
&deviceType, &modelType, &modelParams,
&pinMap ) )
{
wxString modelType;
wxString modelParams;
wxString pinMap;
fields.emplace_back( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
fields.back().SetText( deviceType );
if( SIM_MODEL::InferPassiveSimModel( aSymbol, true, SIM_VALUE_GRAMMAR::NOTATION::SI,
&modelType, &modelParams, &pinMap ) )
if( !modelType.IsEmpty() )
{
fields.emplace_back( &aSymbol, -1, SIM_MODEL::DEVICE_TYPE_FIELD );
fields.back().SetText( aSymbol.GetPrefix().Left( 1 ) );
if( !modelType.IsEmpty() )
{
fields.emplace_back( &aSymbol, -1, SIM_MODEL::TYPE_FIELD );
fields.back().SetText( modelType );
}
fields.emplace_back( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
fields.back().SetText( modelParams );
fields.emplace_back( &aSymbol, -1, SIM_MODEL::PINS_FIELD );
fields.back().SetText( pinMap );
fields.emplace_back( &aSymbol, -1, SIM_MODEL::TYPE_FIELD );
fields.back().SetText( modelType );
}
fields.emplace_back( &aSymbol, -1, SIM_MODEL::PARAMS_FIELD );
fields.back().SetText( modelParams );
fields.emplace_back( &aSymbol, -1, SIM_MODEL::PINS_FIELD );
fields.back().SetText( pinMap );
}
std::vector<LIB_PIN*> sourcePins = aSymbol.GetAllLibPins();

View File

@ -1049,103 +1049,184 @@ bool SIM_MODEL::requiresSpiceModelLine() const
}
template <class T>
bool SIM_MODEL::InferPassiveSimModel( T& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aModelType,
wxString* aModelParams, wxString* aPinMap )
template <class T_symbol, class T_field>
bool SIM_MODEL::InferSimModel( T_symbol& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aDeviceType,
wxString* aModelType, wxString* aModelParams, wxString* aPinMap )
{
wxString aPrefix = aSymbol.GetPrefix();
wxString aValue;
auto convertNotation =
[&]( const wxString& units ) -> wxString
{
if( aNotation == SIM_VALUE_GRAMMAR::NOTATION::SPICE )
{
if( units == wxT( "M" ) )
return wxT( "Meg" );
}
else if( aNotation == SIM_VALUE_GRAMMAR::NOTATION::SI )
{
if( units == wxT( "Meg" ) || units == wxT( "MEG" ) )
return wxT( "M" );
}
if( aResolve )
aValue = aSymbol.FindField( VALUE_FIELD )->GetShownText();
else
aValue = aSymbol.FindField( VALUE_FIELD )->GetText();
return units;
};
if( !aValue.IsEmpty() )
auto getFieldValue =
[&]( const wxString& fieldName ) -> wxString
{
T_field* field = aSymbol.FindField( fieldName );
if( field )
{
if( aResolve )
return field->GetShownText();
else
return field->GetText();
}
return wxEmptyString;
};
wxString prefix = aSymbol.GetPrefix();
wxString value = getFieldValue( VALUE_FIELD );
std::vector<LIB_PIN*> pins = aSymbol.GetAllLibPins();
*aDeviceType = getFieldValue( DEVICE_TYPE_FIELD );
*aModelType = getFieldValue( TYPE_FIELD );
*aModelParams = getFieldValue( PARAMS_FIELD );
*aPinMap = getFieldValue( PINS_FIELD );
if( pins.size() != 2 )
return false;
if( aDeviceType->IsEmpty()
&& aModelType->IsEmpty()
&& !value.IsEmpty()
&& ( prefix.StartsWith( "R" ) || prefix.StartsWith( "L" ) || prefix.StartsWith( "C" ) ) )
{
if( aPrefix.StartsWith( wxT( "R" ) )
|| aPrefix.StartsWith( wxT( "L" ) )
|| aPrefix.StartsWith( wxT( "C" ) ) )
if( aDeviceType->IsEmpty() )
*aDeviceType = prefix.Left( 1 );
if( aModelParams->IsEmpty() )
{
wxRegEx idealVal( wxT( "^"
"([0-9\\. ]+)"
"([fFpPnNuUmMkKgGtTμµ𝛍𝜇𝝁 ]|M(e|E)(g|G))?"
"([fFhHΩΩ𝛀𝛺𝝮]|ohm)?"
"([fFhHΩΩ𝛀𝛺𝝮rR]|ohm)?"
"([-1-9 ]*)"
"([fFhHΩΩ𝛀𝛺𝝮rR]|ohm)?"
"$" ) );
if( idealVal.Matches( aValue ) ) // Ideal
if( idealVal.Matches( value ) ) // Ideal
{
wxString valuePrefix( idealVal.GetMatch( aValue, 1 ) );
wxString valueUnits( idealVal.GetMatch( aValue, 2 ) );
wxString valueSuffix( idealVal.GetMatch( aValue, 6 ) );
wxString valueMantissa( idealVal.GetMatch( value, 1 ) );
wxString valueNotation( idealVal.GetMatch( value, 2 ) );
wxString valueFraction( idealVal.GetMatch( value, 6 ) );
if( aNotation == SIM_VALUE_GRAMMAR::NOTATION::SPICE )
if( valueMantissa.Contains( wxT( "." ) ) )
{
if( valueUnits == wxT( "M" ) )
valueUnits = wxT( "Meg" );
aModelParams->Printf( wxT( "%s=\"%s%s\"" ),
prefix.Left(1).Lower(),
valueMantissa, convertNotation( valueNotation ) );
}
else if( aNotation == SIM_VALUE_GRAMMAR::NOTATION::SI )
else
{
if( valueUnits == wxT( "Meg" ) || valueUnits == wxT( "MEG" ) )
valueUnits = wxT( "M" );
aModelParams->Printf( wxT( "%s=\"%s.%s%s\"" ),
prefix.Left(1).Lower(),
valueMantissa,
valueFraction,
convertNotation( valueNotation ) );
}
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 );
aModelParams->Printf( wxT( "%s=\"%s\"" ), prefix.Left(1).Lower(), value );
}
}
std::vector<LIB_PIN*> pins = aSymbol.GetAllLibPins();
if( aPinMap->IsEmpty() )
aPinMap->Printf( wxT( "%s=+ %s=-" ), pins[0]->GetNumber(), pins[1]->GetNumber() );
if( pins.size() == 2 )
return true;
}
bool inferDCSource = false;
if( ( ( *aDeviceType == wxT( "V" ) || *aDeviceType == wxT( "I" ) )
&& aModelType->IsEmpty() )
||
( aDeviceType->IsEmpty()
&& aModelType->IsEmpty()
&& !value.IsEmpty()
&& ( prefix.StartsWith( "V" ) || prefix.StartsWith( "I" ) ) ) )
{
if( aDeviceType->IsEmpty() )
*aDeviceType = prefix.Left( 1 );
if( aModelType->IsEmpty() )
*aModelType = wxT( "DC" );
if( aModelParams->IsEmpty() )
{
wxRegEx sourceVal( wxT( "^"
"([0-9\\. ]+)"
"([fFpPnNuUmMkKgGtTμµ𝛍𝜇𝝁 ]|M(e|E)(g|G))?"
"([vVaA])?"
"([-1-9 ]*)"
"([vVaA])?"
"$" ) );
if( sourceVal.Matches( value ) )
{
aPinMap->Printf( wxT( "%s=+ %s=-" ),
pins[0]->GetNumber(),
pins[1]->GetNumber() );
wxString valueMantissa( sourceVal.GetMatch( value, 1 ) );
wxString valueNotation( sourceVal.GetMatch( value, 2 ) );
wxString valueFraction( sourceVal.GetMatch( value, 6 ) );
if( valueMantissa.Contains( wxT( "." ) ) )
{
aModelParams->Printf( wxT( "dc=\"%s%s\"" ),
valueMantissa,
convertNotation( valueNotation ) );
}
else
{
aModelParams->Printf( wxT( "dc=\"%s.%s%s\"" ),
valueMantissa,
valueFraction,
convertNotation( valueNotation ) );
}
}
else
{
*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 ) );
}
aModelParams->Printf( wxT( "dc=\"%s\"" ), value );
}
return true;
}
if( aPinMap->IsEmpty() )
aPinMap->Printf( wxT( "%s=+ %s=-" ), pins[0]->GetNumber(), pins[1]->GetNumber() );
return true;
}
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 bool SIM_MODEL::InferSimModel<SCH_SYMBOL, SCH_FIELD>( SCH_SYMBOL& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation,
wxString* aDeviceType,
wxString* aModelType,
wxString* aModelParams,
wxString* aPinMap );
template bool SIM_MODEL::InferSimModel<LIB_SYMBOL, LIB_FIELD>( LIB_SYMBOL& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation,
wxString* aDeviceType,
wxString* aModelType,
wxString* aModelParams,
wxString* aPinMap );
template <typename T_symbol, typename T_field>

View File

@ -518,10 +518,10 @@ public:
virtual void SwitchSingleEndedDiff( bool aDiff ) { };
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 bool InferSimModel( T_symbol& aSymbol, bool aResolve,
SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString* aDeviceType,
wxString* aModelType, wxString* aModelParams, wxString* aPinMap );
template <class T_symbol, class T_field>
static void MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject );