Remove most of SIM_VALUE in favour of good old wxString.

This allows us to save the user's intent, including units, formatting,
and crucially variable references.

(cherry picked from commit 68fe146861)
This commit is contained in:
Jeff Young 2023-02-22 09:10:06 +00:00
parent db3657d411
commit 7f6cb9b07b
29 changed files with 320 additions and 669 deletions

View File

@ -568,7 +568,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelParamsTab( SIM_MODEL* aMode
// This feature is called "autofill" and present only in certain models. Don't do it for
// models that don't have it for performance reasons.
if( aModel->HasAutofill() )
( *it )->SetValueFromString( param.value->ToString() );
( *it )->SetValueFromString( param.value );
}
}

View File

@ -501,7 +501,7 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
if( auto rawSpiceModel = dynamic_cast<const SIM_MODEL_RAW_SPICE*>( aItem.model ) )
{
int libParamIndex = static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
wxString path = rawSpiceModel->GetParam( libParamIndex ).value->ToString();
wxString path = rawSpiceModel->GetParam( libParamIndex ).value;
if( !path.IsEmpty() )
m_rawIncludes.insert( path );

View File

@ -717,7 +717,7 @@ void SIM_MODEL::AddParam( const PARAM::INFO& aInfo )
// Enums are initialized with their default values.
if( aInfo.enumValues.size() >= 1 )
m_params.back().value->FromString( aInfo.defaultValue );
m_params.back().value = aInfo.defaultValue;
}
@ -790,7 +790,7 @@ void SIM_MODEL::SetPinSymbolPinNumber( const std::string& aPinName,
const SIM_MODEL::PARAM& SIM_MODEL::GetParam( unsigned aParamIndex ) const
{
if( m_baseModel && m_params.at( aParamIndex ).value->ToString() == "" )
if( m_baseModel && m_params.at( aParamIndex ).value == "" )
return m_baseModel->GetParam( aParamIndex );
else
return m_params.at( aParamIndex );
@ -847,17 +847,16 @@ const SIM_MODEL::PARAM& SIM_MODEL::GetBaseParam( unsigned aParamIndex ) const
}
void SIM_MODEL::SetParamValue( int aParamIndex, const SIM_VALUE& aValue )
void SIM_MODEL::doSetParamValue( int aParamIndex, const std::string& aValue )
{
*m_params.at( aParamIndex ).value = aValue;
m_params.at( aParamIndex ).value = aValue;
}
void SIM_MODEL::SetParamValue( int aParamIndex, const std::string& aValue,
SIM_VALUE::NOTATION aNotation )
{
const SIM_VALUE& value = *GetParam( aParamIndex ).value;
SetParamValue( aParamIndex, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) );
doSetParamValue( aParamIndex, SIM_VALUE::Normalize( aValue, aNotation ) );
}
@ -882,7 +881,7 @@ bool SIM_MODEL::HasOverrides() const
{
for( const PARAM& param : m_params )
{
if( param.value->ToString() != "" )
if( param.value != "" )
return true;
}
@ -894,7 +893,7 @@ bool SIM_MODEL::HasNonInstanceOverrides() const
{
for( const PARAM& param : m_params )
{
if( !param.info.isInstanceParam && param.value->ToString() != "" )
if( !param.info.isInstanceParam && param.value != "" )
return true;
}
@ -906,7 +905,7 @@ bool SIM_MODEL::HasSpiceNonInstanceOverrides() const
{
for( const PARAM& param : m_params )
{
if( !param.info.isSpiceInstanceParam && param.value->ToString() != "" )
if( !param.info.isSpiceInstanceParam && param.value != "" )
return true;
}

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 CERN
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -377,12 +377,11 @@ public:
}
};
std::unique_ptr<SIM_VALUE> value;
const INFO& info;
std::string value;
const INFO& info;
PARAM( const INFO& aInfo )
: value( SIM_VALUE::Create( aInfo.type ) ),
info( aInfo )
PARAM( const INFO& aInfo ) :
info( aInfo )
{}
};
@ -487,7 +486,6 @@ public:
const PARAM& GetBaseParam( unsigned aParamIndex ) const; // Always return base parameter if it exists.
virtual void SetParamValue( int aParamIndex, const SIM_VALUE& aValue );
void SetParamValue( int aParamIndex, const std::string& aValue,
SIM_VALUE::NOTATION aNotation = SIM_VALUE::NOTATION::SI );
void SetParamValue( const std::string& aParamName, const std::string& aValue,
@ -532,6 +530,7 @@ protected:
void createPins( const std::vector<LIB_PIN*>& aSymbolPins );
virtual int doFindParam( const std::string& aParamName ) const;
virtual void doSetParamValue( int aParamIndex, const std::string& aValue );
private:
template <typename T>

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -44,21 +44,21 @@ std::string SPICE_GENERATOR_BEHAVIORAL::ItemLine( const SPICE_ITEM& aItem ) cons
case SIM_MODEL::TYPE::L_BEHAVIORAL:
{
SPICE_ITEM item = aItem;
item.modelName = m_model.GetParam( 0 ).value->ToSpiceString();
item.modelName = SIM_VALUE::ToSpice( m_model.GetParam( 0 ).value );
return SPICE_GENERATOR::ItemLine( item );
}
case SIM_MODEL::TYPE::V_BEHAVIORAL:
{
SPICE_ITEM item = aItem;
item.modelName = fmt::format( "V={}", m_model.GetParam( 0 ).value->ToSpiceString() );
item.modelName = fmt::format( "V={}", SIM_VALUE::ToSpice( m_model.GetParam( 0 ).value ) );
return SPICE_GENERATOR::ItemLine( item );
}
case SIM_MODEL::TYPE::I_BEHAVIORAL:
{
SPICE_ITEM item = aItem;
item.modelName = fmt::format( "I={}", m_model.GetParam( 0 ).value->ToSpiceString() );
item.modelName = fmt::format( "I={}", SIM_VALUE::ToSpice( m_model.GetParam( 0 ).value ) );
return SPICE_GENERATOR::ItemLine( item );
}

View File

@ -37,7 +37,7 @@ std::string SPICE_GENERATOR_IDEAL::ModelLine( const SPICE_ITEM& aItem ) const
std::string SPICE_GENERATOR_IDEAL::ItemLine( const SPICE_ITEM& aItem ) const
{
SPICE_ITEM item = aItem;
item.modelName = m_model.GetParam( 0 ).value->ToString( SIM_VALUE::NOTATION::SPICE );
item.modelName = SIM_VALUE::ToSpice( m_model.GetParam( 0 ).value );
if( item.modelName != "" )
return SPICE_GENERATOR::ItemLine( item );
@ -46,12 +46,11 @@ std::string SPICE_GENERATOR_IDEAL::ItemLine( const SPICE_ITEM& aItem ) const
}
std::string SPICE_GENERATOR_IDEAL::TunerCommand( const SPICE_ITEM& aItem,
const SIM_VALUE_FLOAT& aValue ) const
std::string SPICE_GENERATOR_IDEAL::TunerCommand( const SPICE_ITEM& aItem, double aValue ) const
{
return fmt::format( "alter @{}={}",
return fmt::format( "alter @{}={:g}",
aItem.model->SpiceGenerator().ItemName( aItem ),
aValue.ToSpiceString() );
aValue );
}

View File

@ -37,7 +37,7 @@ public:
std::string ModelLine( const SPICE_ITEM& aItem ) const override;
std::string ItemLine( const SPICE_ITEM& aItem ) const override;
std::string TunerCommand( const SPICE_ITEM& aItem, const SIM_VALUE_FLOAT& aValue ) const override;
std::string TunerCommand( const SPICE_ITEM& aItem, double aValue ) const override;
};

View File

@ -111,18 +111,18 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PR
KIBIS_PARAMETER kparams;
if ( m_model.FindParam( "vcc" ) )
kparams.SetCornerFromString( kparams.m_supply, m_model.FindParam( "vcc" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_supply, m_model.FindParam( "vcc" )->value );
if ( m_model.FindParam( "rpin" ) )
kparams.SetCornerFromString( kparams.m_Rpin, m_model.FindParam( "rpin" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Rpin, m_model.FindParam( "rpin" )->value );
if ( m_model.FindParam( "lpin" ) )
kparams.SetCornerFromString( kparams.m_Lpin, m_model.FindParam( "lpin" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Lpin, m_model.FindParam( "lpin" )->value );
if ( m_model.FindParam( "cpin" ) )
kparams.SetCornerFromString( kparams.m_Cpin, m_model.FindParam( "cpin" )->value->ToString() );
kparams.SetCornerFromString( kparams.m_Cpin, m_model.FindParam( "cpin" )->value );
//kparams.SetCornerFromString( kparams.m_Ccomp, FindParam( "ccomp" )->value->ToString() );
//kparams.SetCornerFromString( kparams.m_Ccomp, FindParam( "ccomp" )->value );
std::string result;
@ -140,7 +140,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PR
std::string paramValue = "";
if ( m_model.FindParam( "dc" ) )
paramValue = m_model.FindParam( "dc" )->value->ToString();
paramValue = m_model.FindParam( "dc" )->value;
if( paramValue == "hi-Z" )
{
@ -167,16 +167,16 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PR
KIBIS_WAVEFORM_RECTANGULAR* waveform = new KIBIS_WAVEFORM_RECTANGULAR( &kibis );
if ( m_model.FindParam( "ton" ) )
waveform->m_ton = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "ton" )->value ).Get().value_or( 1 );
waveform->m_ton = SIM_VALUE::ToDouble( m_model.FindParam( "ton" )->value, 1 );
if ( m_model.FindParam( "toff" ) )
waveform->m_toff = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "toff" )->value ).Get().value_or( 1 );
waveform->m_toff = SIM_VALUE::ToDouble( m_model.FindParam( "toff" )->value, 1 );
if ( m_model.FindParam( "td" ) )
waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "td" )->value ).Get().value_or( 0 );
waveform->m_delay = SIM_VALUE::ToDouble( m_model.FindParam( "td" )->value, 0 );
if ( m_model.FindParam( "n" ) )
waveform->m_cycles = static_cast<SIM_VALUE_INT&>( *m_model.FindParam( "n" )->value ).Get().value_or( 1 );
waveform->m_cycles = SIM_VALUE::ToInt( m_model.FindParam( "n" )->value, 1 );
kparams.m_waveform = waveform;
@ -192,13 +192,13 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PR
KIBIS_WAVEFORM_PRBS* waveform = new KIBIS_WAVEFORM_PRBS( &kibis );
if ( m_model.FindParam( "f0" ) )
waveform->m_bitrate = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "f0" )->value ).Get().value_or( 0 );
waveform->m_bitrate = SIM_VALUE::ToDouble( m_model.FindParam( "f0" )->value, 0 );
if ( m_model.FindParam( "td" ) )
waveform->m_delay = static_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "td" )->value ).Get().value_or( 0 );
waveform->m_delay = SIM_VALUE::ToDouble( m_model.FindParam( "td" )->value, 0 );
if ( m_model.FindParam( "n" ) )
waveform->m_bits = static_cast<SIM_VALUE_INT&>( *m_model.FindParam( "n" )->value ).Get().value_or( 0 );
waveform->m_bits = SIM_VALUE::ToInt( m_model.FindParam( "n" )->value, 0 );
kparams.m_waveform = waveform;
@ -276,7 +276,7 @@ SIM_MODEL_KIBIS::SIM_MODEL_KIBIS( TYPE aType, const SIM_MODEL_KIBIS& aSource ) :
const PARAM& param2 = param2refwrap.get();
if( param1.info.name == param2.info.name )
*( param1.value ) = *( param2.value );
param1.value = param2.value;
}
}

View File

@ -30,7 +30,7 @@ std::string SPICE_GENERATOR_L_MUTUAL::ItemParams() const
std::string result;
for( const SIM_MODEL::PARAM& param : GetInstanceParams() )
result.append( " " + param.value->ToSpiceString() );
result.append( " " + SIM_VALUE::ToSpice( param.value ) );
return result;
}

View File

@ -127,8 +127,7 @@ void SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName,
&& param.info.category != PARAM::CATEGORY::SUPERFLUOUS
&& ( param.info.name == lowerParamName || param.info.name == lowerParamName + "_" ) )
{
const SIM_VALUE& value = *GetParam( ii ).value;
SetParamValue( ii, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) );
SetParamValue( ii, aValue, aNotation );
return;
}
}
@ -151,8 +150,7 @@ void SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName,
if( param.info.id == ngspiceParamInfo.id
&& param.info.category != PARAM::CATEGORY::SUPERFLUOUS )
{
const SIM_VALUE& value = *GetParam( ii ).value;
SetParamValue( ii, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) );
SetParamValue( ii, aValue, aNotation );
return;
}
}

View File

@ -32,10 +32,10 @@ std::string SPICE_GENERATOR_R_POT::ModelLine( const SPICE_ITEM& aItem ) const
std::string position = "";
if ( m_model.FindParam( "r" ) )
r = m_model.FindParam( "r" )->value->ToSpiceString();
r = SIM_VALUE::ToSpice( m_model.FindParam( "r" )->value );
if ( m_model.FindParam( "pos" ) )
position = m_model.FindParam( "pos" )->value->ToSpiceString();
position = SIM_VALUE::ToSpice( m_model.FindParam( "pos" )->value );
if( position != "" )
{
@ -47,11 +47,11 @@ std::string SPICE_GENERATOR_R_POT::ModelLine( const SPICE_ITEM& aItem ) const
}
std::string SPICE_GENERATOR_R_POT::TunerCommand( const SPICE_ITEM& aItem,
const SIM_VALUE_FLOAT& aValue ) const
std::string SPICE_GENERATOR_R_POT::TunerCommand( const SPICE_ITEM& aItem, double aValue ) const
{
return fmt::format( "altermod @{}[position]={}",
aItem.model->SpiceGenerator().ItemName( aItem ), aValue.ToSpiceString() );
return fmt::format( "altermod @{}[position]={:g}",
aItem.model->SpiceGenerator().ItemName( aItem ),
aValue );
}

View File

@ -35,7 +35,7 @@ public:
using SPICE_GENERATOR::SPICE_GENERATOR;
std::string ModelLine( const SPICE_ITEM& aItem ) const override;
std::string TunerCommand( const SPICE_ITEM& aItem, const SIM_VALUE_FLOAT& aValue ) const override;
std::string TunerCommand( const SPICE_ITEM& aItem, double aValue ) const override;
};

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -47,13 +47,12 @@ std::string SPICE_GENERATOR_RAW_SPICE::ModelLine( const SPICE_ITEM& aItem ) cons
std::string SPICE_GENERATOR_RAW_SPICE::ItemName( const SPICE_ITEM& aItem ) const
{
std::string elementType = m_model.GetParam(
static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::TYPE ) ).value->ToString();
std::string type = m_model.GetParam( (int) SIM_MODEL_RAW_SPICE::SPICE_PARAM::TYPE ).value;
if( aItem.refName != "" && boost::starts_with( aItem.refName, elementType ) )
if( aItem.refName != "" && boost::starts_with( aItem.refName, type ) )
return aItem.refName;
else
return fmt::format( "{}{}", elementType, aItem.refName );
return fmt::format( "{}{}", type, aItem.refName );
}
@ -105,7 +104,7 @@ std::string SPICE_GENERATOR_RAW_SPICE::ItemParams() const
for( const SIM_MODEL::PARAM& param : GetInstanceParams() )
{
if( param.info.name == "model" )
result.append( " " + param.value->ToString() );
result.append( " " + param.value );
}
return result;

View File

@ -67,7 +67,7 @@ std::string SIM_MODEL_SERIALIZER::GenerateType() const
std::string SIM_MODEL_SERIALIZER::GenerateValue() const
{
const SIM_MODEL::PARAM& param = m_model.GetParamOverride( 0 );
std::string result = param.value->ToString();
std::string result = param.value;
if( result == "" )
result = m_model.GetDeviceInfo().fieldValue;
@ -88,14 +88,14 @@ std::string SIM_MODEL_SERIALIZER::GenerateParams() const
const SIM_MODEL::PARAM& param = m_model.GetParamOverride( i );
if( param.value->ToString() == ""
if( param.value == ""
&& !( i == 0 && m_model.HasPrimaryValue() && !m_model.IsStoredInValue() ) )
{
continue;
}
// If the parameter is an enum and the value is default, don't write anything.
if( param.info.enumValues.size() >= 1 && param.value->ToString() == param.info.defaultValue )
if( param.info.enumValues.size() >= 1 && param.value == param.info.defaultValue )
continue;
std::string paramValuePair = generateParamValuePair( param );
@ -296,7 +296,7 @@ std::string SIM_MODEL_SERIALIZER::generateParamValuePair( const SIM_MODEL::PARAM
if( boost::ends_with( aParam.info.name, "_" ) )
name = aParam.info.name.substr( 0, aParam.info.name.length() - 1 );
std::string value = aParam.value->ToString();
std::string value = aParam.value;
if( value == "" || value.find( ' ' ) != std::string::npos )
value = fmt::format( "\"{}\"", value );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -53,9 +53,9 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
std::string dc = "";
if( m_model.FindParam( "ac" ) )
ac = m_model.FindParam( "ac" )->value->ToSpiceString();
ac = SIM_VALUE::ToSpice( m_model.FindParam( "ac" )->value );
if( m_model.FindParam( "dc" ) )
dc = m_model.FindParam( "dc" )->value->ToSpiceString();
dc = SIM_VALUE::ToSpice( m_model.FindParam( "dc" )->value );
bool emptyLine = true;
item.modelName = "";
@ -82,8 +82,7 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
case SIM_MODEL::TYPE::V_PWL:
case SIM_MODEL::TYPE::I_PWL:
{
tao::pegtl::string_input<> in( m_model.GetParam( 0 ).value->ToString(),
"from_content" );
tao::pegtl::string_input<> in( m_model.GetParam( 0 ).value, "from_content" );
std::unique_ptr<tao::pegtl::parse_tree::node> root;
try
@ -104,9 +103,7 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
if( node->is_type<SIM_MODEL_SOURCE_PARSER::number<SIM_VALUE::TYPE_FLOAT,
SIM_VALUE::NOTATION::SI>>() )
{
std::unique_ptr<SIM_VALUE> value = SIM_VALUE::Create( SIM_VALUE::TYPE_FLOAT,
node->string() );
args.append( value->ToString( SIM_VALUE::NOTATION::SPICE ) + " " );
args.append( SIM_VALUE::ToSpice( node->string() ) + " " );
}
}
}
@ -143,16 +140,17 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
case SIM_MODEL::TYPE::V_RANDUNIFORM:
case SIM_MODEL::TYPE::I_RANDUNIFORM:
{
/* JEY TODO
args.append( "1 " );
args.append( getParamValueString( "dt", "0" ) + " " );
args.append( getParamValueString( "td", "0" ) + " " );
SIM_VALUE_FLOAT min = dynamic_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "max" )->value );
SIM_VALUE_FLOAT min = dynamic_cast<SIM_VALUE_FLOAT&>( m_model.FindParam( "max" )->value );
if( !min.ToString().empty() )
min.FromString( "0" );
SIM_VALUE_FLOAT max = dynamic_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "min" )->value );
SIM_VALUE_FLOAT max = dynamic_cast<SIM_VALUE_FLOAT&>( m_model.FindParam( "min" )->value );
if( !max.ToString().empty() )
max.FromString( "0" );
@ -162,7 +160,7 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
args.append( range.ToSpiceString() + " " );
args.append( offset.ToSpiceString() + " " );
*/
break;
}
@ -196,7 +194,7 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
default:
for( const SIM_MODEL::PARAM& param : m_model.GetParams() )
{
std::string argStr = param.value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
std::string argStr = SIM_VALUE::ToSpice( param.value );
if( argStr != "" )
args.append( argStr + " " );
@ -214,7 +212,7 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
std::string ph = "";
if( m_model.FindParam( "ph" ) )
ph = m_model.FindParam( "ph" )->value->ToSpiceString();
ph = SIM_VALUE::ToSpice( m_model.FindParam( "ph" )->value );
emptyLine = false;
item.modelName += fmt::format( "AC {} {}", ac, ph );
@ -222,7 +220,7 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
if( emptyLine )
{
item.modelName = m_model.GetParam( 0 ).value->ToSpiceString();
item.modelName = SIM_VALUE::ToSpice( m_model.GetParam( 0 ).value );
}
return SPICE_GENERATOR::ItemLine( item );
@ -235,7 +233,7 @@ std::string SPICE_GENERATOR_SOURCE::getParamValueString( const std::string& aPar
std::string result = "";
if ( m_model.FindParam( aParamName ) )
result = m_model.FindParam( aParamName )->value->ToSpiceString();
result = SIM_VALUE::ToSpice( m_model.FindParam( aParamName )->value );
if( result == "" )
result = aDefaultValue;
@ -253,32 +251,32 @@ SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType ) :
}
void SIM_MODEL_SOURCE::SetParamValue( int aParamIndex, const SIM_VALUE& aValue )
void SIM_MODEL_SOURCE::doSetParamValue( int aParamIndex, const std::string& aValue )
{
// Sources are special. All preceding parameter values must be filled. If they are not, fill
// them out automatically. If a value is nulled, delete everything after it.
if( aValue.ToString().empty() )
if( aValue.empty() )
{
for( int paramIndex = static_cast<int>( aParamIndex );
paramIndex < GetParamCount();
++paramIndex )
{
m_params.at( aParamIndex ).value->FromString( "" );
m_params.at( aParamIndex ).value = "";
}
}
else
{
for( int paramIndex = 0; paramIndex < aParamIndex; ++paramIndex )
{
if( GetParam( paramIndex ).value->ToString() == "" )
if( GetParam( paramIndex ).value == "" )
{
m_params.at( aParamIndex ).value->FromString( "0" );
m_params.at( aParamIndex ).value = "0";
SIM_MODEL::SetParamValue( paramIndex, "0" );
}
}
}
return SIM_MODEL::SetParamValue( aParamIndex, aValue );
return SIM_MODEL::doSetParamValue( aParamIndex, aValue );
}

View File

@ -71,13 +71,14 @@ class SIM_MODEL_SOURCE : public SIM_MODEL
public:
SIM_MODEL_SOURCE( TYPE aType );
void SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) override;
bool HasAutofill() const override { return true; }
bool HasPrimaryValue() const override { return GetType() == TYPE::V || GetType() == TYPE::I; }
std::vector<std::string> GetPinNames() const override { return { "+", "-" }; }
protected:
void doSetParamValue( int aParamIndex, const std::string& aValue ) override;
private:
static const std::vector<PARAM::INFO>& makeParamInfos( TYPE aType );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -93,12 +93,12 @@ SIM_MODEL_SPICE::SIM_MODEL_SPICE( TYPE aType, std::unique_ptr<SPICE_GENERATOR> a
}
void SIM_MODEL_SPICE::SetParamValue( int aParamIndex, const SIM_VALUE& aValue )
void SIM_MODEL_SPICE::doSetParamValue( int aParamIndex, const std::string& aValue )
{
if( m_spiceCode != "" )
THROW_IO_ERROR( "Could not change model parameters: library models are immutable" );
SIM_MODEL::SetParamValue( aParamIndex, aValue );
SIM_MODEL::doSetParamValue( aParamIndex, aValue );
}

View File

@ -58,7 +58,7 @@ public:
std::unique_ptr<SPICE_MODEL_PARSER> aSpiceModelParser );
protected:
void SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) override;
void doSetParamValue( int aParamIndex, const std::string& aValue ) override;
virtual void SetParamFromSpiceCode( const std::string& aParamName,
const std::string& aParamValue,

View File

@ -69,7 +69,7 @@ std::string SPICE_GENERATOR_SWITCH::ItemParams() const
for( const SIM_MODEL::PARAM& param : GetInstanceParams() )
{
// The only instance param is "ic", which is positional.
std::string value = param.value->ToSpiceString();
std::string value = param.value;
if( value != "none" )
result.append( value );

View File

@ -31,37 +31,34 @@ using PARAM = SIM_MODEL::PARAM;
std::string SPICE_GENERATOR_TLINE::ModelLine( const SPICE_ITEM& aItem ) const
{
std::string r="0" , l="0", g="0", c="0", len="1";
std::string r="0", l="0", g="0", c="0", len="1";
switch( m_model.GetType() )
{
case SIM_MODEL::TYPE::TLINE_Z0:
{
auto z0 = static_cast<const SIM_VALUE_FLOAT&>( *m_model.FindParam( "z0" )->value );
auto td = static_cast<const SIM_VALUE_FLOAT&>( *m_model.FindParam( "td" )->value );
double z0 = SIM_VALUE::ToDouble( m_model.FindParam( "z0" )->value );
double td = SIM_VALUE::ToDouble( m_model.FindParam( "td" )->value );
if( !z0.ToString().empty() || !td.ToString().empty() )
if( isnan( z0 ) || isnan( td ) )
return fmt::format( ".model {} LTRA()\n", aItem.modelName );
r = SIM_VALUE_FLOAT( 0 ).ToSpiceString();
l = ( td * z0 ).ToSpiceString();
g = SIM_VALUE_FLOAT( 0 ).ToSpiceString();
c = ( td / z0 ).ToSpiceString();
len = SIM_VALUE_FLOAT( 1 ).ToSpiceString();
l = fmt::format( "{:g}", td * z0 );
c = fmt::format( "{:g}", td / z0 );
break;
}
case SIM_MODEL::TYPE::TLINE_RLGC:
{
if( m_model.FindParam( "r" ) )
r = m_model.FindParam( "r" )->value->ToSpiceString();
r = SIM_VALUE::ToSpice( m_model.FindParam( "r" )->value );
if( m_model.FindParam( "l" ) )
l = m_model.FindParam( "l" )->value->ToSpiceString();
l = SIM_VALUE::ToSpice( m_model.FindParam( "l" )->value );
if( m_model.FindParam( "g" ) )
g = m_model.FindParam( "g" )->value->ToSpiceString();
g = SIM_VALUE::ToSpice( m_model.FindParam( "g" )->value );
if( m_model.FindParam( "c" ) )
c = m_model.FindParam( "c" )->value->ToSpiceString();
c = SIM_VALUE::ToSpice( m_model.FindParam( "c" )->value );
if( m_model.FindParam( "len" ) )
len = m_model.FindParam( "len" )->value->ToSpiceString();
len = SIM_VALUE::ToSpice( m_model.FindParam( "len" )->value );
break;
}
default:

View File

@ -924,7 +924,7 @@ void SIM_PLOT_FRAME::applyTuners()
continue;
}
SIM_VALUE_FLOAT floatVal( tuner->GetValue().ToDouble() );
double floatVal = tuner->GetValue().ToDouble();
m_simulator->Command( item->model->SpiceGenerator().TunerCommand( *item, floatVal ) );
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -52,11 +52,8 @@ SIM_BOOL_PROPERTY::SIM_BOOL_PROPERTY( const wxString& aLabel, const wxString& aN
wxBoolProperty( aLabel, aName ),
SIM_PROPERTY( aModel, aParamIndex )
{
auto simValue = dynamic_cast<SIM_VALUE_INST<bool>*>( m_model.GetParam( m_paramIndex ).value.get() );
wxCHECK( simValue, /*void*/ );
SetValue( *simValue == true );
std::string value = m_model.GetParam( m_paramIndex ).value;
SetValue( value == "1" );
}
@ -73,14 +70,7 @@ void SIM_BOOL_PROPERTY::OnSetValue()
if( m_disabled )
return;
auto simValue = dynamic_cast<SIM_VALUE_INST<bool>*>( m_model.GetParam( m_paramIndex ).value.get() );
wxCHECK( simValue, /*void*/ );
if( m_model.GetBaseModel() && *simValue == m_value.GetBool() )
m_model.SetParamValue( m_paramIndex, "" );
else
m_model.SetParamValue( m_paramIndex, m_value.GetBool() ? "1" : "0" );
m_model.SetParamValue( m_paramIndex, m_value.GetBool() ? "1" : "0" );
}
@ -93,7 +83,7 @@ SIM_STRING_PROPERTY::SIM_STRING_PROPERTY( const wxString& aLabel, const wxString
m_valueType( aValueType ),
m_notation( aNotation )
{
SetValueFromString( GetParam().value->ToString() );
SetValueFromString( GetParam().value );
}
@ -176,7 +166,7 @@ bool SIM_STRING_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aT
text = aText;
m_model.SetParamValue( m_paramIndex, std::string( text.ToUTF8() ) );
aVariant = GetParam().value->ToString();
aVariant = GetParam().value;
return true;
}
@ -201,7 +191,7 @@ SIM_ENUM_PROPERTY::SIM_ENUM_PROPERTY( const wxString& aLabel, const wxString& aN
{
for( int ii = 0; ii < (int) GetParam().info.enumValues.size(); ++ii )
{
if( GetParam().info.enumValues[ii] == GetParam().value->ToString() )
if( GetParam().info.enumValues[ii] == GetParam().value )
{
SetValue( ii );
return;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -28,6 +28,7 @@
#include <locale_io.h>
#include <pegtl/contrib/parse_tree.hpp>
#include <fmt/core.h>
#include <math/util.h>
#define CALL_INSTANCE( ValueType, Notation, func, ... ) \
@ -176,8 +177,8 @@ static inline void handleNodeForParse( tao::pegtl::parse_tree::node& aNode,
}
else if( aNode.is_type<SIM_VALUE_PARSER::unitPrefix<ValueType, Notation>>() )
{
aParseResult.unitPrefixExponent =
SIM_VALUE_PARSER::UnitPrefixToExponent( aNode.string(), Notation );
aParseResult.unitPrefixExponent = SIM_VALUE_PARSER::UnitPrefixToExponent( aNode.string(),
Notation );
aParseResult.isEmpty = false;
}
else
@ -358,364 +359,82 @@ std::string SIM_VALUE_PARSER::ExponentToUnitPrefix( double aExponent, int& aExpo
}
std::unique_ptr<SIM_VALUE> SIM_VALUE::Create( TYPE aType, const std::string& aString,
NOTATION aNotation )
{
std::unique_ptr<SIM_VALUE> value = SIM_VALUE::Create( aType );
value->FromString( aString, aNotation );
return value;
}
std::unique_ptr<SIM_VALUE> SIM_VALUE::Create( TYPE aType )
{
switch( aType )
{
case TYPE_BOOL: return std::make_unique<SIM_VALUE_BOOL>();
case TYPE_INT: return std::make_unique<SIM_VALUE_INT>();
case TYPE_FLOAT: return std::make_unique<SIM_VALUE_FLOAT>();
case TYPE_COMPLEX: return std::make_unique<SIM_VALUE_COMPLEX>();
case TYPE_STRING: return std::make_unique<SIM_VALUE_STRING>();
case TYPE_BOOL_VECTOR: return std::make_unique<SIM_VALUE_BOOL>();
case TYPE_INT_VECTOR: return std::make_unique<SIM_VALUE_INT>();
case TYPE_FLOAT_VECTOR: return std::make_unique<SIM_VALUE_FLOAT>();
case TYPE_COMPLEX_VECTOR: return std::make_unique<SIM_VALUE_COMPLEX>();
}
wxFAIL_MSG( _( "Unknown SIM_VALUE type" ) );
return nullptr;
}
SIM_VALUE& SIM_VALUE::operator=( const std::string& aString )
{
FromString( aString );
return *this;
}
bool SIM_VALUE::operator!=( const SIM_VALUE& aOther ) const
{
return !( *this == aOther );
}
template <typename T>
SIM_VALUE_INST<T>::SIM_VALUE_INST( const T& aValue ) : m_value( aValue )
{
}
template SIM_VALUE_BOOL::SIM_VALUE_INST( const bool& aValue );
template SIM_VALUE_INT::SIM_VALUE_INST( const int& aValue );
template SIM_VALUE_FLOAT::SIM_VALUE_INST( const double& aValue );
template SIM_VALUE_COMPLEX::SIM_VALUE_INST( const std::complex<double>& aValue );
template SIM_VALUE_STRING::SIM_VALUE_INST( const std::string& aValue );
template <> SIM_VALUE::TYPE SIM_VALUE_BOOL::GetType() const { return TYPE_BOOL; }
template <> SIM_VALUE::TYPE SIM_VALUE_INT::GetType() const { return TYPE_INT; }
template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT::GetType() const { return TYPE_FLOAT; }
template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX::GetType() const { return TYPE_FLOAT; }
template <> SIM_VALUE::TYPE SIM_VALUE_STRING::GetType() const { return TYPE_STRING; }
// TODO
/*template <> SIM_VALUE::TYPE SIM_VALUE_BOOL_VECTOR::GetType() const { return TYPE_BOOL; }
template <> SIM_VALUE::TYPE SIM_VALUE_INT_VECTOR::GetType() const { return TYPE_INT; }
template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT_VECTOR::GetType() const { return TYPE_FLOAT; }
template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX_VECTOR::GetType() const { return TYPE_COMPLEX; }*/
template <>
bool SIM_VALUE_BOOL::FromString( const std::string& aString, NOTATION aNotation )
{
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString, aNotation );
m_value = std::nullopt;
if( !parseResult.isOk )
return false;
if( parseResult.isEmpty )
return true;
if( !parseResult.intPart
|| ( *parseResult.intPart != 0 && *parseResult.intPart != 1 )
|| parseResult.fracPart
|| parseResult.exponent
|| parseResult.unitPrefixExponent )
{
return false;
}
m_value = *parseResult.intPart;
return true;
}
template <>
bool SIM_VALUE_INT::FromString( const std::string& aString, NOTATION aNotation )
{
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString, aNotation );
m_value = std::nullopt;
if( !parseResult.isOk )
return false;
if( parseResult.isEmpty )
return true;
if( !parseResult.intPart || ( parseResult.fracPart && *parseResult.fracPart != 0 ) )
return false;
int exponent = parseResult.exponent ? *parseResult.exponent : 0;
exponent += parseResult.unitPrefixExponent ? *parseResult.unitPrefixExponent : 0;
m_value = static_cast<double>( *parseResult.intPart ) * std::pow( 10, exponent );
return true;
}
template <>
bool SIM_VALUE_FLOAT::FromString( const std::string& aString, NOTATION aNotation )
std::string SIM_VALUE::ConvertNotation( const std::string& aString, NOTATION aFromNotation,
NOTATION aToNotation )
{
wxString buf( aString );
// Convert any entered decimal point separators to the one our PEGTL grammar expects
buf.Replace( wxT( "," ), wxT( "." ) );
buf.Replace( ',', '.' );
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( buf.ToStdString(),
aNotation );
m_value = std::nullopt;
aFromNotation );
if( !parseResult.isOk )
return false;
if( parseResult.isEmpty )
return true;
// Single dot should be allowed in fields.
// TODO: disallow single dot in models.
if( parseResult.significand.empty() || parseResult.significand == "." )
return false;
int exponent = parseResult.exponent ? *parseResult.exponent : 0;
exponent += parseResult.unitPrefixExponent ? *parseResult.unitPrefixExponent : 0;
try
if( parseResult.isOk && !parseResult.isEmpty && !parseResult.significand.empty() )
{
LOCALE_IO toggle;
int exponent = parseResult.exponent ? *parseResult.exponent : 0;
exponent += parseResult.unitPrefixExponent ? *parseResult.unitPrefixExponent : 0;
m_value = std::stod( parseResult.significand ) * std::pow( 10, exponent );
}
catch( const std::invalid_argument& )
{
return false;
}
return true;
}
template <>
bool SIM_VALUE_COMPLEX::FromString( const std::string& aString, NOTATION aNotation )
{
// TODO
/*LOCALE_IO toggle;
double value = 0;
if( !aString.ToDouble( &value ) )
throw KI_PARAM_ERROR( _( "Invalid complex sim value string" ) );
m_value = value;*/
return true;
}
template <>
bool SIM_VALUE_STRING::FromString( const std::string& aString, NOTATION aNotation )
{
m_value = aString;
return true;
}
template <typename T>
std::string SIM_VALUE_INST<T>::ToString( NOTATION aNotation ) const
{
static_assert( std::is_same<T, std::vector<T>>::value );
std::string string;
for( auto it = m_value.cbegin(); it != m_value.cend(); it++ )
{
string += SIM_VALUE_INST<T>( *it ).ToString();
string += ",";
}
return string;
}
template <>
std::string SIM_VALUE_BOOL::ToString( NOTATION aNotation ) const
{
if( m_value )
return fmt::format( "{:d}", *m_value );
return "";
}
template <>
std::string SIM_VALUE_INT::ToString( NOTATION aNotation ) const
{
if( m_value )
{
int value = std::abs( *m_value );
int exponent = 0;
while( value != 0 && value % 1000 == 0 )
try
{
exponent += 3;
value /= 1000;
LOCALE_IO toggle;
int expReduction = 0;
std::string prefix = SIM_VALUE_PARSER::ExponentToUnitPrefix( exponent, expReduction,
aToNotation );
exponent -= expReduction;
return fmt::format( "{:g}{}",
std::stod( parseResult.significand ) * std::pow( 10, exponent ),
prefix );
}
catch( const std::invalid_argument& )
{
// best efforts
}
int dummy = 0;
std::string prefix = SIM_VALUE_PARSER::ExponentToUnitPrefix( (double) exponent, dummy,
aNotation );
return fmt::format( "{:d}{:s}", value, prefix );
}
return "";
return aString;
}
template <>
std::string SIM_VALUE_FLOAT::ToString( NOTATION aNotation ) const
double SIM_VALUE::ToDouble( const std::string& aString, double aDefault )
{
if( m_value )
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString, NOTATION::SI );
if( parseResult.isOk && !parseResult.isEmpty && !parseResult.significand.empty() )
{
double exponent = std::log10( std::abs( *m_value ) );
int reductionExponent = 0;
try
{
LOCALE_IO toggle;
int exponent = parseResult.exponent ? *parseResult.exponent : 0;
std::string prefix = SIM_VALUE_PARSER::ExponentToUnitPrefix( exponent, reductionExponent,
aNotation );
double reducedValue = *m_value / std::pow( 10, reductionExponent );
exponent += parseResult.unitPrefixExponent ? *parseResult.unitPrefixExponent : 0;
return fmt::format( "{:g}{}", reducedValue, prefix );
return std::stod( parseResult.significand ) * std::pow( 10, exponent );
}
catch( const std::invalid_argument& )
{
// best efforts
}
}
else
return "";
return aDefault;
}
template <>
std::string SIM_VALUE_COMPLEX::ToString( NOTATION aNotation ) const
int SIM_VALUE::ToInt( const std::string& aString, int aDefault )
{
if( m_value )
return fmt::format( "{:g}+{:g}i", m_value->real(), m_value->imag() );
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString, NOTATION::SI );
return "";
if( parseResult.isOk
&& !parseResult.isEmpty
&& parseResult.intPart
&& ( !parseResult.fracPart || *parseResult.fracPart == 0 ) )
{
int exponent = parseResult.exponent ? *parseResult.exponent : 0;
exponent += parseResult.unitPrefixExponent ? *parseResult.unitPrefixExponent : 0;
if( exponent >= 0 )
return (int) *parseResult.intPart * (int) std::pow( 10, exponent );
}
return aDefault;
}
template <>
std::string SIM_VALUE_STRING::ToString( NOTATION aNotation ) const
{
if( m_value )
return *m_value;
return ""; // Empty string is completely equivalent to null string.
}
template <typename T>
SIM_VALUE_INST<T>& SIM_VALUE_INST<T>::operator=( const SIM_VALUE& aOther )
{
auto other = dynamic_cast<const SIM_VALUE_INST<T>*>( &aOther );
m_value = other->m_value;
return *this;
}
template <typename T>
bool SIM_VALUE_INST<T>::operator==( const T& aOther ) const
{
return m_value == aOther;
}
template <>
bool SIM_VALUE_BOOL::operator==( const bool& aOther ) const
{
// Note that we take nullopt as the same as false here.
if( !m_value )
return false == aOther;
return m_value == aOther;
}
template bool SIM_VALUE_INT::operator==( const int& aOther ) const;
template bool SIM_VALUE_FLOAT::operator==( const double& aOther ) const;
template bool SIM_VALUE_COMPLEX::operator==( const std::complex<double>& aOther ) const;
template bool SIM_VALUE_STRING::operator==( const std::string& aOther ) const;
template <typename T>
bool SIM_VALUE_INST<T>::operator==( const SIM_VALUE& aOther ) const
{
const SIM_VALUE_INST<T>* otherValue = dynamic_cast<const SIM_VALUE_INST<T>*>( &aOther );
if( otherValue )
return m_value == otherValue->m_value;
return false;
}
template <typename T>
SIM_VALUE_INST<T> operator+( const SIM_VALUE_INST<T>& aLeft, const SIM_VALUE_INST<T>& aRight )
{
return SIM_VALUE_INST( aLeft.m_value.value() + aRight.m_value.value() );
}
template SIM_VALUE_INT operator+( const SIM_VALUE_INT& aLeft,
const SIM_VALUE_INT& aRight );
template SIM_VALUE_FLOAT operator+( const SIM_VALUE_FLOAT& aLeft,
const SIM_VALUE_FLOAT& aRight );
template <typename T>
SIM_VALUE_INST<T> operator-( const SIM_VALUE_INST<T>& aLeft, const SIM_VALUE_INST<T>& aRight )
{
return SIM_VALUE_INST( aLeft.m_value.value() - aRight.m_value.value() );
}
template SIM_VALUE_INT operator-( const SIM_VALUE_INT& aLeft,
const SIM_VALUE_INT& aRight );
template SIM_VALUE_FLOAT operator-( const SIM_VALUE_FLOAT& aLeft,
const SIM_VALUE_FLOAT& aRight );
template <typename T>
SIM_VALUE_INST<T> operator*( const SIM_VALUE_INST<T>& aLeft, const SIM_VALUE_INST<T>& aRight )
{
return SIM_VALUE_INST( aLeft.m_value.value() * aRight.m_value.value() );
}
template SIM_VALUE_INT operator*( const SIM_VALUE_INT& aLeft,
const SIM_VALUE_INT& aRight );
template SIM_VALUE_FLOAT operator*( const SIM_VALUE_FLOAT& aLeft,
const SIM_VALUE_FLOAT& aRight );
template <typename T>
SIM_VALUE_INST<T> operator/( const SIM_VALUE_INST<T>& aLeft, const SIM_VALUE_INST<T>& aRight )
{
return SIM_VALUE_INST( aLeft.m_value.value() / aRight.m_value.value() );
}
template SIM_VALUE_INT operator/( const SIM_VALUE_INT& aLeft,
const SIM_VALUE_INT& aRight );
template SIM_VALUE_FLOAT operator/( const SIM_VALUE_FLOAT& aLeft,
const SIM_VALUE_FLOAT& aRight );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -76,75 +76,26 @@ public:
TYPE_COMPLEX_VECTOR
};
static std::unique_ptr<SIM_VALUE> Create( TYPE aType, const std::string& aString,
NOTATION aNotation = NOTATION::SI );
static std::unique_ptr<SIM_VALUE> Create( TYPE aType );
static std::string ConvertNotation( const std::string& aString, NOTATION aFromNotation,
NOTATION aToNotation );
virtual ~SIM_VALUE() = default;
SIM_VALUE() = default;
static std::string Normalize( const std::string& aString, NOTATION aNotation )
{
// Note: also converts decimal separators to '.'
return ConvertNotation( aString, aNotation, NOTATION::SI );
}
virtual TYPE GetType() const = 0;
static std::string ToSpice( const std::string& aString )
{
return ConvertNotation( aString, NOTATION::SI, NOTATION::SPICE );
}
SIM_VALUE& operator=( const std::string& aString );
virtual SIM_VALUE& operator=( const SIM_VALUE& aValue ) = 0;
virtual bool operator==( const SIM_VALUE& aOther ) const = 0;
bool operator!=( const SIM_VALUE& aOther ) const;
static double ToDouble( const std::string& aString, double aDefault = NAN );
virtual bool FromString( const std::string& aString, NOTATION aNotation = NOTATION::SI ) = 0;
virtual std::string ToString( NOTATION aNotation = NOTATION::SI ) const = 0;
std::string ToSpiceString() const { return ToString( NOTATION::SPICE ); }
static int ToInt( const std::string& aString, int aDefault = -1 );
};
template <typename T>
class SIM_VALUE_INST : public SIM_VALUE
{
public:
SIM_VALUE_INST() = default;
SIM_VALUE_INST( const T& aValue );
TYPE GetType() const override;
// TODO: Don't pass aNotation. Make a FromSpiceString() function instead.
// TODO: Don't use FromString(). Use assignment. Values should be immutable.
bool FromString( const std::string& aString, NOTATION aNotation = NOTATION::SI ) override;
std::string ToString( NOTATION aNotation = NOTATION::SI ) const override;
SIM_VALUE_INST& operator=( const SIM_VALUE& aOther ) override;
bool operator==( const T& aOther ) const;
bool operator==( const SIM_VALUE& aOther ) const override;
template <typename Type>
friend SIM_VALUE_INST<Type> operator+( const SIM_VALUE_INST<Type>& aLeft,
const SIM_VALUE_INST<Type>& aRight );
template <typename Type>
friend SIM_VALUE_INST<Type> operator-( const SIM_VALUE_INST<Type>& aLeft,
const SIM_VALUE_INST<Type>& aRight );
template <typename Type>
friend SIM_VALUE_INST<Type> operator*( const SIM_VALUE_INST<Type>& aLeft,
const SIM_VALUE_INST<Type>& aRight );
template <typename Type>
friend SIM_VALUE_INST<Type> operator/( const SIM_VALUE_INST<Type>& aLeft,
const SIM_VALUE_INST<Type>& aRight );
std::optional<T> Get() { return m_value; };
private:
std::string getMetricSuffix();
std::optional<T> m_value = std::nullopt;
};
typedef SIM_VALUE_INST<bool> SIM_VALUE_BOOL;
typedef SIM_VALUE_INST<int> SIM_VALUE_INT;
typedef SIM_VALUE_INST<double> SIM_VALUE_FLOAT;
typedef SIM_VALUE_INST<std::complex<double>> SIM_VALUE_COMPLEX;
typedef SIM_VALUE_INST<std::string> SIM_VALUE_STRING;
namespace SIM_VALUE_GRAMMAR
{
template <NOTATION Notation>

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -85,7 +85,7 @@ std::string SPICE_GENERATOR::ModelLine( const SPICE_ITEM& aItem ) const
name = param.info.name;
}
value = param.value->ToSpiceString();
value = SIM_VALUE::ToSpice( param.value );
if( value == "" )
continue;
@ -174,7 +174,7 @@ std::string SPICE_GENERATOR::ItemParams() const
{
std::string name = param.info.spiceInstanceName.empty() ? param.info.name
: param.info.spiceInstanceName;
std::string value = param.value->ToSpiceString();
std::string value = SIM_VALUE::ToSpice( param.value );
if( value != "" )
result.append( fmt::format( " {}={}", name, value ) );
@ -184,8 +184,7 @@ std::string SPICE_GENERATOR::ItemParams() const
}
std::string SPICE_GENERATOR::TunerCommand( const SPICE_ITEM& aItem,
const SIM_VALUE_FLOAT& aValue ) const
std::string SPICE_GENERATOR::TunerCommand( const SPICE_ITEM& aItem, double aValue ) const
{
// No tuning available by default.
return "";

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -58,7 +58,7 @@ public:
virtual std::string ItemModelName( const SPICE_ITEM& aItem ) const;
virtual std::string ItemParams() const;
virtual std::string TunerCommand( const SPICE_ITEM& aItem, const SIM_VALUE_FLOAT& aValue ) const;
virtual std::string TunerCommand( const SPICE_ITEM& aItem, double aValue ) const;
virtual std::vector<std::string> CurrentNames( const SPICE_ITEM& aItem ) const;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -189,7 +189,7 @@ void SPICE_MODEL_PARSER::ReadModel( const SIM_LIBRARY_SPICE& aLibrary,
}
for( int i = 0; i < static_cast<int>( sourceModel->GetParamCount() ); ++i )
m_model.SetParamValue( i, *sourceModel->GetParam( i ).value );
m_model.SetParamValue( i, sourceModel->GetParam( i ).value );
std::string paramName;
@ -265,7 +265,7 @@ SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadTypeFromSpiceStrings( const std::string&
const std::string& aVersion,
bool aSkipDefaultLevel )
{
std::unique_ptr<SIM_VALUE> readLevel = SIM_VALUE::Create( SIM_VALUE::TYPE_INT, aLevel );
std::string readLevel = wxString( aLevel ).BeforeFirst( '.' ).ToStdString();
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
@ -279,8 +279,7 @@ SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadTypeFromSpiceStrings( const std::string&
// Check if `aTypeString` starts with `typePrefix`.
if( boost::starts_with( boost::to_upper_copy( aTypeString ), typePrefix )
&& ( level == readLevel->ToString()
|| ( !aSkipDefaultLevel && isDefaultLevel && aLevel == "" ) )
&& ( level == readLevel || ( !aSkipDefaultLevel && isDefaultLevel && aLevel == "" ) )
&& version == aVersion )
{
return type;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
@ -68,7 +68,7 @@ TUNER_SLIDER::TUNER_SLIDER( SIM_PLOT_FRAME* aFrame, wxWindow* aParent,
// Special case for potentiometers because we don't have value ranges implemented yet.
if( item->model->GetType() == SIM_MODEL::TYPE::R_POT )
{
std::string valueStr = item->model->GetTunerParam()->value->ToSpiceString();
std::string valueStr = SIM_VALUE::ToSpice( item->model->GetTunerParam()->value );
if( valueStr != "" )
m_value = SPICE_VALUE( valueStr );
@ -80,7 +80,7 @@ TUNER_SLIDER::TUNER_SLIDER( SIM_PLOT_FRAME* aFrame, wxWindow* aParent,
}
else
{
m_value = SPICE_VALUE( item->model->GetTunerParam()->value->ToSpiceString() );
m_value = SPICE_VALUE( SIM_VALUE::ToSpice( item->model->GetTunerParam()->value ) );
m_min = SPICE_VALUE( 0.5 ) * m_value;
m_max = SPICE_VALUE( 2.0 ) * m_value;
}

View File

@ -58,12 +58,12 @@ public:
fmt::format( "{}{}_Usual",
boost::to_upper_copy( aModel.GetSpiceInfo().modelType ),
aModelIndex ) );
BOOST_CHECK_EQUAL( aModel.FindParam( "bv" )->value->ToString(), "1.1u" );
BOOST_CHECK_EQUAL( aModel.FindParam( "cjo" )->value->ToString(), "2.2m" );
BOOST_CHECK_EQUAL( aModel.FindParam( "ibv" )->value->ToString(), "3.3" );
BOOST_CHECK_EQUAL( aModel.FindParam( "is" )->value->ToString(), "4.4k" );
BOOST_CHECK_EQUAL( aModel.FindParam( "m_" )->value->ToString(), "5.5M" );
BOOST_CHECK_EQUAL( aModel.FindParam( "n" )->value->ToString(), "6.6G" );
BOOST_CHECK_EQUAL( aModel.FindParam( "bv" )->value, "1.1u" );
BOOST_CHECK_EQUAL( aModel.FindParam( "cjo" )->value, "2.2m" );
BOOST_CHECK_EQUAL( aModel.FindParam( "ibv" )->value, "3.3" );
BOOST_CHECK_EQUAL( aModel.FindParam( "is" )->value, "4.4k" );
BOOST_CHECK_EQUAL( aModel.FindParam( "m_" )->value, "5.5M" );
BOOST_CHECK_EQUAL( aModel.FindParam( "n" )->value, "6.6G" );
}
void CompareToEmptyModel( const SIM_MODEL& aModel, const std::string& aModelName, int aModelIndex )
@ -79,7 +79,7 @@ public:
{
BOOST_TEST_CONTEXT( "Param name: " << aModel.GetParam( i ).info.name )
{
BOOST_CHECK_EQUAL( aModel.GetParamOverride( i ).value->ToString(), "" );
BOOST_CHECK_EQUAL( aModel.GetParamOverride( i ).value, "" );
}
}
}
@ -125,16 +125,19 @@ public:
BOOST_TEST_CONTEXT( "Param name: " << paramName )
{
if( i % 10 == 0 )
BOOST_CHECK_EQUAL( aModel.FindParam( paramName )->value->ToString(), "0" );
{
BOOST_CHECK( aModel.FindParam( paramName )->value == "0M"
|| aModel.FindParam( paramName )->value == "0" );
}
else if( aModel.FindParam( paramName )->info.type == SIM_VALUE::TYPE_INT )
{
BOOST_CHECK_EQUAL( aModel.FindParam( paramName )->value->ToString(),
BOOST_CHECK_EQUAL( aModel.FindParam( paramName )->value,
fmt::format( "{:d}", i % 10 ) );
}
else
{
BOOST_CHECK_EQUAL( aModel.FindParam( paramName )->value->ToString(),
fmt::format( "{}.0000{}G", i % 10, i % 10 ) );
BOOST_CHECK_EQUAL( aModel.FindParam( paramName )->value,
fmt::format( "{}000.0{}M", i % 10, i % 10 ) );
}
}
}
@ -253,35 +256,35 @@ BOOST_AUTO_TEST_CASE( Diodes )
case 0:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "1N4148" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value->ToString(), "100" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value->ToString(), "4p" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value->ToString(), "100u" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "4n" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value->ToString(), "330m" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "2" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value->ToString(), "500m" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value->ToString(), "10n" );
BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value->ToString(), "800m" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "100" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "4p" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "100u" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "4n" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "0.33" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "2" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "0.5" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "10n" );
BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value, "0.8" );
break;
case 1:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "D1" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "1.23n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "1.23" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value->ToString(), "789m" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value->ToString(), "12.34m" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value->ToString(), "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value->ToString(), "1.23" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value->ToString(), "900f" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value->ToString(), "560m" );
BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value->ToString(), "780m" );
BOOST_CHECK_EQUAL( model.FindParam( "fc" )->value->ToString(), "900m" );
BOOST_CHECK_EQUAL( model.FindParam( "isr" )->value->ToString(), "12.34n" );
BOOST_CHECK_EQUAL( model.FindParam( "nr" )->value->ToString(), "2.345" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value->ToString(), "100" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value->ToString(), "100u" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value->ToString(), "12.34n" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "1.23n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "1.23" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "0.789" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "12.34m" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "1.23" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "0.9p" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "0.56" );
BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value, "0.78" );
BOOST_CHECK_EQUAL( model.FindParam( "fc" )->value, "0.9" );
BOOST_CHECK_EQUAL( model.FindParam( "isr" )->value, "12.34n" );
BOOST_CHECK_EQUAL( model.FindParam( "nr" )->value, "2.345" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "100" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "100u" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "12.34n" );
break;
case 2:
@ -292,12 +295,12 @@ BOOST_AUTO_TEST_CASE( Diodes )
case 4:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "D4" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "100f" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value->ToString(), "2" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value->ToString(), "3p" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value->ToString(), "45n" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value->ToString(), "678" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value->ToString(), "100f" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "0.1p" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "2" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "3p" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "45n" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "678" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "0.1p" );
break;
case 5:
@ -322,12 +325,12 @@ BOOST_AUTO_TEST_CASE( Diodes )
case 18:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "D<>/?:\\|[]!@#$%^&-_18" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "-1.1" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value->ToString(), "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "-3.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value->ToString(), "44k" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value->ToString(), "55u" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value->ToString(), "6.6M" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "-1.1" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "-3.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "44k" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "55u" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "6.6M" );
break;
case 19:
@ -339,115 +342,115 @@ BOOST_AUTO_TEST_CASE( Diodes )
case 22:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "D22" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "11.1n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value->ToString(), "33.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value->ToString(), "99.9" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value->ToString(), "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value->ToString(), "1.1" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "11.1n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "33.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "99.9" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "1.1" );
break;
case 23:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "D23" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "11.1n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value->ToString(), "33.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value->ToString(), "111.1" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value->ToString(), "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value->ToString(), "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value->ToString(), "300m" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "11.1n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "33.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "111.1" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "0.3" );
break;
case 24:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "D24" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "11.1n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "1.1" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value->ToString(), "33.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value->ToString(), "99.9" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value->ToString(), "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value->ToString(), "1.1" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "11.1n" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "1.1" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "33.3m" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "99.9" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "3" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "1.1" );
break;
case 25:
BOOST_CHECK( model.GetType() == SIM_MODEL::TYPE::D );
BOOST_CHECK_EQUAL( modelName, "D25" );
//level
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "0" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value, "0M" );
//js
BOOST_CHECK_EQUAL( model.FindParam( "jsw" )->value->ToString(), "1.00001G" );
BOOST_CHECK_EQUAL( model.FindParam( "tnom" )->value->ToString(), "2.00002G" );
BOOST_CHECK_EQUAL( model.FindParam( "jsw" )->value, "1000.01M" );
BOOST_CHECK_EQUAL( model.FindParam( "tnom" )->value, "2000.02M" );
//tref
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value->ToString(), "3.00003G" );
BOOST_CHECK_EQUAL( model.FindParam( "trs" )->value->ToString(), "4.00004G" );
BOOST_CHECK_EQUAL( model.FindParam( "rs" )->value, "3000.03M" );
BOOST_CHECK_EQUAL( model.FindParam( "trs" )->value, "4000.04M" );
//trs1
BOOST_CHECK_EQUAL( model.FindParam( "trs2" )->value->ToString(), "5.00005G" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "6.00006G" );
BOOST_CHECK_EQUAL( model.FindParam( "ns" )->value->ToString(), "7.00007G" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value->ToString(), "8.00008G" );
BOOST_CHECK_EQUAL( model.FindParam( "ttt1" )->value->ToString(), "9.00009G" );
BOOST_CHECK_EQUAL( model.FindParam( "ttt2" )->value->ToString(), "0" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value->ToString(), "1.00001G" );
BOOST_CHECK_EQUAL( model.FindParam( "trs2" )->value, "5000.05M" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value, "6000.06M" );
BOOST_CHECK_EQUAL( model.FindParam( "ns" )->value, "7000.07M" );
BOOST_CHECK_EQUAL( model.FindParam( "tt" )->value, "8000.08M" );
BOOST_CHECK_EQUAL( model.FindParam( "ttt1" )->value, "9000.09M" );
BOOST_CHECK_EQUAL( model.FindParam( "ttt2" )->value, "0M" );
BOOST_CHECK_EQUAL( model.FindParam( "cjo" )->value, "1000.01M" );
//cj0
//cj
BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value->ToString(), "2.00002G" );
BOOST_CHECK_EQUAL( model.FindParam( "vj" )->value, "2000.02M" );
//pb
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value->ToString(), "3.00003G" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value, "3000.03M" );
//mj
BOOST_CHECK_EQUAL( model.FindParam( "tm1" )->value->ToString(), "4.00004G" );
BOOST_CHECK_EQUAL( model.FindParam( "tm2" )->value->ToString(), "5.00005G" );
BOOST_CHECK_EQUAL( model.FindParam( "cjp" )->value->ToString(), "6.00006G" );
BOOST_CHECK_EQUAL( model.FindParam( "tm1" )->value, "4000.04M" );
BOOST_CHECK_EQUAL( model.FindParam( "tm2" )->value, "5000.05M" );
BOOST_CHECK_EQUAL( model.FindParam( "cjp" )->value, "6000.06M" );
//cjsw
BOOST_CHECK_EQUAL( model.FindParam( "php" )->value->ToString(), "7.00007G" );
BOOST_CHECK_EQUAL( model.FindParam( "mjsw" )->value->ToString(), "8.00008G" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value->ToString(), "9.00009G" );
BOOST_CHECK_EQUAL( model.FindParam( "php" )->value, "7000.07M" );
BOOST_CHECK_EQUAL( model.FindParam( "mjsw" )->value, "8000.08M" );
BOOST_CHECK_EQUAL( model.FindParam( "ikf" )->value, "9000.09M" );
//ik
BOOST_CHECK_EQUAL( model.FindParam( "ikr" )->value->ToString(), "0" );
BOOST_CHECK_EQUAL( model.FindParam( "nbv" )->value->ToString(), "1.00001G" );
BOOST_CHECK_EQUAL( model.FindParam( "area_" )->value->ToString(), "2.00002G" );
BOOST_CHECK_EQUAL( model.FindParam( "pj_" )->value->ToString(), "3.00003G" );
BOOST_CHECK_EQUAL( model.FindParam( "tlev" )->value->ToString(), "4" ); //"4.00004G" );
BOOST_CHECK_EQUAL( model.FindParam( "tlevc" )->value->ToString(), "5" ); //"5.00005G" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value->ToString(), "6.00006G" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value->ToString(), "7.00007G" );
BOOST_CHECK_EQUAL( model.FindParam( "cta" )->value->ToString(), "8.00008G" );
BOOST_CHECK_EQUAL( model.FindParam( "ikr" )->value, "0M" );
BOOST_CHECK_EQUAL( model.FindParam( "nbv" )->value, "1000.01M" );
BOOST_CHECK_EQUAL( model.FindParam( "area_" )->value, "2000.02M" );
BOOST_CHECK_EQUAL( model.FindParam( "pj_" )->value, "3000.03M" );
BOOST_CHECK_EQUAL( model.FindParam( "tlev" )->value, "4" );
BOOST_CHECK_EQUAL( model.FindParam( "tlevc" )->value, "5" );
BOOST_CHECK_EQUAL( model.FindParam( "eg" )->value, "6000.06M" );
BOOST_CHECK_EQUAL( model.FindParam( "xti" )->value, "7000.07M" );
BOOST_CHECK_EQUAL( model.FindParam( "cta" )->value, "8000.08M" );
//ctc
BOOST_CHECK_EQUAL( model.FindParam( "ctp" )->value->ToString(), "9.00009G" );
BOOST_CHECK_EQUAL( model.FindParam( "tpb" )->value->ToString(), "0" );
BOOST_CHECK_EQUAL( model.FindParam( "ctp" )->value, "9000.09M" );
BOOST_CHECK_EQUAL( model.FindParam( "tpb" )->value, "0M" );
//tvj
BOOST_CHECK_EQUAL( model.FindParam( "tphp" )->value->ToString(), "1.00001G" );
BOOST_CHECK_EQUAL( model.FindParam( "jtun" )->value->ToString(), "2.00002G" );
BOOST_CHECK_EQUAL( model.FindParam( "jtunsw" )->value->ToString(), "3.00003G" );
BOOST_CHECK_EQUAL( model.FindParam( "ntun" )->value->ToString(), "4.00004G" );
BOOST_CHECK_EQUAL( model.FindParam( "xtitun" )->value->ToString(), "5.00005G" );
BOOST_CHECK_EQUAL( model.FindParam( "keg" )->value->ToString(), "6.00006G" );
BOOST_CHECK_EQUAL( model.FindParam( "kf" )->value->ToString(), "7.00007G" );
BOOST_CHECK_EQUAL( model.FindParam( "af" )->value->ToString(), "8.00008G" );
BOOST_CHECK_EQUAL( model.FindParam( "fc" )->value->ToString(), "9.00009G" );
BOOST_CHECK_EQUAL( model.FindParam( "fcs" )->value->ToString(), "0" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value->ToString(), "1.00001G" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value->ToString(), "2.00002G" );
BOOST_CHECK_EQUAL( model.FindParam( "tphp" )->value, "1000.01M" );
BOOST_CHECK_EQUAL( model.FindParam( "jtun" )->value, "2000.02M" );
BOOST_CHECK_EQUAL( model.FindParam( "jtunsw" )->value, "3000.03M" );
BOOST_CHECK_EQUAL( model.FindParam( "ntun" )->value, "4000.04M" );
BOOST_CHECK_EQUAL( model.FindParam( "xtitun" )->value, "5000.05M" );
BOOST_CHECK_EQUAL( model.FindParam( "keg" )->value, "6000.06M" );
BOOST_CHECK_EQUAL( model.FindParam( "kf" )->value, "7000.07M" );
BOOST_CHECK_EQUAL( model.FindParam( "af" )->value, "8000.08M" );
BOOST_CHECK_EQUAL( model.FindParam( "fc" )->value, "9000.09M" );
BOOST_CHECK_EQUAL( model.FindParam( "fcs" )->value, "0M" );
BOOST_CHECK_EQUAL( model.FindParam( "bv" )->value, "1000.01M" );
BOOST_CHECK_EQUAL( model.FindParam( "ibv" )->value, "2000.02M" );
//ib
BOOST_CHECK_EQUAL( model.FindParam( "tcv" )->value->ToString(), "3.00003G" );
BOOST_CHECK_EQUAL( model.FindParam( "cond" )->value->ToString(), "4.00004G" );
BOOST_CHECK_EQUAL( model.FindParam( "isr" )->value->ToString(), "5.00005G" );
BOOST_CHECK_EQUAL( model.FindParam( "nr" )->value->ToString(), "6.00006G" );
BOOST_CHECK_EQUAL( model.FindParam( "fv_max" )->value->ToString(), "7.00007G" );
BOOST_CHECK_EQUAL( model.FindParam( "bv_max" )->value->ToString(), "8.00008G" );
BOOST_CHECK_EQUAL( model.FindParam( "id_max" )->value->ToString(), "9.00009G" );
BOOST_CHECK_EQUAL( model.FindParam( "te_max" )->value->ToString(), "0" );
BOOST_CHECK_EQUAL( model.FindParam( "pd_max" )->value->ToString(), "1.00001G" );
BOOST_CHECK_EQUAL( model.FindParam( "rth0" )->value->ToString(), "2.00002G" );
BOOST_CHECK_EQUAL( model.FindParam( "cth0" )->value->ToString(), "3.00003G" );
BOOST_CHECK_EQUAL( model.FindParam( "lm_" )->value->ToString(), "4.00004G" );
BOOST_CHECK_EQUAL( model.FindParam( "lp_" )->value->ToString(), "5.00005G" );
BOOST_CHECK_EQUAL( model.FindParam( "wm_" )->value->ToString(), "6.00006G" );
BOOST_CHECK_EQUAL( model.FindParam( "wp_" )->value->ToString(), "7.00007G" );
BOOST_CHECK_EQUAL( model.FindParam( "xom" )->value->ToString(), "8.00008G" );
BOOST_CHECK_EQUAL( model.FindParam( "xoi" )->value->ToString(), "9.00009G" );
BOOST_CHECK_EQUAL( model.FindParam( "xm" )->value->ToString(), "0" );
BOOST_CHECK_EQUAL( model.FindParam( "xp" )->value->ToString(), "1.00001G" );
BOOST_CHECK_EQUAL( model.FindParam( "tcv" )->value, "3000.03M" );
BOOST_CHECK_EQUAL( model.FindParam( "cond" )->value, "4000.04M" );
BOOST_CHECK_EQUAL( model.FindParam( "isr" )->value, "5000.05M" );
BOOST_CHECK_EQUAL( model.FindParam( "nr" )->value, "6000.06M" );
BOOST_CHECK_EQUAL( model.FindParam( "fv_max" )->value, "7000.07M" );
BOOST_CHECK_EQUAL( model.FindParam( "bv_max" )->value, "8000.08M" );
BOOST_CHECK_EQUAL( model.FindParam( "id_max" )->value, "9000.09M" );
BOOST_CHECK_EQUAL( model.FindParam( "te_max" )->value, "0M" );
BOOST_CHECK_EQUAL( model.FindParam( "pd_max" )->value, "1000.01M" );
BOOST_CHECK_EQUAL( model.FindParam( "rth0" )->value, "2000.02M" );
BOOST_CHECK_EQUAL( model.FindParam( "cth0" )->value, "3000.03M" );
BOOST_CHECK_EQUAL( model.FindParam( "lm_" )->value, "4000.04M" );
BOOST_CHECK_EQUAL( model.FindParam( "lp_" )->value, "5000.05M" );
BOOST_CHECK_EQUAL( model.FindParam( "wm_" )->value, "6000.06M" );
BOOST_CHECK_EQUAL( model.FindParam( "wp_" )->value, "7000.07M" );
BOOST_CHECK_EQUAL( model.FindParam( "xom" )->value, "8000.08M" );
BOOST_CHECK_EQUAL( model.FindParam( "xoi" )->value, "9000.09M" );
BOOST_CHECK_EQUAL( model.FindParam( "xm" )->value, "0M" );
BOOST_CHECK_EQUAL( model.FindParam( "xp" )->value, "1000.01M" );
//d
break;