Convert OP text variables pin names/numbers to SPICE vectors.

Also fixes a wrap-around bug in SPICE_VALUE::Normalize() where
it would lose the run of itself if the value was already
normalized to either the largest or smallest UNIT_PREFIX.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17228

(cherry picked from commit ff8ddae9bd)
This commit is contained in:
Jeff Young 2024-03-04 14:24:00 +00:00
parent 45e17307a1
commit 03af8dcc88
4 changed files with 70 additions and 19 deletions

View File

@ -33,6 +33,9 @@
#include <sch_symbol.h>
#include <sch_sheet_path.h>
#include <schematic.h>
#include <sim/sim_model.h>
#include <sim/spice_generator.h>
#include <sim/sim_lib_mgr.h>
#include <trace_helpers.h>
#include <trigo.h>
#include <refdes_utils.h>
@ -1285,7 +1288,7 @@ bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, i
{
static wxRegEx operatingPoint( wxT( "^"
"OP"
"(:[a-zA-Z]*)?" // port
"(:[^.]*)?" // pin
"(.([0-9])?([a-zA-Z]*))?" // format
"$" ) );
@ -1298,26 +1301,66 @@ bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, i
if( operatingPoint.Matches( *token ) )
{
wxString port( operatingPoint.GetMatch( *token, 1 ) );
wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
wxString range( operatingPoint.GetMatch( *token, 4 ) );
wxString signal = GetRef( aPath ) + port;
int precision = 3;
if( !precisionStr.IsEmpty() )
precision = precisionStr[0] - '0';
if( range.IsEmpty() )
range = wxS( "~A" );
SIM_LIB_MGR simLibMgr( &schematic->Prj() );
NULL_REPORTER devnull;
SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ),
devnull ).model;
SPICE_ITEM spiceItem;
spiceItem.refName = GetRef( aPath );
wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
spiceRef = spiceRef.Lower();
if( pin.IsEmpty() )
{
if( port == wxS( ":power" ) )
*token = schematic->GetOperatingPoint( spiceRef, precision, range );
return true;
}
else if( pin == wxS( ":power" ) )
{
if( range.IsEmpty() )
range = wxS( "~W" );
else
range = wxS( "~A" );
*token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
return true;
}
else
{
pin = pin.SubString( 1, -1 ); // Strip ':' from front
for( const std::reference_wrapper<const SIM_MODEL::PIN>& modelPin : model.GetPins() )
{
SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
{
if( model.GetPins().size() == 2 )
{
*token = schematic->GetOperatingPoint( spiceRef, precision, range );
}
else
{
wxString signalName = spiceRef + wxS( ":" ) + modelPin.get().name;
*token = schematic->GetOperatingPoint( signalName, precision, range );
}
return true;
}
}
}
*token = schematic->GetOperatingPoint( signal.Lower(), precision, range );
*token = wxS( "?" );
return true;
}

View File

@ -202,12 +202,17 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S
for( const SCH_FIELD& field : aSymbol.GetFields() )
{
fields.emplace_back( VECTOR2I(), -1, &aSymbol, field.GetName() );
if( field.GetId() == REFERENCE_FIELD )
{
fields.emplace_back( VECTOR2I(), -1, &aSymbol, field.GetName() );
fields.back().SetText( aSymbol.GetRef( aSheetPath ) );
else
}
else if( field.GetId() == VALUE_FIELD
|| field.GetName().StartsWith( wxS( "Sim." ) ) )
{
fields.emplace_back( VECTOR2I(), -1, &aSymbol, field.GetName() );
fields.back().SetText( field.GetShownText( aSheetPath, false ) );
}
}
wxString deviceType;

View File

@ -2795,9 +2795,12 @@ void SIMULATOR_FRAME_UI::OnSimRefresh( bool aFinal )
m_simConsole->AppendText( msg );
m_simConsole->SetInsertionPointEnd();
if( signal.StartsWith( wxS( "V(" ) ) || signal.StartsWith( wxS( "I(" ) ) )
if( type == SPT_VOLTAGE || type == SPT_CURRENT || type == SPT_POWER )
signal = signal.SubString( 2, signal.Length() - 2 );
if( type == SPT_POWER )
signal += wxS( ":power" );
m_schematicFrame->Schematic().SetOperatingPoint( signal, val_list.at( 0 ) );
}
}

View File

@ -115,20 +115,20 @@ void SPICE_VALUE::Normalize()
{
while( std::fabs( m_base ) >= 1000.0 )
{
m_base *= 0.001;
m_prefix = (UNIT_PREFIX)( m_prefix + 3 );
if( m_prefix == PFX_TERA ) // this is the biggest unit available
break;
m_base *= 0.001;
m_prefix = (UNIT_PREFIX)( m_prefix + 3 );
}
while( m_base != 0.0 && std::fabs( m_base ) < 1.000 )
{
m_base *= 1000.0;
m_prefix = (UNIT_PREFIX)( m_prefix - 3 );
if( m_prefix == PFX_FEMTO ) // this is the smallest unit available
break;
m_base *= 1000.0;
m_prefix = (UNIT_PREFIX)( m_prefix - 3 );
}
}