From 7f6cb9b07b910d9dc11ab15f3273ddc43a0850ba Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Wed, 22 Feb 2023 09:10:06 +0000 Subject: [PATCH] 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 68fe146861283c37032ba21868a839e8bba995fb) --- eeschema/dialogs/dialog_sim_model.cpp | 2 +- .../netlist_exporter_spice.cpp | 2 +- eeschema/sim/sim_model.cpp | 17 +- eeschema/sim/sim_model.h | 13 +- eeschema/sim/sim_model_behavioral.cpp | 8 +- eeschema/sim/sim_model_ideal.cpp | 9 +- eeschema/sim/sim_model_ideal.h | 2 +- eeschema/sim/sim_model_kibis.cpp | 28 +- eeschema/sim/sim_model_l_mutual.cpp | 2 +- eeschema/sim/sim_model_ngspice.cpp | 6 +- eeschema/sim/sim_model_r_pot.cpp | 12 +- eeschema/sim/sim_model_r_pot.h | 2 +- eeschema/sim/sim_model_raw_spice.cpp | 11 +- eeschema/sim/sim_model_serializer.cpp | 8 +- eeschema/sim/sim_model_source.cpp | 40 +- eeschema/sim/sim_model_source.h | 5 +- eeschema/sim/sim_model_spice.cpp | 6 +- eeschema/sim/sim_model_spice.h | 2 +- eeschema/sim/sim_model_switch.cpp | 2 +- eeschema/sim/sim_model_tline.cpp | 25 +- eeschema/sim/sim_plot_frame.cpp | 2 +- eeschema/sim/sim_property.cpp | 24 +- eeschema/sim/sim_value.cpp | 397 +++--------------- eeschema/sim/sim_value.h | 77 +--- eeschema/sim/spice_generator.cpp | 9 +- eeschema/sim/spice_generator.h | 4 +- eeschema/sim/spice_model_parser.cpp | 9 +- eeschema/widgets/tuner_slider.cpp | 6 +- .../eeschema/sim/test_library_spice.cpp | 259 ++++++------ 29 files changed, 320 insertions(+), 669 deletions(-) diff --git a/eeschema/dialogs/dialog_sim_model.cpp b/eeschema/dialogs/dialog_sim_model.cpp index d1dd2b22da..9ad8ed6215 100644 --- a/eeschema/dialogs/dialog_sim_model.cpp +++ b/eeschema/dialogs/dialog_sim_model.cpp @@ -568,7 +568,7 @@ void DIALOG_SIM_MODEL::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 ); } } diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp index 33434d84dc..14e98e994c 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp @@ -501,7 +501,7 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym if( auto rawSpiceModel = dynamic_cast( aItem.model ) ) { int libParamIndex = static_cast( 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 ); diff --git a/eeschema/sim/sim_model.cpp b/eeschema/sim/sim_model.cpp index e3cbedfbc3..3222bb2b19 100644 --- a/eeschema/sim/sim_model.cpp +++ b/eeschema/sim/sim_model.cpp @@ -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; } diff --git a/eeschema/sim/sim_model.h b/eeschema/sim/sim_model.h index 517ccdb817..b5aa0dbd2c 100644 --- a/eeschema/sim/sim_model.h +++ b/eeschema/sim/sim_model.h @@ -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 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& aSymbolPins ); virtual int doFindParam( const std::string& aParamName ) const; + virtual void doSetParamValue( int aParamIndex, const std::string& aValue ); private: template diff --git a/eeschema/sim/sim_model_behavioral.cpp b/eeschema/sim/sim_model_behavioral.cpp index 1894b922a7..097d84e7b9 100644 --- a/eeschema/sim/sim_model_behavioral.cpp +++ b/eeschema/sim/sim_model_behavioral.cpp @@ -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 ); } diff --git a/eeschema/sim/sim_model_ideal.cpp b/eeschema/sim/sim_model_ideal.cpp index 520f037660..99cf4e3021 100644 --- a/eeschema/sim/sim_model_ideal.cpp +++ b/eeschema/sim/sim_model_ideal.cpp @@ -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 ); } diff --git a/eeschema/sim/sim_model_ideal.h b/eeschema/sim/sim_model_ideal.h index dc3d778427..0a22a23144 100644 --- a/eeschema/sim/sim_model_ideal.h +++ b/eeschema/sim/sim_model_ideal.h @@ -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; }; diff --git a/eeschema/sim/sim_model_kibis.cpp b/eeschema/sim/sim_model_kibis.cpp index 5ed3f44f73..933fed12f0 100644 --- a/eeschema/sim/sim_model_kibis.cpp +++ b/eeschema/sim/sim_model_kibis.cpp @@ -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( *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( *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( *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( *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( *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( *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( *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; } } diff --git a/eeschema/sim/sim_model_l_mutual.cpp b/eeschema/sim/sim_model_l_mutual.cpp index 876b3254a3..5e5fc20f56 100644 --- a/eeschema/sim/sim_model_l_mutual.cpp +++ b/eeschema/sim/sim_model_l_mutual.cpp @@ -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; } diff --git a/eeschema/sim/sim_model_ngspice.cpp b/eeschema/sim/sim_model_ngspice.cpp index 2c63a0fca8..6dfdbf307e 100644 --- a/eeschema/sim/sim_model_ngspice.cpp +++ b/eeschema/sim/sim_model_ngspice.cpp @@ -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; } } diff --git a/eeschema/sim/sim_model_r_pot.cpp b/eeschema/sim/sim_model_r_pot.cpp index bb0f9c2f9d..9656700e6c 100644 --- a/eeschema/sim/sim_model_r_pot.cpp +++ b/eeschema/sim/sim_model_r_pot.cpp @@ -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 ); } diff --git a/eeschema/sim/sim_model_r_pot.h b/eeschema/sim/sim_model_r_pot.h index 7376b3c1f5..fedb6082bb 100644 --- a/eeschema/sim/sim_model_r_pot.h +++ b/eeschema/sim/sim_model_r_pot.h @@ -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; }; diff --git a/eeschema/sim/sim_model_raw_spice.cpp b/eeschema/sim/sim_model_raw_spice.cpp index f4eb27d190..a4e5707621 100644 --- a/eeschema/sim/sim_model_raw_spice.cpp +++ b/eeschema/sim/sim_model_raw_spice.cpp @@ -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( 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; diff --git a/eeschema/sim/sim_model_serializer.cpp b/eeschema/sim/sim_model_serializer.cpp index fb4ed04730..a5c515ffc6 100644 --- a/eeschema/sim/sim_model_serializer.cpp +++ b/eeschema/sim/sim_model_serializer.cpp @@ -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 ); diff --git a/eeschema/sim/sim_model_source.cpp b/eeschema/sim/sim_model_source.cpp index 494f62f556..764bce0fbb 100644 --- a/eeschema/sim/sim_model_source.cpp +++ b/eeschema/sim/sim_model_source.cpp @@ -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 root; try @@ -104,9 +103,7 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const if( node->is_type>() ) { - std::unique_ptr 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( *m_model.FindParam( "max" )->value ); + SIM_VALUE_FLOAT min = dynamic_cast( m_model.FindParam( "max" )->value ); if( !min.ToString().empty() ) min.FromString( "0" ); - SIM_VALUE_FLOAT max = dynamic_cast( *m_model.FindParam( "min" )->value ); + SIM_VALUE_FLOAT max = dynamic_cast( 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( 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 ); } diff --git a/eeschema/sim/sim_model_source.h b/eeschema/sim/sim_model_source.h index 2b98ed90e5..9a3a9c7032 100644 --- a/eeschema/sim/sim_model_source.h +++ b/eeschema/sim/sim_model_source.h @@ -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 GetPinNames() const override { return { "+", "-" }; } +protected: + void doSetParamValue( int aParamIndex, const std::string& aValue ) override; + private: static const std::vector& makeParamInfos( TYPE aType ); diff --git a/eeschema/sim/sim_model_spice.cpp b/eeschema/sim/sim_model_spice.cpp index 50409d1e0b..5e9fd496cc 100644 --- a/eeschema/sim/sim_model_spice.cpp +++ b/eeschema/sim/sim_model_spice.cpp @@ -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 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 ); } diff --git a/eeschema/sim/sim_model_spice.h b/eeschema/sim/sim_model_spice.h index 0485bd4238..e2a42f189d 100644 --- a/eeschema/sim/sim_model_spice.h +++ b/eeschema/sim/sim_model_spice.h @@ -58,7 +58,7 @@ public: std::unique_ptr 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, diff --git a/eeschema/sim/sim_model_switch.cpp b/eeschema/sim/sim_model_switch.cpp index d2990eee71..6d13496446 100644 --- a/eeschema/sim/sim_model_switch.cpp +++ b/eeschema/sim/sim_model_switch.cpp @@ -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 ); diff --git a/eeschema/sim/sim_model_tline.cpp b/eeschema/sim/sim_model_tline.cpp index b922effb34..1d6eae99ab 100644 --- a/eeschema/sim/sim_model_tline.cpp +++ b/eeschema/sim/sim_model_tline.cpp @@ -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( *m_model.FindParam( "z0" )->value ); - auto td = static_cast( *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: diff --git a/eeschema/sim/sim_plot_frame.cpp b/eeschema/sim/sim_plot_frame.cpp index deef90b88f..a01fbe2853 100644 --- a/eeschema/sim/sim_plot_frame.cpp +++ b/eeschema/sim/sim_plot_frame.cpp @@ -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 ) ); } diff --git a/eeschema/sim/sim_property.cpp b/eeschema/sim/sim_property.cpp index 3f29b5c845..eba8d7e953 100644 --- a/eeschema/sim/sim_property.cpp +++ b/eeschema/sim/sim_property.cpp @@ -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*>( 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*>( 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; diff --git a/eeschema/sim/sim_value.cpp b/eeschema/sim/sim_value.cpp index d06791025d..2e30b52fdd 100644 --- a/eeschema/sim/sim_value.cpp +++ b/eeschema/sim/sim_value.cpp @@ -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 #include #include +#include #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>() ) { - 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::Create( TYPE aType, const std::string& aString, - NOTATION aNotation ) -{ - std::unique_ptr value = SIM_VALUE::Create( aType ); - value->FromString( aString, aNotation ); - return value; -} - - -std::unique_ptr SIM_VALUE::Create( TYPE aType ) -{ - switch( aType ) - { - case TYPE_BOOL: return std::make_unique(); - case TYPE_INT: return std::make_unique(); - case TYPE_FLOAT: return std::make_unique(); - case TYPE_COMPLEX: return std::make_unique(); - case TYPE_STRING: return std::make_unique(); - case TYPE_BOOL_VECTOR: return std::make_unique(); - case TYPE_INT_VECTOR: return std::make_unique(); - case TYPE_FLOAT_VECTOR: return std::make_unique(); - case TYPE_COMPLEX_VECTOR: return std::make_unique(); - } - - 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 -SIM_VALUE_INST::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& 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( *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 -std::string SIM_VALUE_INST::ToString( NOTATION aNotation ) const -{ - static_assert( std::is_same>::value ); - - std::string string; - - for( auto it = m_value.cbegin(); it != m_value.cend(); it++ ) - { - string += SIM_VALUE_INST( *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 -SIM_VALUE_INST& SIM_VALUE_INST::operator=( const SIM_VALUE& aOther ) -{ - auto other = dynamic_cast*>( &aOther ); - m_value = other->m_value; - return *this; -} - - -template -bool SIM_VALUE_INST::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& aOther ) const; -template bool SIM_VALUE_STRING::operator==( const std::string& aOther ) const; - - -template -bool SIM_VALUE_INST::operator==( const SIM_VALUE& aOther ) const -{ - const SIM_VALUE_INST* otherValue = dynamic_cast*>( &aOther ); - - if( otherValue ) - return m_value == otherValue->m_value; - - return false; -} - -template -SIM_VALUE_INST operator+( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& 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 -SIM_VALUE_INST operator-( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& 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 -SIM_VALUE_INST operator*( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& 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 -SIM_VALUE_INST operator/( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& 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 ); diff --git a/eeschema/sim/sim_value.h b/eeschema/sim/sim_value.h index 2ef52f7414..521c841a8f 100644 --- a/eeschema/sim/sim_value.h +++ b/eeschema/sim/sim_value.h @@ -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 Create( TYPE aType, const std::string& aString, - NOTATION aNotation = NOTATION::SI ); - static std::unique_ptr 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 -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 - friend SIM_VALUE_INST operator+( const SIM_VALUE_INST& aLeft, - const SIM_VALUE_INST& aRight ); - - template - friend SIM_VALUE_INST operator-( const SIM_VALUE_INST& aLeft, - const SIM_VALUE_INST& aRight ); - - template - friend SIM_VALUE_INST operator*( const SIM_VALUE_INST& aLeft, - const SIM_VALUE_INST& aRight ); - - template - friend SIM_VALUE_INST operator/( const SIM_VALUE_INST& aLeft, - const SIM_VALUE_INST& aRight ); - - std::optional Get() { return m_value; }; - -private: - std::string getMetricSuffix(); - - std::optional m_value = std::nullopt; -}; - -typedef SIM_VALUE_INST SIM_VALUE_BOOL; -typedef SIM_VALUE_INST SIM_VALUE_INT; -typedef SIM_VALUE_INST SIM_VALUE_FLOAT; -typedef SIM_VALUE_INST> SIM_VALUE_COMPLEX; -typedef SIM_VALUE_INST SIM_VALUE_STRING; - - namespace SIM_VALUE_GRAMMAR { template diff --git a/eeschema/sim/spice_generator.cpp b/eeschema/sim/spice_generator.cpp index b2f677581d..96361be4bf 100644 --- a/eeschema/sim/spice_generator.cpp +++ b/eeschema/sim/spice_generator.cpp @@ -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 ""; diff --git a/eeschema/sim/spice_generator.h b/eeschema/sim/spice_generator.h index b0b47a3356..791501e9b6 100644 --- a/eeschema/sim/spice_generator.h +++ b/eeschema/sim/spice_generator.h @@ -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 CurrentNames( const SPICE_ITEM& aItem ) const; diff --git a/eeschema/sim/spice_model_parser.cpp b/eeschema/sim/spice_model_parser.cpp index 40b1a12be1..e370b645fa 100644 --- a/eeschema/sim/spice_model_parser.cpp +++ b/eeschema/sim/spice_model_parser.cpp @@ -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( 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 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; diff --git a/eeschema/widgets/tuner_slider.cpp b/eeschema/widgets/tuner_slider.cpp index 3b92dd3582..cad069d3d7 100644 --- a/eeschema/widgets/tuner_slider.cpp +++ b/eeschema/widgets/tuner_slider.cpp @@ -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 * @@ -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; } diff --git a/qa/unittests/eeschema/sim/test_library_spice.cpp b/qa/unittests/eeschema/sim/test_library_spice.cpp index 4aaf3a7a57..dc487fe1a6 100644 --- a/qa/unittests/eeschema/sim/test_library_spice.cpp +++ b/qa/unittests/eeschema/sim/test_library_spice.cpp @@ -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;