Split spice tests into separate test
This commit is contained in:
parent
7a24672120
commit
27e2e820cb
|
@ -141,7 +141,7 @@ fedora_report_metrics_public:
|
|||
parallel:
|
||||
matrix:
|
||||
# The name of the test without the qa_ prefix
|
||||
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step]
|
||||
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step, spice]
|
||||
|
||||
fedora_qa_kicad:
|
||||
extends: .fedora_qa
|
||||
|
|
|
@ -115,4 +115,4 @@
|
|||
parallel:
|
||||
matrix:
|
||||
# The name of the test without the qa_ prefix
|
||||
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step]
|
||||
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step, spice]
|
||||
|
|
|
@ -23,6 +23,8 @@ set( QA_UTIL_COMMON_SRC
|
|||
stdstream_line_reader.cpp
|
||||
utility_program.cpp
|
||||
|
||||
uuid_test_utils.cpp
|
||||
|
||||
geometry/line_chain_construction.cpp
|
||||
geometry/poly_set_construction.cpp
|
||||
geometry/seg_construction.cpp
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "uuid_test_utils.h"
|
||||
|
||||
#include <qa_utils/uuid_test_utils.h>
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
namespace KI_TEST
|
|
@ -19,7 +19,7 @@
|
|||
# Eeschema-related auxiliary functions that are useful for QA purposes
|
||||
|
||||
set( QA_SCHEMATIC_UTILS_SRCS
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/eeschema_test_utils.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/schematic_file_util.cpp
|
||||
)
|
||||
|
||||
|
@ -35,12 +35,14 @@ target_include_directories( qa_schematic_utils PUBLIC
|
|||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/eeschema
|
||||
${CMAKE_SOURCE_DIR}/pcbnew
|
||||
${CMAKE_SOURCE_DIR}/common
|
||||
${INC_AFTER}
|
||||
)
|
||||
|
||||
target_link_libraries( qa_schematic_utils PUBLIC
|
||||
qa_utils
|
||||
pcbcommon
|
||||
)
|
||||
|
||||
# # we need to pretend to be something to appease the units code
|
||||
|
|
|
@ -24,4 +24,8 @@ add_subdirectory( common )
|
|||
add_subdirectory( gerbview )
|
||||
add_subdirectory( eeschema )
|
||||
add_subdirectory( libs )
|
||||
add_subdirectory( pcbnew )
|
||||
add_subdirectory( pcbnew )
|
||||
|
||||
if( KICAD_SPICE_QA )
|
||||
add_subdirectory( spice )
|
||||
endif()
|
||||
|
|
|
@ -25,19 +25,6 @@
|
|||
|
||||
include_directories( BEFORE ${INC_BEFORE} )
|
||||
|
||||
if( KICAD_SPICE_QA )
|
||||
set( INC_AFTER ${INC_AFTER} ${NGSPICE_INCLUDE_DIR} )
|
||||
|
||||
# Find out the exact libngspice file name
|
||||
get_filename_component( NGSPICE_DLL_ABSPATH "${NGSPICE_DLL}" ABSOLUTE )
|
||||
get_filename_component( NGSPICE_DLL_FILE "${NGSPICE_DLL_ABSPATH}" NAME )
|
||||
|
||||
set_property( SOURCE sim/ngspice.cpp
|
||||
APPEND PROPERTY COMPILE_DEFINITIONS
|
||||
NGSPICE_DLL_FILE="${NGSPICE_DLL_FILE}"
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
|
@ -52,9 +39,6 @@ set( QA_EESCHEMA_SRCS
|
|||
# need the mock Pgm for many functions
|
||||
${CMAKE_SOURCE_DIR}/qa/mocks/kicad/common_mocks.cpp
|
||||
|
||||
eeschema_test_utils.cpp
|
||||
uuid_test_utils.cpp
|
||||
|
||||
# The main test entry points
|
||||
test_module.cpp
|
||||
|
||||
|
@ -88,21 +72,6 @@ set( QA_EESCHEMA_SRCS
|
|||
test_sch_symbol.cpp
|
||||
)
|
||||
|
||||
|
||||
# Spice specific testing routine
|
||||
if( KICAD_SPICE_QA )
|
||||
set( QA_EESCHEMA_SRCS
|
||||
${QA_EESCHEMA_SRCS}
|
||||
# Simulation tests
|
||||
test_netlist_exporter_spice.cpp
|
||||
sim/test_library_spice.cpp
|
||||
sim/test_sim_model_inference.cpp
|
||||
sim/test_sim_model_ngspice.cpp
|
||||
sim/test_sim_regressions.cpp
|
||||
sim/test_ngspice_helpers.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if( WIN32 )
|
||||
# We want to declare a resource manifest on Windows to enable UTF8 mode
|
||||
# Without UTF8 mode, some random IO tests may fail, we set the active code page on normal kicad to UTF8 as well
|
||||
|
@ -129,24 +98,11 @@ PRIVATE
|
|||
qa_utils
|
||||
qa_schematic_utils
|
||||
markdown_lib
|
||||
${NGSPICE_LIBRARY}
|
||||
${GDI_PLUS_LIBRARIES}
|
||||
Boost::headers
|
||||
Boost::unit_test_framework
|
||||
)
|
||||
|
||||
if( KICAD_SPICE_QA AND MSVC )
|
||||
# Allow for MSVC to run from the build directory
|
||||
add_custom_command( TARGET qa_eeschema POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${NGSPICE_DLL}" "$<TARGET_FILE_DIR:qa_eeschema>"
|
||||
)
|
||||
|
||||
add_custom_command( TARGET qa_eeschema POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${NGSPICE_CM_DIR}" "$<TARGET_FILE_DIR:qa_eeschema>/ngspice"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# Eeschema tests, so pretend to be eeschema (for units, etc)
|
||||
target_compile_definitions( qa_eeschema
|
||||
PUBLIC EESCHEMA
|
||||
|
|
|
@ -30,13 +30,12 @@
|
|||
#include <ignore.h>
|
||||
#include <sch_junction.h>
|
||||
#include <sch_no_connect.h>
|
||||
#include <qa_utils/uuid_test_utils.h>
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
// Code under test
|
||||
#include <sch_rtree.h>
|
||||
|
||||
#include "uuid_test_utils.h"
|
||||
|
||||
#include <qa_utils/wx_utils/wx_assert.h>
|
||||
|
||||
class TEST_SCH_RTREE_FIXTURE
|
||||
|
|
|
@ -33,8 +33,7 @@
|
|||
#include <sch_sheet_pin.h>
|
||||
#include <schematic.h>
|
||||
|
||||
#include "uuid_test_utils.h"
|
||||
|
||||
#include <qa_utils/uuid_test_utils.h>
|
||||
#include <qa_utils/wx_utils/wx_assert.h>
|
||||
|
||||
class TEST_SCH_SHEET_FIXTURE
|
||||
|
|
|
@ -26,13 +26,12 @@
|
|||
* Test suite for #SCH_SHEET_PATH and #SCH_SHEET_LIST
|
||||
*/
|
||||
|
||||
#include <qa_utils/uuid_test_utils.h>
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
// Code under test
|
||||
#include <sch_sheet_path.h>
|
||||
|
||||
#include "uuid_test_utils.h"
|
||||
|
||||
#include <sch_sheet.h>
|
||||
|
||||
#include <sstream>
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
#
|
||||
# This program source code file is part of KiCad, a free EDA CAD application.
|
||||
#
|
||||
# Copyright (C) 2023 Ian McInerney
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, you may find one here:
|
||||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# or you may search the http://www.gnu.org website for the version 2 license,
|
||||
# or you may write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
|
||||
include_directories( BEFORE ${INC_BEFORE} )
|
||||
|
||||
set( INC_AFTER ${INC_AFTER} ${NGSPICE_INCLUDE_DIR} )
|
||||
|
||||
# Find out the exact libngspice file name
|
||||
get_filename_component( NGSPICE_DLL_ABSPATH "${NGSPICE_DLL}" ABSOLUTE )
|
||||
get_filename_component( NGSPICE_DLL_FILE "${NGSPICE_DLL_ABSPATH}" NAME )
|
||||
|
||||
set_property( SOURCE sim/ngspice.cpp
|
||||
APPEND PROPERTY COMPILE_DEFINITIONS
|
||||
NGSPICE_DLL_FILE="${NGSPICE_DLL_FILE}"
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/pcbnew
|
||||
${CMAKE_SOURCE_DIR}/qa/mocks/include
|
||||
${CMAKE_SOURCE_DIR}/qa/qa_utils
|
||||
${CMAKE_SOURCE_DIR}/qa
|
||||
${INC_AFTER}
|
||||
)
|
||||
|
||||
set( QA_SPICE_SRCS
|
||||
# need the mock Pgm for many functions
|
||||
${CMAKE_SOURCE_DIR}/qa/mocks/kicad/common_mocks.cpp
|
||||
|
||||
# The main test entry points
|
||||
test_module.cpp
|
||||
|
||||
# Test exporting the netlist
|
||||
test_netlist_exporter_spice.cpp
|
||||
|
||||
# Test SPICE library and models
|
||||
test_library_spice.cpp
|
||||
test_sim_model_inference.cpp
|
||||
test_sim_model_ngspice.cpp
|
||||
test_sim_regressions.cpp
|
||||
|
||||
test_ngspice_helpers.cpp
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
# We want to declare a resource manifest on Windows to enable UTF8 mode
|
||||
# Without UTF8 mode, some random IO tests may fail, we set the active code page on normal kicad to UTF8 as well
|
||||
if( MINGW )
|
||||
# QA_SPICE_RESOURCES variable is set by the macro.
|
||||
mingw_resource_compiler( qa_spice )
|
||||
else()
|
||||
set( QA_SPICE_RESOURCES ${CMAKE_SOURCE_DIR}/resources/msw/qa_spice.rc )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable( qa_spice
|
||||
${QA_SPICE_SRCS}
|
||||
${QA_SPICE_RESOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries( qa_spice
|
||||
PRIVATE
|
||||
eeschema_kiface_objects
|
||||
common
|
||||
pcbcommon
|
||||
scripting
|
||||
kimath
|
||||
qa_utils
|
||||
qa_schematic_utils
|
||||
markdown_lib
|
||||
${NGSPICE_LIBRARY}
|
||||
${GDI_PLUS_LIBRARIES}
|
||||
Boost::headers
|
||||
Boost::unit_test_framework
|
||||
)
|
||||
|
||||
if( KICAD_SPICE_QA AND MSVC )
|
||||
# Allow for MSVC to run from the build directory
|
||||
add_custom_command( TARGET qa_spice POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${NGSPICE_DLL}" "$<TARGET_FILE_DIR:qa_spice>"
|
||||
)
|
||||
|
||||
add_custom_command( TARGET qa_spice POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${NGSPICE_CM_DIR}" "$<TARGET_FILE_DIR:qa_spice>/ngspice"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# Eeschema tests, so pretend to be eeschema (for units, etc)
|
||||
target_compile_definitions( qa_spice
|
||||
PUBLIC EESCHEMA
|
||||
)
|
||||
|
||||
kicad_add_boost_test( qa_spice qa_spice )
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 CERN
|
||||
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
|
||||
* Copyright (C) 2019-2020 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main file for the spice tests to be compiled
|
||||
*/
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <kiplatform/app.h>
|
||||
|
||||
#include <pgm_base.h>
|
||||
#include <wx/app.h>
|
||||
#include <wx/init.h>
|
||||
|
||||
#include <qa_utils/wx_utils/wx_assert.h>
|
||||
|
||||
/*
|
||||
* Simple function to handle a WX assertion and throw a real exception.
|
||||
*
|
||||
* This is useful when you want to check assertions fire in unit tests.
|
||||
*/
|
||||
void wxAssertThrower( const wxString& aFile, int aLine, const wxString& aFunc,
|
||||
const wxString& aCond, const wxString& aMsg )
|
||||
{
|
||||
throw KI_TEST::WX_ASSERT_ERROR( aFile, aLine, aFunc, aCond, aMsg );
|
||||
}
|
||||
|
||||
|
||||
bool init_unit_test()
|
||||
{
|
||||
KIPLATFORM::APP::Init();
|
||||
boost::unit_test::framework::master_test_suite().p_name.value = "Common spice integration tests";
|
||||
|
||||
wxApp::SetInstance( new wxAppConsole );
|
||||
|
||||
bool ok = wxInitialize( boost::unit_test::framework::master_test_suite().argc,
|
||||
boost::unit_test::framework::master_test_suite().argv );
|
||||
|
||||
wxSetAssertHandler( &wxAssertThrower );
|
||||
|
||||
Pgm().InitPgm( true, true, true );
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
int ret = boost::unit_test::unit_test_main( &init_unit_test, argc, argv );
|
||||
|
||||
Pgm().Destroy();
|
||||
|
||||
// This causes some glib warnings on GTK3 (http://trac.wxwidgets.org/ticket/18274)
|
||||
// but without it, Valgrind notices a lot of leaks from WX
|
||||
wxUninitialize();
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
#include <boost/test/results_collector.hpp> // To check if the current test failed (to be moved?).
|
||||
#include <test_netlist_exporter_spice.h>
|
||||
#include <sim/spice_reporter.h>
|
||||
#include <mock_pgm_base.h>
|
||||
#include <locale_io.h>
|
||||
|
||||
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( NetlistExporterSpice, TEST_NETLIST_EXPORTER_SPICE_FIXTURE )
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( Rectifier )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
|
||||
const MOCK_PGM_BASE& program = static_cast<MOCK_PGM_BASE&>( Pgm() );
|
||||
MOCK_EXPECT( program.GetLocalEnvVariables ).returns( ENV_VAR_MAP() );
|
||||
|
||||
TestNetlist( "rectifier" );
|
||||
TestTranPoint( 0, { { "V(/in)", 0 }, { "V(/out)", 0 } } );
|
||||
TestTranPoint( 9250e-6, { { "V(/in)", 5 }, { "V(/out)", 4.26 } } );
|
||||
TestTranPoint( 10e-3, { { "V(/in)", 0 }, { "V(/out)", 4.24 } } );
|
||||
}
|
||||
|
||||
// FIXME: Fails due to some nondeterminism, seems related to convergence problems.
|
||||
|
||||
/*BOOST_AUTO_TEST_CASE( Chirp )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "chirp", { "V(/out)", "I(R1)" } );
|
||||
}*/
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( Opamp )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
// Instead of Simulation_SPICE:OPAMP, we use Amplifier_Operational:MCP6001-OT because its pins
|
||||
// are not ordered by pin numbers, which is a possible failure condition.
|
||||
|
||||
const MOCK_PGM_BASE& program = static_cast<MOCK_PGM_BASE&>( Pgm() );
|
||||
MOCK_EXPECT( program.GetLocalEnvVariables ).returns( ENV_VAR_MAP() );
|
||||
|
||||
TestNetlist( "opamp" );
|
||||
TestTranPoint( 0, { { "V(/in)", 0 }, { "V(/out)", 0 } } );
|
||||
TestTranPoint( 250e-6, { { "V(/in)", 500e-3 }, { "V(/out)", 1 } } );
|
||||
TestTranPoint( 500e-6, { { "V(/in)", 0 }, { "V(/out)", 0 } } );
|
||||
TestTranPoint( 750e-6, { { "V(/in)", -500e-3 }, { "V(/out)", -1 } } );
|
||||
TestTranPoint( 1e-3, { { "V(/in)", 0 }, { "V(/out)", 0 } } );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( NpnCeAmp )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
// This test intentionally uses non-inferred voltage sources to test them.
|
||||
|
||||
TestNetlist( "npn_ce_amp" );
|
||||
TestTranPoint( 900e-6, { { "V(/in)", 0 }, { "V(/out)", 5.32 } } );
|
||||
TestTranPoint( 925e-6, { { "V(/in)", 10e-3 }, { "V(/out)", 5.30 } } );
|
||||
TestTranPoint( 950e-6, { { "V(/in)", 0 }, { "V(/out)", 5.88 } } );
|
||||
TestTranPoint( 975e-6, { { "V(/in)", -10e-3 }, { "V(/out)", 5.91 } } );
|
||||
TestTranPoint( 1e-3, { { "V(/in)", 0 }, { "V(/out)", 5.32 } } );
|
||||
}
|
||||
|
||||
// Incomplete. TODO.
|
||||
BOOST_AUTO_TEST_CASE( Rlc )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "rlc" );
|
||||
TestTranPoint( 9.43e-3, { { "V(/Vp)", -19e-3 }, { "I(Rs1)", 19e-3 } } );
|
||||
TestTranPoint( 9.74e-3, { { "V(/Vp)", 19e-3 }, { "I(Rs1)", -19e-3 } } );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( Potentiometers )
|
||||
{
|
||||
TestNetlist( "potentiometers" );
|
||||
TestOpPoint( 0.5, "V(/out1)" );
|
||||
TestOpPoint( 0.7, "V(/out2)" );
|
||||
TestOpPoint( 0.9, "V(/out3)" );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( Tlines )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "tlines" );
|
||||
TestTranPoint( 910e-6, { { "V(/z0_in)", 1 }, { "V(/z0_out)", 0 },
|
||||
{ "V(/rlgc_in)", 1 }, { "V(/rlgc_out)", 0 } } );
|
||||
TestTranPoint( 970e-6, { { "V(/z0_in)", 0 }, { "V(/z0_out)", 1 },
|
||||
{ "V(/rlgc_in)", 0 }, { "V(/rlgc_out)", 1 } } );
|
||||
}
|
||||
|
||||
|
||||
/*BOOST_AUTO_TEST_CASE( Sources )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "sources", { "V(/vdc)", "V(/idc)",
|
||||
"V(/vsin)", "V(/isin)",
|
||||
"V(/vpulse)", "V(/ipulse)",
|
||||
"V(/vexp)", "V(/iexp)",
|
||||
"V(/vpwl)", "V(/ipwl)",
|
||||
"V(/vbehavioral)", "V(/ibehavioral)" } );
|
||||
|
||||
// TODO: Make some tests for random and noise sources, e.g. check their RMS or spectra.
|
||||
//"V(/vwhitenoise)", "V(/iwhitenoise)",
|
||||
//"V(/vpinknoise)", "V(/ipinknoise)",
|
||||
//"V(/vburstnoise)", "V(/iburstnoise)",
|
||||
//"V(/vranduniform)", "V(/iranduniform)",
|
||||
//"V(/vrandnormal)", "V(/iranduniform)",
|
||||
//"V(/vrandexp)", "V(/irandexp)",
|
||||
}*/
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( CmosNot )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "cmos_not" );
|
||||
TestTranPoint( 0, { { "V(/in)", 2.5 }, { "V(/out)", 2.64 } } );
|
||||
TestTranPoint( 250e-6, { { "V(/in)", 5 }, { "V(/out)", 0.013 } } );
|
||||
TestTranPoint( 500e-6, { { "V(/in)", 2.5 }, { "V(/out)", 2.64 } } );
|
||||
TestTranPoint( 750e-6, { { "V(/in)", 0 }, { "V(/out)", 5 } } );
|
||||
TestTranPoint( 1e-3, { { "V(/in)", 2.5 }, { "V(/out)", 2.64 } } );
|
||||
}
|
||||
|
||||
|
||||
/*BOOST_AUTO_TEST_CASE( InstanceParams )
|
||||
{
|
||||
// TODO.
|
||||
//TestNetlist( "instance_params", {} );
|
||||
}*/
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( FliegeFilter )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
// We test a multi-unit part here, as Fliege topology uses two op amps (power supply pins are a
|
||||
// third part).
|
||||
|
||||
TestNetlist( "fliege_filter" );
|
||||
TestACPoint( 0.8e3, { { "V(/in)", 1 }, { "V(/out)", 1 } } );
|
||||
TestACPoint( 1.061e3, { { "V(/in)", 1 }, { "V(/out)", 0 } } );
|
||||
TestACPoint( 1.2e3, { { "V(/in)", 1 }, { "V(/out)", 1 } } );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( Switches )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "switches" );
|
||||
TestTranPoint( 0.5e-3, { { "V(/inswv)", 0 }, { "V(/outswv)", 0 } } );
|
||||
TestTranPoint( 1.5e-3, { { "V(/inswv)", 1 }, { "V(/outswv)", 5 } } );
|
||||
TestTranPoint( 2.5e-3, { { "V(/inswv)", 0 }, { "V(/outswv)", 0 } } );
|
||||
|
||||
// TODO: Current switch, when it's fixed in Ngspice.
|
||||
}
|
||||
|
||||
|
||||
// This test is sometimes failing on certain platforms for unknown reasons
|
||||
// Disabling it for now so that it doesn't prevent packages from building
|
||||
#if 0
|
||||
BOOST_AUTO_TEST_CASE( Directives )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "directives" );
|
||||
TestTranPoint( 9.25e-3, { { "V(/in)", 1 }, { "V(/out)", -900e-3 }, { "I(XR1)", 1e-3 } } );
|
||||
TestTranPoint( 9.50e-3, { { "V(/in)", 0 }, { "V(/out)", 0 }, { "I(XR1)", 1e-3 } } );
|
||||
TestTranPoint( 9.75e-3, { { "V(/in)", -1 }, { "V(/out)", 900e-3 }, { "I(XR1)", 1e-3 } } );
|
||||
TestTranPoint( 10e-3, { { "V(/in)", 0 }, { "V(/out)", 0 }, { "I(XR1)", 1e-3 } } );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( LegacyLaserDriver )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
|
||||
TestNetlist( "legacy_laser_driver" );
|
||||
|
||||
if( m_abort )
|
||||
return;
|
||||
|
||||
// Test D1 current before the pulse
|
||||
TestTranPoint( 95e-9, { { "I(D1)", 0 } } );
|
||||
// Test D1 current during the pulse
|
||||
TestTranPoint( 110e-9, { { "I(D1)", 0.770 } }, 0.1 );
|
||||
// Test D1 current after the pulse
|
||||
TestTranPoint( 150e-9, { { "I(D1)", 0 } } );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( LegacyPspice )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "legacy_pspice" );
|
||||
TestACPoint( 190, { { "V(/VIN)", pow( 10, -186e-3 / 20 ) },
|
||||
{ "V(VOUT)", pow( 10, 87e-3 / 20 ) } } );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( LegacyRectifier )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "legacy_rectifier" );
|
||||
TestTranPoint( 0, { { "V(/signal_in)", 0 },
|
||||
{ "V(/rect_out)", 0 } } );
|
||||
TestTranPoint( 9.75e-3, { { "V(/signal_in)", 1.5 },
|
||||
{ "V(/rect_out)", 823e-3 } } );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( LegacySallenKey )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "legacy_sallen_key" );
|
||||
|
||||
if( m_abort )
|
||||
return;
|
||||
|
||||
TestACPoint( 1, { { "V(/lowpass)", pow( 10, 0.0 / 20 ) } } );
|
||||
TestACPoint( 1e3, { { "V(/lowpass)", pow( 10, -2.9 / 20 ) } } );
|
||||
}
|
||||
|
||||
|
||||
/*BOOST_AUTO_TEST_CASE( LegacySources )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
TestNetlist( "legacy_sources", { "V(/vam)", "V(/iam)",
|
||||
"V(/vdc)", "V(/idc)",
|
||||
"V(/vexp)", "V(/iexp)",
|
||||
"V(/vpulse)", "V(/ipulse)",
|
||||
"V(/vpwl)", "V(/ipwl)",
|
||||
"V(/vsffm)", "V(/isffm)",
|
||||
"V(/vsin)", "V(/isin)" } );
|
||||
//"V(/vtrnoise)", "V(/itrnoise)",
|
||||
//"V(/vtrrandom)", "V(/itrrandom)" } );
|
||||
}*/
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( LegacyOpamp )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
// Amplifier_Operational:AD797 model is used to test symbols that have more pins than the model.
|
||||
|
||||
TestNetlist( "legacy_opamp" );
|
||||
TestTranPoint( 0, { { "V(/in)", 0 }, { "V(/out)", 0 } } );
|
||||
TestTranPoint( 250e-6, { { "V(/in)", 500e-3 }, { "V(/out)", 1 } } );
|
||||
TestTranPoint( 500e-6, { { "V(/in)", 0 }, { "V(/out)", 0 } } );
|
||||
TestTranPoint( 750e-6, { { "V(/in)", -500e-3 }, { "V(/out)", -1 } } );
|
||||
TestTranPoint( 1e-3, { { "V(/in)", 0 }, { "V(/out)", 0 } } );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
#include <boost/test/results_collector.hpp> // To check if the current test failed (to be moved?).
|
||||
#include <eeschema_test_utils.h>
|
||||
#include <netlist_exporter_spice.h>
|
||||
#include <sim/ngspice.h>
|
||||
#include <sim/spice_reporter.h>
|
||||
#include <wx/ffile.h>
|
||||
#include <mock_pgm_base.h>
|
||||
#include <locale_io.h>
|
||||
|
||||
// A relative max error accepted when comparing 2 values
|
||||
#define MAX_DEFAULT_REL_ERROR 2e-2
|
||||
|
||||
|
||||
class TEST_NETLIST_EXPORTER_SPICE_FIXTURE : public TEST_NETLIST_EXPORTER_FIXTURE<NETLIST_EXPORTER_SPICE>
|
||||
{
|
||||
public:
|
||||
class SPICE_TEST_REPORTER : public SPICE_REPORTER
|
||||
{
|
||||
public:
|
||||
SPICE_TEST_REPORTER( std::shared_ptr<wxString> aLog ) :
|
||||
m_log( std::move( aLog ) )
|
||||
{}
|
||||
|
||||
REPORTER& Report( const wxString& aText,
|
||||
SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
|
||||
{
|
||||
*m_log << aText << "\n";
|
||||
|
||||
// You can add a debug trace here.
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool HasMessage() const override { return false; }
|
||||
|
||||
void OnSimStateChange( SPICE_SIMULATOR* aObject, SIM_STATE aNewState ) override { }
|
||||
|
||||
private:
|
||||
std::shared_ptr<wxString> m_log;
|
||||
};
|
||||
|
||||
TEST_NETLIST_EXPORTER_SPICE_FIXTURE() :
|
||||
TEST_NETLIST_EXPORTER_FIXTURE<NETLIST_EXPORTER_SPICE>(),
|
||||
m_simulator( SPICE_SIMULATOR::CreateInstance( "ngspice" ) ),
|
||||
m_log( std::make_shared<wxString>() ),
|
||||
m_reporter( std::make_unique<SPICE_TEST_REPORTER>( m_log ) ),
|
||||
m_abort( false )
|
||||
{
|
||||
}
|
||||
|
||||
~TEST_NETLIST_EXPORTER_SPICE_FIXTURE()
|
||||
{
|
||||
using namespace boost::unit_test;
|
||||
|
||||
test_case::id_t id = framework::current_test_case().p_id;
|
||||
test_results results = results_collector.results( id );
|
||||
|
||||
// Output a log if the test has failed.
|
||||
BOOST_CHECK_MESSAGE( results.passed(), "\nNGSPICE LOG\n===========\n" << *m_log );
|
||||
}
|
||||
|
||||
wxFileName GetSchematicPath( const wxString& aBaseName ) override
|
||||
{
|
||||
wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
|
||||
fn.AppendDir( "spice_netlists" );
|
||||
fn.AppendDir( aBaseName );
|
||||
fn.SetName( aBaseName );
|
||||
fn.SetExt( KiCadSchematicFileExtension );
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
wxString GetNetlistPath( bool aTest = false ) override
|
||||
{
|
||||
wxFileName netFile = m_schematic.Prj().GetProjectFullName();
|
||||
|
||||
if( aTest )
|
||||
netFile.SetName( netFile.GetName() + "_test" );
|
||||
|
||||
netFile.SetExt( "spice" );
|
||||
return netFile.GetFullPath();
|
||||
}
|
||||
|
||||
void CompareNetlists() override
|
||||
{
|
||||
m_abort = false;
|
||||
|
||||
// Our simulator is actually Ngspice.
|
||||
NGSPICE* ngspice = dynamic_cast<NGSPICE*>( m_simulator.get() );
|
||||
BOOST_REQUIRE( ngspice );
|
||||
|
||||
ngspice->SetReporter( m_reporter.get() );
|
||||
|
||||
wxFFile file( GetNetlistPath( true ), "rt" );
|
||||
wxString netlist;
|
||||
|
||||
file.ReadAll( &netlist );
|
||||
|
||||
//ngspice->Init();
|
||||
ngspice->Command( "set ngbehavior=ps" );
|
||||
ngspice->Command( "setseed 1" );
|
||||
BOOST_REQUIRE( ngspice->LoadNetlist( std::string( netlist.ToUTF8() ) ) );
|
||||
BOOST_REQUIRE( ngspice->Run() );
|
||||
|
||||
// Test if ngspice cannot run a simulation (missing code models).
|
||||
// in this case the log contains "MIF-ERROR" and/or "Error: circuit not parsed"
|
||||
// when the simulation is not run the spice command "linearize" crashes.
|
||||
bool mif_error = m_log->Find( wxT( "MIF-ERROR" ) ) != wxNOT_FOUND;
|
||||
|
||||
BOOST_TEST_INFO( "Cannot run ngspice. test skipped. Missing code model files?" );
|
||||
BOOST_CHECK( !mif_error );
|
||||
|
||||
bool err_found = m_log->Find( wxT( "Error: circuit not parsed" ) ) != wxNOT_FOUND;
|
||||
|
||||
BOOST_TEST_INFO( "Cannot run ngspice. test skipped. Install error?" );
|
||||
BOOST_CHECK( !err_found );
|
||||
|
||||
if( mif_error || err_found )
|
||||
{
|
||||
m_abort = true;
|
||||
|
||||
// Still display the original netlist in this case.
|
||||
*m_log << "Original Netlist\n";
|
||||
*m_log << "----------------\n";
|
||||
*m_log << netlist << "\n";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to make sure that the number of points always the same.
|
||||
ngspice->Command( "linearize" );
|
||||
|
||||
|
||||
// Debug info.
|
||||
|
||||
// Display all vectors.
|
||||
*m_log << "\n";
|
||||
ngspice->Command( "echo Available Vectors" );
|
||||
ngspice->Command( "echo -----------------" );
|
||||
ngspice->Command( "display" );
|
||||
|
||||
// Display the original netlist.
|
||||
*m_log << "\n";
|
||||
*m_log << "Original Netlist\n";
|
||||
*m_log << "----------------\n";
|
||||
*m_log << netlist << "\n";
|
||||
|
||||
// Display the expanded netlist.
|
||||
ngspice->Command( "echo Expanded Netlist" );
|
||||
ngspice->Command( "echo ----------------" );
|
||||
ngspice->Command( "listing runnable" );
|
||||
}
|
||||
|
||||
void TestOpPoint( double aRefValue, const std::string& aVectorName,
|
||||
double aMaxRelError = MAX_DEFAULT_REL_ERROR )
|
||||
{
|
||||
BOOST_TEST_CONTEXT( "Vector name: " << aVectorName )
|
||||
{
|
||||
NGSPICE* ngspice = static_cast<NGSPICE*>( m_simulator.get() );
|
||||
|
||||
std::vector<double> vector = ngspice->GetRealPlot( aVectorName );
|
||||
|
||||
BOOST_REQUIRE_EQUAL( vector.size(), 1 );
|
||||
|
||||
double maxError = abs( aRefValue * aMaxRelError );
|
||||
BOOST_CHECK_LE( abs( vector[0] - aRefValue ), aMaxRelError );
|
||||
}
|
||||
}
|
||||
|
||||
void TestPoint( const std::string& aXVectorName, double aXValue,
|
||||
const std::map<const std::string, double> aTestVectorsAndValues,
|
||||
double aMaxRelError = MAX_DEFAULT_REL_ERROR )
|
||||
{
|
||||
// The default aMaxRelError is fairly large because we have some problems with determinism
|
||||
// in QA pipeline. We don't need to fix this for now because, if this has to be fixed in
|
||||
// the first place, this has to be done from Ngspice's side.
|
||||
|
||||
BOOST_TEST_CONTEXT( "X vector name: " << aXVectorName << ", X value: " << aXValue )
|
||||
{
|
||||
NGSPICE* ngspice = static_cast<NGSPICE*>( m_simulator.get() );
|
||||
|
||||
std::vector<double> xVector = ngspice->GetRealPlot( aXVectorName );
|
||||
std::size_t i = 0;
|
||||
|
||||
for(; i < xVector.size(); ++i )
|
||||
{
|
||||
double inf = std::numeric_limits<double>::infinity();
|
||||
|
||||
double leftDelta = ( aXValue - ( i >= 1 ? xVector[i - 1] : -inf ) );
|
||||
double middleDelta = ( aXValue - xVector[i] );
|
||||
double rightDelta = ( aXValue - ( i < xVector.size() - 1 ? xVector[i + 1] : inf ) );
|
||||
|
||||
// Check if this point is the closest one.
|
||||
if( abs( middleDelta ) <= abs( leftDelta )
|
||||
&& abs( middleDelta ) <= abs( rightDelta ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_REQUIRE_LT( i, xVector.size() );
|
||||
|
||||
for( auto& [vectorName, refValue] : aTestVectorsAndValues )
|
||||
{
|
||||
std::vector<double> yVector = ngspice->GetMagPlot( vectorName );
|
||||
|
||||
BOOST_REQUIRE_GE( yVector.size(), i + 1 );
|
||||
|
||||
BOOST_TEST_CONTEXT( "Y vector name: " << vectorName
|
||||
<< ", Ref value: " << refValue
|
||||
<< ", Actual value: " << yVector[i] )
|
||||
{
|
||||
double maxError = abs( refValue * aMaxRelError );
|
||||
|
||||
if( maxError == 0 )
|
||||
{
|
||||
// If refValue is 0, we need a obtain the max. error differently.
|
||||
maxError = aMaxRelError;
|
||||
}
|
||||
|
||||
BOOST_CHECK_LE( abs( yVector[i] - refValue ), maxError );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestTranPoint( double aTime,
|
||||
const std::map<const std::string, double> aTestVectorsAndValues,
|
||||
double aMaxRelError = MAX_DEFAULT_REL_ERROR )
|
||||
{
|
||||
TestPoint( "time", aTime, aTestVectorsAndValues, aMaxRelError );
|
||||
}
|
||||
|
||||
void TestACPoint( double aFrequency,
|
||||
const std::map<const std::string, double> aTestVectorsAndValues,
|
||||
double aMaxRelError = MAX_DEFAULT_REL_ERROR )
|
||||
{
|
||||
TestPoint( "frequency", aFrequency, aTestVectorsAndValues, aMaxRelError );
|
||||
}
|
||||
|
||||
wxString GetResultsPath( bool aTest = false )
|
||||
{
|
||||
wxFileName netlistPath( GetNetlistPath( aTest ) );
|
||||
netlistPath.SetExt( "csv" );
|
||||
|
||||
return netlistPath.GetFullPath();
|
||||
}
|
||||
|
||||
unsigned GetNetlistOptions() override
|
||||
{
|
||||
return NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES
|
||||
| NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS
|
||||
| NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS
|
||||
| NETLIST_EXPORTER_SPICE::OPTION_ADJUST_INCLUDE_PATHS
|
||||
| NETLIST_EXPORTER_SPICE::OPTION_SIM_COMMAND;
|
||||
}
|
||||
|
||||
std::shared_ptr<SPICE_SIMULATOR> m_simulator;
|
||||
std::shared_ptr<wxString> m_log;
|
||||
std::unique_ptr<SPICE_TEST_REPORTER> m_reporter;
|
||||
bool m_abort; // set to true to force abort durint a test
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
icon_qa_spice ICON "../../resources/bitmaps_png/icons/icon_eeschema.ico"
|
||||
|
||||
#define RC_VER_FILE_DESCRIPTION "KiCad QA Spice " KICAD_WIN32_RC_PRODVER_STR
|
||||
#define RC_VER_INTERNALNAME "qa_spice"
|
||||
#define RC_VER_ORIGINALFILENAME "qa_spice.exe"
|
||||
|
||||
#include "kiwin32.rc"
|
Loading…
Reference in New Issue