Add tuner support for potentiometer code model

This commit is contained in:
Frank Zeeman 2020-10-23 21:28:03 +02:00 committed by Mikolaj Wielgus
parent e618ef98e9
commit f004665df8
5 changed files with 76 additions and 18 deletions

View File

@ -61,6 +61,36 @@ wxString NETLIST_EXPORTER_PSPICE::GetSpiceDevice( const wxString& aSymbol ) cons
} }
// most part is identical to above GetSpiceDevice()
std::pair<wxString, bool>
NETLIST_EXPORTER_PSPICE::GetSpiceTuningCommand( const wxString& aSymbol ) const
{
const std::list<SPICE_ITEM>& spiceItems = GetSpiceItems();
auto it = std::find_if( spiceItems.begin(), spiceItems.end(),
[&]( const SPICE_ITEM& item )
{
return item.m_refName == aSymbol;
} );
if( it == spiceItems.end() )
return { wxEmptyString, false };
/// @todo assuming ngspice potentiometer code model
/// @todo no ngspice hard coding
if( it->m_primitive == SP_CODEMODEL )
return { "altermod @" + it->m_model.Lower() + "[position]=", true };
// Prefix the device type if plain reference would result in a different device type
wxString name = it->m_primitive != it->m_refName[0]
? wxString( it->m_primitive + it->m_refName )
: it->m_refName;
/// @todo no ngspice hard coding
return { "alter @" + name.Lower() + "=", false };
}
bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions ) bool NETLIST_EXPORTER_PSPICE::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions )
{ {
FILE_OUTPUTFORMATTER outputFile( aOutFileName, wxT( "wt" ), '\'' ); FILE_OUTPUTFORMATTER outputFile( aOutFileName, wxT( "wt" ), '\'' );

View File

@ -119,6 +119,16 @@ public:
*/ */
wxString GetSpiceDevice( const wxString& aSymbol ) const; wxString GetSpiceDevice( const wxString& aSymbol ) const;
/**
* @brief Returns the command to alter a Spice parameter of a schematic symbol.
*
* @param aSymbol is the symbol reference.
* @return Spice command or empty string if there is no such component in the netlist,
* and true if it is a code model parameter, false if it is an instance parameter.
*/
std::pair<wxString, bool> GetSpiceTuningCommand( const wxString& aSymbol ) const;
/** /**
* Write to specified output file * Write to specified output file
*/ */

View File

@ -539,11 +539,11 @@ void SIM_PLOT_FRAME::AddTuner( SCH_SYMBOL* aSymbol )
if( !plotPanel ) if( !plotPanel )
return; return;
// For now limit the tuner tool to RLC components // For now limit the tuner tool to RLC and code model components
char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aSymbol, 0 )[0]; char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aSymbol, 0 )[0];
if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR
&& primitiveType != SP_INDUCTOR ) && primitiveType != SP_INDUCTOR && primitiveType != SP_CODEMODEL )
return; return;
const wxString componentName = aSymbol->GetField( REFERENCE_FIELD )->GetText(); const wxString componentName = aSymbol->GetField( REFERENCE_FIELD )->GetText();
@ -917,11 +917,15 @@ void SIM_PLOT_FRAME::applyTuners()
{ {
for( auto& tuner : m_tuners ) for( auto& tuner : m_tuners )
{ {
/// @todo no ngspice hard coding std::pair<wxString, bool> command = tuner->GetSpiceTuningCommand();
std::string command( "alter @" + tuner->GetSpiceName() const SPICE_VALUE& value = tuner->GetValue();
+ "=" + tuner->GetValue().ToSpiceString() );
m_simulator->Command( command ); // 0 < value < 1 for model parameter to avoid division by zero, etc.
command.first += command.second
? wxString::FromCDouble( Clamp( 1e-9, value.ToDouble() / 100.0, 1-1e-9 ), 9 )
: value.ToSpiceString();
m_simulator->Command( command.first.ToStdString() );
} }
} }

View File

@ -34,26 +34,40 @@
TUNER_SLIDER::TUNER_SLIDER( SIM_PLOT_FRAME* aFrame, wxWindow* aParent, SCH_SYMBOL* aSymbol ) : TUNER_SLIDER::TUNER_SLIDER( SIM_PLOT_FRAME* aFrame, wxWindow* aParent, SCH_SYMBOL* aSymbol ) :
TUNER_SLIDER_BASE( aParent ), TUNER_SLIDER_BASE( aParent ),
m_symbol( aSymbol ), m_symbol( aSymbol ),
m_fieldId( MANDATORY_FIELD_T::VALUE_FIELD ),
m_min( 0.0 ), m_min( 0.0 ),
m_max( 0.0 ), m_max( 0.0 ),
m_changed( false ), m_value( 0.0 ),
m_frame ( aFrame ) m_frame ( aFrame )
{ {
const wxString compName = aSymbol->GetField( REFERENCE_FIELD )->GetText(); const wxString compName = aSymbol->GetField( REFERENCE_FIELD )->GetText();
m_name->SetLabel( compName ); m_name->SetLabel( compName );
m_spiceTuningCommand = aFrame->GetExporter()->GetSpiceTuningCommand( compName );
if( aSymbol->FindField( NETLIST_EXPORTER_PSPICE::GetSpiceFieldName( SF_MODEL ) ) ) if( m_spiceTuningCommand.second )
m_fieldId = aSymbol->FindField( NETLIST_EXPORTER_PSPICE::GetSpiceFieldName( SF_MODEL ) )->GetId(); {
// model parameter, with fixed %-range and unknown initial value
m_min = 0;
m_max = 100;
m_value = ( m_max - m_min ) / 2.0; // midpoint
m_minText->Disable();
m_maxText->Disable();
m_saveBtn->Disable(); // not an instance parameter that could be updated (invalid m_fieldId)
}
else else
m_fieldId = aSymbol->GetField( VALUE_FIELD )->GetId(); {
// instance parameter
if( aSymbol->FindField( NETLIST_EXPORTER_PSPICE::GetSpiceFieldName( SF_MODEL ) ) )
m_fieldId = aSymbol->FindField( NETLIST_EXPORTER_PSPICE::GetSpiceFieldName( SF_MODEL ) )->GetId();
else
m_fieldId = aSymbol->GetField( VALUE_FIELD )->GetId();
m_value = SPICE_VALUE( aSymbol->GetFieldById( m_fieldId )->GetText() ); m_value = SPICE_VALUE( aSymbol->GetFieldById( m_fieldId )->GetText() );
m_spiceName = aFrame->GetExporter()->GetSpiceDevice( compName ).Lower(); m_min = SPICE_VALUE( 0.5 ) * m_value;
m_max = SPICE_VALUE( 2.0 ) * m_value;
}
// Call Set*() methods to update fields and slider // Call Set*() methods to update fields and slider
m_max = SPICE_VALUE( 2.0 ) * m_value;
m_min = SPICE_VALUE( 0.5 ) * m_value;
m_minText->SetValue( m_min.ToOrigString() ); m_minText->SetValue( m_min.ToOrigString() );
m_maxText->SetValue( m_max.ToOrigString() ); m_maxText->SetValue( m_max.ToOrigString() );

View File

@ -49,9 +49,9 @@ public:
return m_name->GetLabel(); return m_name->GetLabel();
} }
const wxString& GetSpiceName() const const std::pair<wxString, bool>& GetSpiceTuningCommand() const
{ {
return m_spiceName; return m_spiceTuningCommand;
} }
const SPICE_VALUE& GetValue() const const SPICE_VALUE& GetValue() const
@ -96,7 +96,7 @@ private:
void onSimTimer( wxTimerEvent& event ); void onSimTimer( wxTimerEvent& event );
wxString m_spiceName; std::pair<wxString, bool> m_spiceTuningCommand;
///< Timer that restarts the simulation after the slider value has changed ///< Timer that restarts the simulation after the slider value has changed
wxTimer m_simTimer; wxTimer m_simTimer;