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 )
{
FILE_OUTPUTFORMATTER outputFile( aOutFileName, wxT( "wt" ), '\'' );

View File

@ -119,6 +119,16 @@ public:
*/
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
*/

View File

@ -539,11 +539,11 @@ void SIM_PLOT_FRAME::AddTuner( SCH_SYMBOL* aSymbol )
if( !plotPanel )
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];
if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR
&& primitiveType != SP_INDUCTOR )
&& primitiveType != SP_INDUCTOR && primitiveType != SP_CODEMODEL )
return;
const wxString componentName = aSymbol->GetField( REFERENCE_FIELD )->GetText();
@ -917,11 +917,15 @@ void SIM_PLOT_FRAME::applyTuners()
{
for( auto& tuner : m_tuners )
{
/// @todo no ngspice hard coding
std::string command( "alter @" + tuner->GetSpiceName()
+ "=" + tuner->GetValue().ToSpiceString() );
std::pair<wxString, bool> command = tuner->GetSpiceTuningCommand();
const SPICE_VALUE& value = tuner->GetValue();
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_BASE( aParent ),
m_symbol( aSymbol ),
m_fieldId( MANDATORY_FIELD_T::VALUE_FIELD ),
m_min( 0.0 ),
m_max( 0.0 ),
m_changed( false ),
m_value( 0.0 ),
m_frame ( aFrame )
{
const wxString compName = aSymbol->GetField( REFERENCE_FIELD )->GetText();
m_name->SetLabel( compName );
m_spiceTuningCommand = aFrame->GetExporter()->GetSpiceTuningCommand( compName );
if( aSymbol->FindField( NETLIST_EXPORTER_PSPICE::GetSpiceFieldName( SF_MODEL ) ) )
m_fieldId = aSymbol->FindField( NETLIST_EXPORTER_PSPICE::GetSpiceFieldName( SF_MODEL ) )->GetId();
if( m_spiceTuningCommand.second )
{
// 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
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_spiceName = aFrame->GetExporter()->GetSpiceDevice( compName ).Lower();
m_value = SPICE_VALUE( aSymbol->GetFieldById( m_fieldId )->GetText() );
m_min = SPICE_VALUE( 0.5 ) * m_value;
m_max = SPICE_VALUE( 2.0 ) * m_value;
}
// 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_maxText->SetValue( m_max.ToOrigString() );

View File

@ -49,9 +49,9 @@ public:
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
@ -96,7 +96,7 @@ private:
void onSimTimer( wxTimerEvent& event );
wxString m_spiceName;
std::pair<wxString, bool> m_spiceTuningCommand;
///< Timer that restarts the simulation after the slider value has changed
wxTimer m_simTimer;