ADDED noise simulation GUI.

This commit is contained in:
Jeff Young 2023-07-03 15:45:58 +01:00
parent b5e420c33c
commit 80340c607c
10 changed files with 340 additions and 364 deletions

View File

@ -57,8 +57,8 @@ static wxString getStringSelection( const wxChoice* aCtrl )
DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( wxWindow* aParent,
std::shared_ptr<NGSPICE_CIRCUIT_MODEL> aCircuitModel,
std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& aSettings ) :
std::shared_ptr<NGSPICE_CIRCUIT_MODEL> aCircuitModel,
std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& aSettings ) :
DIALOG_SIM_COMMAND_BASE( aParent ),
m_circuitModel( aCircuitModel ),
m_settings( aSettings ),
@ -87,12 +87,32 @@ DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( wxWindow* aParent,
m_transInitial->SetValidator( m_spiceEmptyValidator );
m_transMaxStep->SetValidator( m_spiceEmptyValidator );
wxChar type1 = getStringSelection( m_dcSourceType1 ).Upper().GetChar( 0 );
updateDCSources( type1, m_dcSource1 );
wxChar type2 = getStringSelection( m_dcSourceType2 ).Upper().GetChar( 0 );
updateDCSources( type2, m_dcSource2 );
// NoiseRef is optional
m_noiseRef->Append( wxEmptyString );
for( const std::string& net : m_circuitModel->GetNets() )
{
m_noiseMeas->Append( net );
m_noiseRef->Append( net );
}
for( const SPICE_ITEM& item : m_circuitModel->GetItems() )
{
if( item.model->GetDeviceType() == SIM_MODEL::DEVICE_T::V )
m_noiseSrc->Append( item.refName );
}
refreshUIControls();
// Hide pages that aren't fully implemented yet
// wxPanel::Hide() isn't enough on some platforms
m_simPages->RemovePage( m_simPages->FindPage( m_pgDistortion ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgNoise ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgPoleZero ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgSensitivity ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgTransferFunction ) );
@ -104,7 +124,7 @@ DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( wxWindow* aParent,
}
wxString DIALOG_SIM_COMMAND::evaluateDCControls( wxChoice* aDcSource, wxTextCtrl* aDcStart,
wxTextCtrl* aDcStop, wxTextCtrl* aDcIncr )
wxTextCtrl* aDcStop, wxTextCtrl* aDcIncr )
{
wxString dcSource;
wxWindow* ctrlWithError = nullptr;
@ -114,11 +134,9 @@ wxString DIALOG_SIM_COMMAND::evaluateDCControls( wxChoice* aDcSource, wxTextCtrl
if( dcSource.IsEmpty() )
{
DisplayError( this, _( "You need to select DC source" ) );
DisplayError( this, _( "A DC source must be specified." ) );
ctrlWithError = aDcSource;
}
/// @todo for some reason it does not trigger the assigned SPICE_VALIDATOR,
// hence try..catch below
else if( !aDcStart->Validate() )
ctrlWithError = aDcStart;
else if( !aDcStop->Validate() )
@ -132,31 +150,14 @@ wxString DIALOG_SIM_COMMAND::evaluateDCControls( wxChoice* aDcSource, wxTextCtrl
return wxEmptyString;
}
try
{
// pick device name from exporter when something different than temperature is selected
if( dcSource.Cmp( "TEMP" ) )
dcSource = m_circuitModel->GetItemName( std::string( dcSource.ToUTF8() ) );
// pick device name from exporter when something different than temperature is selected
if( dcSource.Cmp( "TEMP" ) )
dcSource = m_circuitModel->GetItemName( std::string( dcSource.ToUTF8() ) );
return wxString::Format( "%s %s %s %s", dcSource,
SPICE_VALUE( aDcStart->GetValue() ).ToSpiceString(),
SPICE_VALUE( aDcStop->GetValue() ).ToSpiceString(),
SPICE_VALUE( aDcIncr->GetValue() ).ToSpiceString() );
}
catch( std::exception& e )
{
DisplayError( this, e.what() );
return wxEmptyString;
}
catch( const KI_PARAM_ERROR& e )
{
DisplayError( this, e.What() );
return wxEmptyString;
}
catch( ... )
{
return wxEmptyString;
}
return wxString::Format( "%s %s %s %s", dcSource,
SPICE_VALUE( aDcStart->GetValue() ).ToSpiceString(),
SPICE_VALUE( aDcStop->GetValue() ).ToSpiceString(),
SPICE_VALUE( aDcIncr->GetValue() ).ToSpiceString() );
}
@ -218,7 +219,7 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
if( m_dcSource1->GetStringSelection() == m_dcSource2->GetStringSelection() )
{
DisplayError( this, _( "Source 1 and Source 2 must be different" ) );
DisplayError( this, _( "Source 1 and Source 2 must be different." ) );
return false;
}
}
@ -227,31 +228,27 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
}
else if( page == m_pgNoise ) // Noise analysis
{
/*const std::map<wxString, int>& netMap = m_circuitModel->GetNetIndexMap();
wxString output = m_noiseMeas->GetStringSelection();
wxString ref = m_noiseRef->GetStringSelection();
wxString noiseSource = m_noiseSrc->GetStringSelection();
if( empty( m_noiseMeas ) || empty( m_noiseSrc ) || empty( m_noisePointsNumber )
|| empty( m_noiseFreqStart ) || empty( m_noiseFreqStop ) )
if( m_noiseFreqStart->IsEmpty() || m_noiseFreqStop->IsEmpty() )
{
DisplayError( this, _( "A frequency range must be specified." ) );
return false;
}
wxString ref;
if( !ref.IsEmpty() )
ref = wxS( "," ) + m_circuitModel->GetItemName( std::string( ref.ToUTF8() ) );
if( !empty( m_noiseRef ) )
ref = wxString::Format( ", %d", netMap.at( m_noiseRef->GetValue() ) );
wxString noiseSource = m_circuitModel->GetSpiceDevice( m_noiseSrc->GetValue() );
// Add voltage source prefix if needed
if( noiseSource[0] != 'v' && noiseSource[0] != 'V' )
noiseSource += 'v' + noiseSource;
m_simCommand.Printf( ".noise v(%d%s) %s %s %s %s %s",
netMap.at( m_noiseMeas->GetValue() ), ref,
noiseSource, scaleToString( m_noiseScale->GetSelection() ),
m_simCommand.Printf( ".noise v(%s%s) %s %s %s %s %s",
output,
ref,
noiseSource,
scaleToString( m_noiseScale->GetSelection() ),
m_noisePointsNumber->GetValue(),
SPICE_VALUE( m_noiseFreqStart->GetValue() ).ToSpiceString(),
SPICE_VALUE( m_noiseFreqStop->GetValue() ).ToSpiceString() );*/
SPICE_VALUE( m_noiseFreqStop->GetValue() ).ToSpiceString() );
}
else if( page == m_pgOP ) // DC operating point analysis
{
@ -277,7 +274,9 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
optionals = wxS( "uic" );
if( !empty( m_transMaxStep ) )
{
optionals = SPICE_VALUE( m_transMaxStep->GetValue() ).ToSpiceString() + spc + optionals;
}
else if( !optionals.IsEmpty() )
{
SPICE_VALUE maxStep = ( finalTime - startTime ) / 50.0;
@ -359,56 +358,13 @@ bool DIALOG_SIM_COMMAND::TransferDataToWindow()
}
}
if( !m_dcSource1->GetCount() )
{
wxChar type1 = getStringSelection( m_dcSourceType1 ).Upper().GetChar( 0 );
updateDCSources( type1, m_dcSource1 );
}
if( !m_dcSource2->GetCount() )
{
wxChar type2 = getStringSelection( m_dcSourceType2 ).Upper().GetChar( 0 );
updateDCSources( type2, m_dcSource2 );
}
if( m_simCommand.IsEmpty() && !empty( m_customTxt ) )
return parseCommand( m_customTxt->GetValue() );
parseCommand( m_customTxt->GetValue() );
return true;
}
int DIALOG_SIM_COMMAND::ShowModal()
{
// Fill out comboboxes that allows one to select nets
// Map comoboxes to their current values
std::map<wxComboBox*, wxString> cmbNet = {
{ m_noiseMeas, m_noiseMeas->GetStringSelection() },
{ m_noiseRef, m_noiseRef->GetStringSelection() }
};
for( const std::pair<wxComboBox* const, wxString>& c : cmbNet )
c.first->Clear();
for( const std::string& net : m_circuitModel->GetNets() )
{
for( const std::pair<wxComboBox* const, wxString>& c : cmbNet )
c.first->Append( net );
}
// Try to restore the previous selection, if possible
for( const std::pair<wxComboBox* const, wxString>& c : cmbNet )
{
int idx = c.first->FindString( c.second );
if( idx != wxNOT_FOUND )
c.first->SetSelection( idx );
}
return DIALOG_SIM_COMMAND_BASE::ShowModal();
}
void DIALOG_SIM_COMMAND::updateDCSources( wxChar aType, wxChoice* aSource )
{
wxString prevSelection;
@ -453,117 +409,137 @@ void DIALOG_SIM_COMMAND::updateDCSources( wxChar aType, wxChoice* aSource )
}
bool DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
void DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
{
if( aCommand.IsEmpty() )
return false;
return;
wxStringTokenizer tokenizer( aCommand, " " );
wxString tkn = tokenizer.GetNextToken().Lower();
wxString token = tokenizer.GetNextToken().Lower();
try
if( token == ".ac" )
{
if( tkn == ".ac" )
m_simPages->SetSelection( m_simPages->FindPage( m_pgAC ) );
token = tokenizer.GetNextToken().Lower();
for( SCALE_TYPE candidate : { DECADE, OCTAVE, LINEAR } )
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgAC ) );
tkn = tokenizer.GetNextToken().Lower();
if( tkn == "dec" )
m_acScale->SetSelection( 0 );
else if( tkn == "oct" )
m_acScale->SetSelection( 1 );
else if( tkn == "lin" )
m_acScale->SetSelection( 2 );
else
return false;
// If the fields below are empty, it will be caught by the exception handler
m_acPointsNumber->SetValue( tokenizer.GetNextToken() );
m_acFreqStart->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
m_acFreqStop->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
}
else if( tkn == ".dc" )
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgDC ) );
SPICE_DC_PARAMS src1, src2;
src2.m_vincrement = SPICE_VALUE( -1 );
if( !m_circuitModel->ParseDCCommand( aCommand, &src1, &src2 ) )
return false;
if( src1.m_source.IsSameAs( wxT( "TEMP" ), false ) )
setStringSelection( m_dcSourceType1, wxT( "TEMP" ) );
else
setStringSelection( m_dcSourceType1, src1.m_source.GetChar( 0 ) );
updateDCSources( src1.m_source.GetChar( 0 ), m_dcSource1 );
m_dcSource1->SetStringSelection( src1.m_source );
m_dcStart1->SetValue( src1.m_vstart.ToSpiceString() );
m_dcStop1->SetValue( src1.m_vend.ToSpiceString() );
m_dcIncr1->SetValue( src1.m_vincrement.ToSpiceString() );
if( src2.m_vincrement.ToDouble() != -1 )
if( scaleToString( candidate ) == token )
{
if( src2.m_source.IsSameAs( wxT( "TEMP" ), false ) )
setStringSelection( m_dcSourceType2, wxT( "TEMP" ) );
else
setStringSelection( m_dcSourceType2, src2.m_source.GetChar( 0 ) );
updateDCSources( src2.m_source.GetChar( 0 ), m_dcSource2 );
m_dcSource2->SetStringSelection( src2.m_source );
m_dcStart2->SetValue( src2.m_vstart.ToSpiceString() );
m_dcStop2->SetValue( src2.m_vend.ToSpiceString() );
m_dcIncr2->SetValue( src2.m_vincrement.ToSpiceString() );
m_dcEnable2->SetValue( true );
m_acScale->SetSelection( candidate );
break;
}
refreshUIControls();
}
else if( tkn == ".tran" )
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgTransient ) );
// If the fields below are empty, it will be caught by the exception handler
m_transStep->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
m_transFinal->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
// Initial time is an optional field
tkn = tokenizer.GetNextToken();
if( !tkn.IsEmpty() )
m_transInitial->SetValue( SPICE_VALUE( tkn ).ToSpiceString() );
// Max step is an optional field
tkn = tokenizer.GetNextToken();
if( !tkn.IsEmpty() )
m_transMaxStep->SetValue( SPICE_VALUE( tkn ).ToSpiceString() );
// uic is an optional field
tkn = tokenizer.GetNextToken();
if( tkn.IsSameAs( wxS( "uic" ) ) )
m_useInitialConditions->SetValue( true );
}
else if( tkn == ".op" )
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgOP ) );
}
else if( !empty( m_customTxt ) ) // Custom directives
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgCustom ) );
}
m_acPointsNumber->SetValue( tokenizer.GetNextToken() );
m_acFreqStart->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
m_acFreqStop->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
}
catch( ... )
else if( token == ".dc" )
{
// Nothing really bad has happened
return false;
}
m_simPages->SetSelection( m_simPages->FindPage( m_pgDC ) );
return true;
SPICE_DC_PARAMS src1, src2;
src2.m_vincrement = SPICE_VALUE( -1 );
m_circuitModel->ParseDCCommand( aCommand, &src1, &src2 );
if( src1.m_source.IsSameAs( wxT( "TEMP" ), false ) )
setStringSelection( m_dcSourceType1, wxT( "TEMP" ) );
else
setStringSelection( m_dcSourceType1, src1.m_source.GetChar( 0 ) );
updateDCSources( src1.m_source.GetChar( 0 ), m_dcSource1 );
m_dcSource1->SetStringSelection( src1.m_source );
m_dcStart1->SetValue( src1.m_vstart.ToSpiceString() );
m_dcStop1->SetValue( src1.m_vend.ToSpiceString() );
m_dcIncr1->SetValue( src1.m_vincrement.ToSpiceString() );
if( src2.m_vincrement.ToDouble() != -1 )
{
if( src2.m_source.IsSameAs( wxT( "TEMP" ), false ) )
setStringSelection( m_dcSourceType2, wxT( "TEMP" ) );
else
setStringSelection( m_dcSourceType2, src2.m_source.GetChar( 0 ) );
updateDCSources( src2.m_source.GetChar( 0 ), m_dcSource2 );
m_dcSource2->SetStringSelection( src2.m_source );
m_dcStart2->SetValue( src2.m_vstart.ToSpiceString() );
m_dcStop2->SetValue( src2.m_vend.ToSpiceString() );
m_dcIncr2->SetValue( src2.m_vincrement.ToSpiceString() );
m_dcEnable2->SetValue( true );
}
refreshUIControls();
}
else if( token == ".noise" )
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgNoise ) );
wxString output;
wxString ref;
wxString source;
wxString scale;
SPICE_VALUE pts;
SPICE_VALUE fStart;
SPICE_VALUE fStop;
m_circuitModel->ParseNoiseCommand( aCommand, &output, &ref, &source, &scale, &pts,
&fStart, &fStop );
m_noiseMeas->SetStringSelection( output );
m_noiseRef->SetStringSelection( ref );
m_noiseSrc->SetStringSelection( source );
for( SCALE_TYPE candidate : { DECADE, OCTAVE, LINEAR } )
{
if( scaleToString( candidate ) == scale )
{
m_noiseScale->SetSelection( candidate );
break;
}
}
m_noisePointsNumber->SetValue( pts.ToSpiceString() );
m_noiseFreqStart->SetValue( fStart.ToSpiceString() );
m_noiseFreqStop->SetValue( fStop.ToSpiceString() );
}
else if( token == ".tran" )
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgTransient ) );
// If the fields below are empty, it will be caught by the exception handler
m_transStep->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
m_transFinal->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
// Initial time is an optional field
token = tokenizer.GetNextToken();
if( !token.IsEmpty() )
m_transInitial->SetValue( SPICE_VALUE( token ).ToSpiceString() );
// Max step is an optional field
token = tokenizer.GetNextToken();
if( !token.IsEmpty() )
m_transMaxStep->SetValue( SPICE_VALUE( token ).ToSpiceString() );
// uic is an optional field
token = tokenizer.GetNextToken();
if( token.IsSameAs( wxS( "uic" ) ) )
m_useInitialConditions->SetValue( true );
}
else if( token == ".op" )
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgOP ) );
}
else if( !empty( m_customTxt ) ) // Custom directives
{
m_simPages->SetSelection( m_simPages->FindPage( m_pgCustom ) );
}
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2022 CERN
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
@ -48,14 +48,10 @@ public:
return m_simCommand;
}
bool SetSimCommand( const wxString& aCommand )
void SetSimCommand( const wxString& aCommand )
{
bool res = parseCommand( aCommand );
if( res )
m_simCommand = aCommand;
return res;
parseCommand( aCommand );
m_simCommand = aCommand;
}
int GetSimOptions() const
@ -97,8 +93,6 @@ public:
return true;
}
int ShowModal() override;
private:
enum SCALE_TYPE
{
@ -147,9 +141,8 @@ private:
* Parse a Spice directive.
*
* @param aCommand is the directive to be parsed (e.g. ".tran 10n 1000n").
* @return true if the directive was parsed correctly.
*/
bool parseCommand( const wxString& aCommand );
void parseCommand( const wxString& aCommand );
void onLoadDirectives( wxCommandEvent& event ) override
{

View File

@ -69,10 +69,7 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer1->Add( m_staticText110, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
bSizer3->Add( fgSizer1, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );
bSizer3->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer3->Add( fgSizer1, 0, wxEXPAND|wxALL, 5 );
m_pgAC->SetSizer( bSizer3 );
@ -194,15 +191,15 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
gbSizer1->Add( m_src2DCStepUnit, wxGBPosition( 5, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
bSizer82->Add( gbSizer1, 0, wxTOP|wxBOTTOM, 5 );
bSizer82->Add( gbSizer1, 0, wxALL, 5 );
bSizer82->Add( 0, 5, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );
bSizer82->Add( 0, 10, 0, wxEXPAND, 5 );
m_swapDCSources = new wxButton( m_pgDC, wxID_ANY, _("Swap sources"), wxDefaultPosition, wxDefaultSize, 0 );
m_swapDCSources->SetMinSize( wxSize( 132,-1 ) );
bSizer82->Add( m_swapDCSources, 0, wxALL, 5 );
bSizer82->Add( m_swapDCSources, 0, wxALL, 10 );
m_pgDC->SetSizer( bSizer82 );
@ -212,25 +209,22 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
m_pgDistortion = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_simPages->AddPage( m_pgDistortion, _("Distortion"), false );
m_pgNoise = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_pgNoise->Hide();
wxBoxSizer* bSizer15;
bSizer15 = new wxBoxSizer( wxVERTICAL );
bSizer15->Add( 0, 0, 1, wxEXPAND, 5 );
wxFlexGridSizer* fgSizer7;
fgSizer7 = new wxFlexGridSizer( 0, 3, 2, 0 );
fgSizer7 = new wxFlexGridSizer( 0, 3, 5, 0 );
fgSizer7->SetFlexibleDirection( wxBOTH );
fgSizer7->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText14 = new wxStaticText( m_pgNoise, wxID_ANY, _("Measured node:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText14->Wrap( -1 );
fgSizer7->Add( m_staticText14, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5 );
fgSizer7->Add( m_staticText14, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_noiseMeas = new wxComboBox( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
fgSizer7->Add( m_noiseMeas, 1, wxTOP|wxALIGN_CENTER_VERTICAL, 5 );
wxArrayString m_noiseMeasChoices;
m_noiseMeas = new wxChoice( m_pgNoise, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseMeasChoices, 0 );
m_noiseMeas->SetSelection( 0 );
fgSizer7->Add( m_noiseMeas, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 );
fgSizer7->Add( 0, 0, 1, wxEXPAND, 5 );
@ -239,8 +233,10 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
m_staticText15->Wrap( -1 );
fgSizer7->Add( m_staticText15, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_noiseRef = new wxComboBox( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
fgSizer7->Add( m_noiseRef, 1, wxALIGN_CENTER_VERTICAL, 5 );
wxArrayString m_noiseRefChoices;
m_noiseRef = new wxChoice( m_pgNoise, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseRefChoices, 0 );
m_noiseRef->SetSelection( 0 );
fgSizer7->Add( m_noiseRef, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 );
m_staticText23 = new wxStaticText( m_pgNoise, wxID_ANY, _("(optional; default GND)"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText23->Wrap( -1 );
@ -248,19 +244,18 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
m_staticText16 = new wxStaticText( m_pgNoise, wxID_ANY, _("Noise source:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText16->Wrap( -1 );
fgSizer7->Add( m_staticText16, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
fgSizer7->Add( m_staticText16, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_noiseSrc = new wxComboBox( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
fgSizer7->Add( m_noiseSrc, 1, wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 );
wxArrayString m_noiseSrcChoices;
m_noiseSrc = new wxChoice( m_pgNoise, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseSrcChoices, 0 );
m_noiseSrc->SetSelection( 0 );
fgSizer7->Add( m_noiseSrc, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 );
fgSizer7->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer15->Add( fgSizer7, 0, 0, 5 );
bSizer15->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer15->Add( fgSizer7, 0, wxALL, 5 );
wxBoxSizer* bSizer10;
bSizer10 = new wxBoxSizer( wxHORIZONTAL );
@ -284,6 +279,8 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer11->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5 );
m_noisePointsNumber = new wxTextCtrl( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_noisePointsNumber->SetMinSize( wxSize( 80,-1 ) );
fgSizer11->Add( m_noisePointsNumber, 1, wxALIGN_CENTER_VERTICAL|wxTOP, 5 );
@ -294,6 +291,8 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer11->Add( m_staticText21, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_noiseFreqStart = new wxTextCtrl( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_noiseFreqStart->SetMinSize( wxSize( 80,-1 ) );
fgSizer11->Add( m_noiseFreqStart, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_noiseFreqStartUnits = new wxStaticText( m_pgNoise, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
@ -305,6 +304,8 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer11->Add( m_staticText31, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_noiseFreqStop = new wxTextCtrl( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_noiseFreqStop->SetMinSize( wxSize( 80,-1 ) );
fgSizer11->Add( m_noiseFreqStop, 1, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
m_noiseFreqStopUnits = new wxStaticText( m_pgNoise, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
@ -315,19 +316,13 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
bSizer10->Add( fgSizer11, 0, wxALIGN_BOTTOM|wxBOTTOM|wxLEFT, 4 );
bSizer15->Add( bSizer10, 0, wxEXPAND, 5 );
bSizer15->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer15->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer15->Add( bSizer10, 0, wxEXPAND|wxTOP, 5 );
m_pgNoise->SetSizer( bSizer15 );
m_pgNoise->Layout();
bSizer15->Fit( m_pgNoise );
m_simPages->AddPage( m_pgNoise, _("Noise"), false );
m_simPages->AddPage( m_pgNoise, _("Noise"), true );
m_pgOP = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer8;
bSizer8 = new wxBoxSizer( wxVERTICAL );
@ -430,13 +425,13 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
gbSizer2->Add( m_useInitialConditionsHelp, wxGBPosition( 4, 3 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizer81->Add( gbSizer2, 1, wxEXPAND, 5 );
bSizer81->Add( gbSizer2, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_pgTransient->SetSizer( bSizer81 );
m_pgTransient->Layout();
bSizer81->Fit( m_pgTransient );
m_simPages->AddPage( m_pgTransient, _("Transient"), true );
m_simPages->AddPage( m_pgTransient, _("Transient"), false );
m_pgCustom = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );

View File

@ -247,7 +247,7 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">0</property>
<object class="wxFlexGridSizer" expanded="1">
<property name="cols">3</property>
@ -770,16 +770,6 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
</object>
</object>
</object>
@ -845,7 +835,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxGridBagSizer" expanded="1">
<property name="empty_cell_size"></property>
@ -2370,16 +2360,16 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">5</property>
<property name="height">10</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="border">10</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
@ -2515,7 +2505,7 @@
<object class="notebookpage" expanded="1">
<property name="bitmap"></property>
<property name="label">Noise</property>
<property name="select">0</property>
<property name="select">1</property>
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -2542,7 +2532,7 @@
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">1</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
@ -2572,19 +2562,9 @@
<property name="name">bSizer15</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag"></property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxFlexGridSizer" expanded="1">
<property name="cols">3</property>
@ -2597,10 +2577,10 @@
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="rows">0</property>
<property name="vgap">2</property>
<property name="vgap">5</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
@ -2659,11 +2639,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxTOP|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">1</property>
<object class="wxComboBox" expanded="0">
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -2707,18 +2687,17 @@
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="selection">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
@ -2795,11 +2774,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">1</property>
<object class="wxComboBox" expanded="0">
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -2843,18 +2822,17 @@
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="selection">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
@ -2923,7 +2901,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
@ -2982,11 +2960,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">1</property>
<object class="wxComboBox" expanded="0">
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -3030,18 +3008,17 @@
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="selection">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
@ -3059,19 +3036,9 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="flag">wxEXPAND|wxTOP</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
@ -3269,7 +3236,7 @@
<property name="maxlength">0</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="minimum_size">80,-1</property>
<property name="moveable">1</property>
<property name="name">m_noisePointsNumber</property>
<property name="pane_border">1</property>
@ -3404,7 +3371,7 @@
<property name="maxlength">0</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="minimum_size">80,-1</property>
<property name="moveable">1</property>
<property name="name">m_noiseFreqStart</property>
<property name="pane_border">1</property>
@ -3590,7 +3557,7 @@
<property name="maxlength">0</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="minimum_size">80,-1</property>
<property name="moveable">1</property>
<property name="name">m_noiseFreqStop</property>
<property name="pane_border">1</property>
@ -3681,26 +3648,6 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
</object>
</object>
</object>
@ -4022,7 +3969,7 @@
<object class="notebookpage" expanded="1">
<property name="bitmap"></property>
<property name="label">Transient</property>
<property name="select">1</property>
<property name="select">0</property>
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -4081,7 +4028,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT</property>
<property name="proportion">1</property>
<object class="wxGridBagSizer" expanded="1">
<property name="empty_cell_size"></property>

View File

@ -29,7 +29,6 @@
#include <wx/choice.h>
#include <wx/gbsizer.h>
#include <wx/button.h>
#include <wx/combobox.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
@ -83,12 +82,12 @@ class DIALOG_SIM_COMMAND_BASE : public DIALOG_SHIM
wxPanel* m_pgDistortion;
wxPanel* m_pgNoise;
wxStaticText* m_staticText14;
wxComboBox* m_noiseMeas;
wxChoice* m_noiseMeas;
wxStaticText* m_staticText15;
wxComboBox* m_noiseRef;
wxChoice* m_noiseRef;
wxStaticText* m_staticText23;
wxStaticText* m_staticText16;
wxComboBox* m_noiseSrc;
wxChoice* m_noiseSrc;
wxRadioBox* m_noiseScale;
wxStaticText* m_staticText11;
wxTextCtrl* m_noisePointsNumber;

View File

@ -130,24 +130,75 @@ bool NGSPICE_CIRCUIT_MODEL::ParseDCCommand( const wxString& aCmd, SPICE_DC_PARAM
wxString cmd = aCmd.Mid( 3 );
wxStringTokenizer tokens( cmd, wxS( " \t" ), wxTOKEN_STRTOK );
size_t num = tokens.CountTokens();
if( num != 4 && num != 8 )
return false;
aSource1->m_source = tokens.GetNextToken();
aSource1->m_vstart = SPICE_VALUE( tokens.GetNextToken() );
aSource1->m_vend = SPICE_VALUE( tokens.GetNextToken() );
aSource1->m_vincrement = SPICE_VALUE( tokens.GetNextToken() );
if( num == 8 )
aSource2->m_source = tokens.GetNextToken();
aSource2->m_vstart = SPICE_VALUE( tokens.GetNextToken() );
aSource2->m_vend = SPICE_VALUE( tokens.GetNextToken() );
aSource2->m_vincrement = SPICE_VALUE( tokens.GetNextToken() );
return true;
}
bool NGSPICE_CIRCUIT_MODEL::ParseNoiseCommand( const wxString& aCmd, wxString* aOutput,
wxString* aRef, wxString* aSource, wxString* aScale,
SPICE_VALUE* aPts, SPICE_VALUE* aFStart,
SPICE_VALUE* aFStop )
{
if( !aCmd.Lower().StartsWith( wxS( ".noise" ) ) )
return false;
wxString cmd = aCmd.Mid( 6 );
cmd.Trim( false );
if( !cmd.Lower().StartsWith( wxS( "v(" ) ) )
return false;
cmd = cmd.Mid( 2 );
wxString function = cmd.Before( ')' );
wxString params = cmd.After( ')' );
wxStringTokenizer func_tokens( function, wxS( " ,\t" ), wxTOKEN_STRTOK );
*aOutput = func_tokens.GetNextToken();
*aRef = func_tokens.GetNextToken();
wxStringTokenizer tokens( params, wxS( " \t" ), wxTOKEN_STRTOK );
wxString token = tokens.GetNextToken();
if( !token.IsEmpty() )
{
aSource2->m_source = tokens.GetNextToken();
aSource2->m_vstart = SPICE_VALUE( tokens.GetNextToken() );
aSource2->m_vend = SPICE_VALUE( tokens.GetNextToken() );
aSource2->m_vincrement = SPICE_VALUE( tokens.GetNextToken() );
*aSource = token;
token = tokens.GetNextToken();
}
if( token.Lower() == "dec" || token.Lower() == "oct" || token.Lower() == "lin" )
{
*aScale = token;
token = tokens.GetNextToken();
}
if( !token.IsEmpty() )
{
*aPts = token;
token = tokens.GetNextToken();
}
if( !token.IsEmpty() )
{
*aFStart = SPICE_VALUE( token );
token = tokens.GetNextToken();
}
if( !token.IsEmpty() )
*aFStop = SPICE_VALUE( token );
return true;
}

View File

@ -127,6 +127,10 @@ public:
bool ParseDCCommand( const wxString& aCmd, SPICE_DC_PARAMS* aSource1,
SPICE_DC_PARAMS* aSource2 );
bool ParseNoiseCommand( const wxString& aCmd, wxString* aOutput, wxString* aRef,
wxString* aSource, wxString* aScale, SPICE_VALUE* aPts,
SPICE_VALUE* aFStart, SPICE_VALUE* aFStop );
/**
* Determine if a directive is a simulation command.
*/

View File

@ -1351,8 +1351,17 @@ bool SIM_MODEL::InferSimModel( T_symbol& aSymbol, std::vector<T_field>* aFields,
{
if( aModelParams->IsEmpty() && !value.IsEmpty() )
{
wxString param = "dc";
if( value.StartsWith( wxT( "DC " ) ) )
{
value = value.Right( value.Length() - 3 );
}
else if( value.StartsWith( wxT( "AC " ) ) )
{
value = value.Right( value.Length() - 3 );
param = "ac";
}
wxRegEx sourceVal( wxT( "^"
"([0-9\\,\\. ]+)"
@ -1373,13 +1382,15 @@ bool SIM_MODEL::InferSimModel( T_symbol& aSymbol, std::vector<T_field>* aFields,
if( valueMantissa.Contains( wxT( "." ) ) || valueFraction.IsEmpty() )
{
aModelParams->Printf( wxT( "dc=\"%s%s\"" ),
aModelParams->Printf( wxT( "%s=\"%s%s\"" ),
param,
valueMantissa,
convertNotation( valueExponent ) );
}
else
{
aModelParams->Printf( wxT( "dc=\"%s.%s%s\"" ),
aModelParams->Printf( wxT( "%s=\"%s.%s%s\"" ),
param,
valueMantissa,
valueFraction,
convertNotation( valueExponent ) );
@ -1387,7 +1398,7 @@ bool SIM_MODEL::InferSimModel( T_symbol& aSymbol, std::vector<T_field>* aFields,
}
else
{
aModelParams->Printf( wxT( "dc=\"%s\"" ), value );
aModelParams->Printf( wxT( "%s=\"%s\"" ), param, value );
}
}
@ -1719,16 +1730,20 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
pinMapInfo.m_Text = generateDefaultPinMapFromSymbol( sourcePins );
}
}
else if( ( spiceDeviceType == "R" || spiceDeviceType == "L" || spiceDeviceType == "C" )
else if( ( spiceDeviceType == wxS( "R" )
|| spiceDeviceType == wxS( "L" )
|| spiceDeviceType == wxS( "C" )
|| spiceDeviceType == wxS( "V" )
|| spiceDeviceType == wxS( "I" ) )
&& prefix.StartsWith( spiceDeviceType )
&& modelFromValueField )
{
inferredModel = true;
}
else
else if( spiceDeviceType == wxS( "V" ) || spiceDeviceType == wxS( "I" ) )
{
// See if we have a SPICE model such as "sin(0 1 60)" or "sin 0 1 60" that can be handled
// by a built-in SIM_MODEL.
// See if we have a SPICE time-dependent function such as "sin(0 1 60)" or "sin 0 1 60"
// that can be handled by a built-in SIM_MODEL_SOURCE.
wxStringTokenizer tokenizer( spiceModel, wxT( "() " ), wxTOKEN_STRTOK );

View File

@ -252,7 +252,7 @@ bool SIM_MODEL_SERIALIZER::ParseParams( const std::string& aParams )
}
}
return !m_model.HasPrimaryValue() || isPrimaryValueSet;
return !m_model.HasPrimaryValue() || m_model.HasAutofill() || isPrimaryValueSet;
}

View File

@ -34,7 +34,6 @@
#include <wx/numformatter.h>
#include <confirm.h>
#include <common.h>
#include <ki_exception.h>
#include <locale_io.h>
@ -64,38 +63,37 @@ void SPICE_VALUE_FORMAT::UpdateUnits( const wxString& aUnits )
}
SPICE_VALUE::SPICE_VALUE( const wxString& aString )
SPICE_VALUE::SPICE_VALUE( const wxString& aString ) :
m_base( 0.0 ),
m_prefix( PFX_NONE ),
m_spiceStr( false )
{
char buf[8] = { 0, };
if( aString.IsEmpty() )
throw KI_PARAM_ERROR( _( "Spice value cannot be empty" ) );
return;
LOCALE_IO dummy; // All numeric values should be in "C" locale(decimal separator = .)
char units[8] = { 0, };
LOCALE_IO dummy; // Numeric values must be in "C" locale ('.' decimal separator)
if( sscanf( (const char*) aString.c_str(), "%lf%7s", &m_base, buf ) == 0 )
throw KI_PARAM_ERROR( _( "Invalid Spice value string" ) );
sscanf( (const char*) aString.c_str(), "%lf%7s", &m_base, units );
if( *buf == 0 )
if( *units == 0 )
{
m_prefix = PFX_NONE;
m_spiceStr = false;
Normalize();
return;
}
m_spiceStr = true;
for( char* bufPtr = buf; *bufPtr; ++bufPtr )
for( char* bufPtr = units; *bufPtr; ++bufPtr )
*bufPtr = tolower( *bufPtr );
if( !strcmp( buf, "meg" ) )
if( strcmp( units, "meg" ) == 0 )
{
m_prefix = PFX_MEGA;
}
else
{
switch( buf[0] )
switch( units[0] )
{
case 'f': m_prefix = PFX_FEMTO; break;
case 'p': m_prefix = PFX_PICO; break;
@ -105,9 +103,7 @@ SPICE_VALUE::SPICE_VALUE( const wxString& aString )
case 'k': m_prefix = PFX_KILO; break;
case 'g': m_prefix = PFX_GIGA; break;
case 't': m_prefix = PFX_TERA; break;
default:
throw KI_PARAM_ERROR( _( "Invalid unit prefix" ) );
default: m_prefix = PFX_NONE; break;
}
}