32#include <fmt/format.h> 
   33#include <wx/wfstream.h> 
   34#include <wx/stdstream.h> 
   36#include <wx/clipbrd.h> 
   58#include <magic_enum.hpp> 
   63    int res = 
static_cast<int>( aFirst ) | 
static_cast<int>( aSecond);
 
 
  124    void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) 
override;
 
 
  175                menu.AppendSeparator();
 
  176                menu.Append( 
MYID_FOURIER, 
_( 
"Perform Fourier Analysis..." ) );
 
  179            menu.AppendSeparator();
 
  182            menu.AppendSeparator();
 
  185            m_grid->PopupMenu( &menu );
 
  192        menu.AppendSeparator();
 
  194        wxString msg = 
m_grid->GetColLabelValue( 
m_grid->GetNumberCols() - 1 );
 
  196        menu.AppendSeparator();
 
  199        m_grid->PopupMenu( &menu );
 
  205        m_grid->PopupMenu( &menu );
 
 
  212    std::vector<wxString> signals;
 
  214    wxGridCellCoordsArray cells1 = 
m_grid->GetSelectionBlockTopLeft();
 
  215    wxGridCellCoordsArray cells2 = 
m_grid->GetSelectionBlockBottomRight();
 
  217    for( 
size_t i = 0; i < cells1.Count(); i++ )
 
  221            for( 
int j = cells1[i].GetRow(); j < cells2[i].GetRow() + 1; j++ )
 
  223                signals.push_back( 
m_grid->GetCellValue( j, cells1[i].GetCol() ) );
 
  228    wxGridCellCoordsArray cells3 = 
m_grid->GetSelectedCells();
 
  230    for( 
size_t i = 0; i < cells3.Count(); i++ )
 
  233            signals.push_back( 
m_grid->GetCellValue( cells3[i].GetRow(), cells3[i].GetCol() ) );
 
  236    if( signals.size() < 1 )
 
  239    auto addMeasurement =
 
  240            [
this]( 
const wxString& cmd, wxString signal )
 
  242                if( signal.EndsWith( 
_( 
" (phase)" ) ) )
 
  245                if( signal.EndsWith( 
_( 
" (gain)" ) ) || signal.EndsWith( 
_( 
" (amplitude)" ) ) )
 
  247                    signal = signal.Left( signal.length() - 7 );
 
  249                    if( signal.Upper().StartsWith( wxS( 
"V(" ) ) )
 
  250                        signal = wxS( 
"vdb" ) + signal.Mid( 1 );
 
  253                m_parent->AddMeasurement( cmd + wxS( 
" " ) + signal );
 
  258        for( 
const wxString& signal : signals )
 
  259            addMeasurement( wxS( 
"MIN" ), signal );
 
  263        for( 
const wxString& signal : signals )
 
  264            addMeasurement( wxS( 
"MAX" ), signal );
 
  268        for( 
const wxString& signal : signals )
 
  269            addMeasurement( wxS( 
"AVG" ), signal );
 
  273        for( 
const wxString& signal : signals )
 
  274            addMeasurement( wxS( 
"RMS" ), signal );
 
  278        for( 
const wxString& signal : signals )
 
  279            addMeasurement( wxS( 
"PP" ), signal );
 
  283        for( 
const wxString& signal : signals )
 
  284            addMeasurement( wxS( 
"MIN_AT" ), signal );
 
  288        for( 
const wxString& signal : signals )
 
  289            addMeasurement( wxS( 
"MAX_AT" ), signal );
 
  293        for( 
const wxString& signal : signals )
 
  294            addMeasurement( wxS( 
"INTEG" ), signal );
 
  299        wxString fundamental = wxT( 
"1K" );
 
  301        if( signals.size() == 1 )
 
  302            title.Printf( 
_( 
"Fourier Analysis of %s" ), signals[0] );
 
  304            title = 
_( 
"Fourier Analyses of Multiple Signals" );
 
  314        for( 
const wxString& signal : signals )
 
  315            m_parent->DoFourier( signal, fundamental );
 
  322        for( 
const wxString& signal : signals )
 
  330        if( wxTheClipboard->Open() )
 
  332            wxTheClipboard->SetData( 
new wxTextDataObject( txt ) );
 
  333            wxTheClipboard->Flush(); 
 
  334            wxTheClipboard->Close();
 
 
  359    void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) 
override;
 
 
  379        menu.AppendSeparator();
 
 
  389            [
this]( 
int row ) -> wxString
 
  393                if( signal.EndsWith( 
"[2 - 1]" ) )
 
  394                    signal = signal.Left( signal.length() - 7 );
 
  405        if( formatDialog.
ShowModal() == wxID_OK )
 
  407            for( 
int row = 0; row < 
m_grid->GetNumberRows(); ++row )
 
  409                if( getSignalName( row ) == getSignalName( 
m_menuRow ) )
 
  410                    m_parent->SetCursorFormat( row, axis, format );
 
 
  432    void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) 
override;
 
 
  458    menu.AppendSeparator();
 
 
  471        if( formatDialog.
ShowModal() == wxID_OK )
 
  480        std::vector<int> measurements;
 
  482        wxGridCellCoordsArray cells1 = 
m_grid->GetSelectionBlockTopLeft();
 
  483        wxGridCellCoordsArray cells2 = 
m_grid->GetSelectionBlockBottomRight();
 
  485        for( 
size_t i = 0; i < cells1.Count(); i++ )
 
  489                for( 
int j = cells1[i].GetRow(); j < cells2[i].GetRow() + 1; j++ )
 
  490                    measurements.push_back( j );
 
  494        wxGridCellCoordsArray cells3 = 
m_grid->GetSelectedCells();
 
  496        for( 
size_t i = 0; i < cells3.Count(); i++ )
 
  499                measurements.push_back( cells3[i].GetRow() );
 
  502        if( measurements.size() < 1 )
 
  507        sort( measurements.begin(), measurements.end(), std::greater<>() );
 
  509        for( 
int row : measurements )
 
 
  529        m_frame->m_SuppressGridEvents++;
 
 
  534        m_frame->m_SuppressGridEvents--;
 
 
 
  542#define ID_SIM_REFRESH 10207 
  543#define REFRESH_INTERVAL 50    
  569    wxGridCellAttr* attr = 
new wxGridCellAttr;
 
  573    attr = 
new wxGridCellAttr;
 
  577    attr = 
new wxGridCellAttr;
 
  581    attr = 
new wxGridCellAttr;
 
  587    attr = 
new wxGridCellAttr;
 
  597            [&]( wxTimerEvent& aEvent )
 
  606#ifndef wxHAS_NATIVE_TABART 
 
  626        m_cursorFormat[0] = { 3, wxS( 
"~s" ) };
 
  627        m_cursorFormat[1] = { 3, wxS( 
"~V" ) };
 
  638        for( 
size_t index2 = 0; index2 < std::size( 
m_cursorFormats[0] ); index2++ )
 
  654        maxCursor.Replace( 
_( 
"Cursor " ), 
"" );
 
  656        int tmpMax = wxAtoi( maxCursor );
 
  658        if( nameMax < tmpMax )
 
 
  668    std::vector<SPICE_VALUE_FORMAT> tmp;
 
  680    wxGridCellAttr* attr = 
new wxGridCellAttr;
 
 
  700        for( 
int i = 0; i < rows; i++ )
 
  702            if( 
m_signalsGrid->GetCellValue( i, col - 1 ) == wxS( 
"1" ) )
 
  705                wxGridEvent aDummy( wxID_ANY, wxEVT_GRID_CELL_CHANGED, 
m_signalsGrid, i, col - 1 );
 
 
  725    for( 
int ii = 0; ii < static_cast<int>( 
m_plotNotebook->GetPageCount() ); ++ii )
 
  729            simTab->OnLanguageChanged();
 
  731            wxString pageTitle( 
simulator()->TypeToName( simTab->GetSimType(), 
true ) );
 
  732            pageTitle.Prepend( wxString::Format( 
_( 
"Analysis %u - " ), ii+1  ) );
 
  753        tuner->ShowChangedLanguage();
 
 
  793            simTab->ApplyPreferences( aPrefs );
 
 
  800    if( !
simulator()->Settings()->GetWorkbookFilename().IsEmpty() )
 
  812        if( !schTextSimCommand.IsEmpty() )
 
 
  845    std::sort( signals.begin(), signals.end(),
 
  846            []( 
const wxString& lhs, 
const wxString& rhs )
 
  849                if( lhs.Upper().StartsWith( 
'V' ) && !rhs.Upper().StartsWith( 
'V' ) )
 
  851                else if( !lhs.Upper().StartsWith( 
'V' ) && rhs.Upper().StartsWith( 
'V' ) )
 
  854                return StrNumCmp( lhs, rhs, true  ) < 0;
 
 
  871    std::vector<wxString> signals;
 
  875        wxStringTokenizer tokenizer( plotPanel->
GetSimCommand(), 
" \t\r\n", wxTOKEN_STRTOK );
 
  877        while( tokenizer.HasMoreTokens() && tokenizer.GetNextToken().Lower() != wxT( 
"fft" ) )
 
  880        while( tokenizer.HasMoreTokens() )
 
  881            signals.emplace_back( tokenizer.GetNextToken() );
 
  888        for( 
const wxString& signal : 
m_signals )
 
  889            signals.push_back( signal );
 
  893            if( simType == 
ST_AC )
 
  895                signals.push_back( signal + 
_( 
" (gain)" ) );
 
  896                signals.push_back( signal + 
_( 
" (phase)" ) );
 
  898            else if( simType == 
ST_SP )
 
  900                signals.push_back( signal + 
_( 
" (amplitude)" ) );
 
  901                signals.push_back( signal + 
_( 
" (phase)" ) );
 
  905                signals.push_back( signal );
 
  912    if( aFilter.IsEmpty() )
 
  913        aFilter = wxS( 
"*" );
 
  918    for( 
const wxString& signal : signals )
 
  920        if( matcher.
Find( signal.Upper() ) )
 
  929            wxGridCellAttr* attr = 
new wxGridCellAttr;
 
  930            attr->SetRenderer( 
new wxGridCellBoolRenderer() );
 
  932            attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
  937                attr = 
new wxGridCellAttr;
 
  942                attr = 
new wxGridCellAttr;
 
  946                attr = 
new wxGridCellAttr;
 
  954                        attr = 
new wxGridCellAttr;
 
  964                attr = 
new wxGridCellAttr;
 
  967                attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
  972                attr = 
new wxGridCellAttr;
 
  973                attr->SetRenderer( 
new wxGridCellBoolRenderer() );
 
  975                attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
  979                attr = 
new wxGridCellAttr;
 
  980                attr->SetRenderer( 
new wxGridCellBoolRenderer() );
 
  982                attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
  990                        attr = 
new wxGridCellAttr;
 
  991                        attr->SetRenderer( 
new wxGridCellBoolRenderer() );
 
  993                        attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
 
 1012    wxString unconnected = wxString( wxS( 
"unconnected-(" ) );
 
 1017    unconnected.Replace( 
'(', 
'_' );    
 
 1020            [&]( 
const wxString& aSignalName )
 
 1022                if( simType == 
ST_AC )
 
 1024                    m_signals.push_back( aSignalName + 
_( 
" (gain)" ) );
 
 1025                    m_signals.push_back( aSignalName + 
_( 
" (phase)" ) );
 
 1027                else if( simType == 
ST_SP )
 
 1029                    m_signals.push_back( aSignalName + 
_( 
" (amplitude)" ) );
 
 1030                    m_signals.push_back( aSignalName + 
_( 
" (phase)" ) );
 
 1047            if( netname == 
"GND" || netname == 
"0" || netname.StartsWith( unconnected ) )
 
 1051            addSignal( wxString::Format( wxS( 
"V(%s)" ), netname ) );
 
 1061            for( 
const std::string& 
name : item.model->SpiceGenerator().CurrentNames( item ) )
 
 1071            if( item.model->GetPinCount() >= 2 )
 
 1073                wxString 
name = item.model->SpiceGenerator().ItemName( item );
 
 1074                addSignal( wxString::Format( wxS( 
"P(%s)" ), 
name ) );
 
 1081        addSignal( wxS( 
"inoise_spectrum" ) );
 
 1082        addSignal( wxS( 
"onoise_spectrum" ) );
 
 1085    if( simType == 
ST_SP )
 
 1087        std::vector<std::string> portnums;
 
 1091            wxString 
name = item.model->SpiceGenerator().ItemName( item );
 
 1094            if( !
name.StartsWith( 
"V" ) )
 
 1097            std::string portnum = 
"";
 
 1099            if( 
const SIM_MODEL::PARAM* portnum_param = item.model->FindParam( 
"portnum" ) )
 
 1103                portnums.push_back( portnum );
 
 1106        for( 
const std::string& portnum1 : portnums )
 
 1108            for( 
const std::string& portnum2 : portnums )
 
 1110                addSignal( wxString::Format( wxS( 
"S_%s_%s" ), portnum1, portnum2 ) );
 
 1116    for( 
const wxString& directive : 
circuitModel()->GetDirectives() )
 
 1118        wxStringTokenizer directivesTokenizer( directive, 
"\r\n", wxTOKEN_STRTOK );
 
 1120        while( directivesTokenizer.HasMoreTokens() )
 
 1122            wxString line = directivesTokenizer.GetNextToken().Upper();
 
 1123            wxString directiveParams;
 
 1125            if( line.StartsWith( wxS( 
".SAVE" ), &directiveParams )
 
 1126                    || line.StartsWith( wxS( 
".PROBE" ), &directiveParams ) )
 
 1128                wxStringTokenizer paramsTokenizer( directiveParams, 
" \t", wxTOKEN_STRTOK );
 
 1130                while( paramsTokenizer.HasMoreTokens() )
 
 1131                    addSignal( paramsTokenizer.GetNextToken() );
 
 
 1154    wxString pageTitle( 
simulator()->TypeToName( simType, 
true ) );
 
 1155    pageTitle.Prepend( wxString::Format( 
_( 
"Analysis %u - " ), 
static_cast<unsigned int>( ++
m_plotNumber ) ) );
 
 
 1171#if defined( __WXOSX__ ) || wxCHECK_VERSION( 3, 3, 0 )  
 1172    wxPoint pos = aEvent.GetPosition();
 
 1173    wxRect  ctrlRect = 
m_filter->GetScreenRect();
 
 1174    int     buttonWidth = ctrlRect.GetHeight();         
 
 1176    if( 
m_filter->IsSearchButtonVisible() && pos.x < buttonWidth )
 
 1177        SetCursor( wxCURSOR_ARROW );
 
 1178    else if( 
m_filter->IsCancelButtonVisible() && pos.x > ctrlRect.GetWidth() - buttonWidth )
 
 1179        SetCursor( wxCURSOR_ARROW );
 
 1181        SetCursor( wxCURSOR_IBEAM );
 
 
 1188    return wxString::Format( wxS( 
"user%d" ), aUserDefinedSignalId );
 
 
 1197                                                       const wxString& aSignalName,
 
 1200    auto looksLikePower = []( 
const wxString& aExpression ) -> 
bool 
 1202        wxString exprUpper = aExpression.Upper();
 
 1204        if( exprUpper.Contains( wxS( 
":POWER" ) ) )
 
 1207        if( exprUpper.Find( 
'*' ) == wxNOT_FOUND )
 
 1210        if( !exprUpper.Contains( wxS( 
"V(" ) ) )
 
 1213        if( !exprUpper.Contains( wxS( 
"I(" ) ) )
 
 1219    std::map<wxString, int> suffixes;
 
 1235            wxUniChar firstChar = aSignalName.Upper()[0];
 
 1237            if( firstChar == 
'V' )
 
 1239            else if( firstChar == 
'I' )
 
 1241            else if( firstChar == 
'P' )
 
 1246    wxString 
name = aSignalName;
 
 1248    for( 
const auto& [ candidate, type ] : suffixes )
 
 1250        if( 
name.EndsWith( candidate ) )
 
 1252            name = 
name.Left( 
name.Length() - candidate.Length() );
 
 1255                *aTraceType |= type;
 
 1263        if( 
name == signal )
 
 1265            if( aTraceType && looksLikePower( signal ) )
 
 
 1289    int           row = aEvent.GetRow();
 
 1290    int           col = aEvent.GetCol();
 
 1298        if( 
text == wxS( 
"1" ) )
 
 1334        TRACE* activeTrace = 
nullptr;
 
 1336        if( 
text == wxS( 
"1" ) )
 
 1340            activeTrace = plotTab->
GetTrace( vectorName, traceType );
 
 1351            if( trace != activeTrace && trace->
HasCursor( 
id ) )
 
 
 1374    int      row = aEvent.GetRow();
 
 1375    int      col = aEvent.GetCol();
 
 1383        CURSOR* cursor1 = 
nullptr;
 
 1384        CURSOR* cursor2 = 
nullptr;
 
 1386        std::vector<CURSOR*> cursorsVec;
 
 1408                    cursorsVec.emplace_back( 
cursor );
 
 1410                    if( cursorName == ( wxString( 
"" ) << i ) && 
cursor )
 
 1411                        cursor->SetCoordX( value );
 
 1418        if( cursorName == wxS( 
"1" ) && cursor1 )
 
 1420        else if( cursorName == wxS( 
"2" ) && cursor2 )
 
 1422        else if( cursorName == 
_( 
"Diff" ) && cursor1 && cursor2 )
 
 1430        wxFAIL_MSG( wxT( 
"All other columns are supposed to be read-only!" ) );
 
 
 1463    int row = aEvent.GetRow();
 
 1464    int col = aEvent.GetCol();
 
 1474        wxFAIL_MSG( wxT( 
"All other columns are supposed to be read-only!" ) );
 
 1482    for( row = rowCount - 1; row >= 0; row-- )
 
 1492        int killRows = emptyRows - 1;
 
 1495    else if( emptyRows == 0 )
 
 
 1506        if( plotTab->GetLegendPosition() != plotTab->m_LastLegendPosition )
 
 1508            plotTab->m_LastLegendPosition = plotTab->GetLegendPosition();
 
 
 1531    static wxRegEx measureParamsRegEx( wxT( 
"^" 
 1535                                            "([a-zA-Z]*)\\(([^\\)]+)\\)" ) );
 
 1544    if( 
text.IsEmpty() )
 
 1551    wxString resultName = wxString::Format( wxS( 
"meas_result_%u" ), aRow );
 
 1552    wxString 
result = wxS( 
"?" );
 
 1554    if( measureParamsRegEx.Matches( 
text ) )
 
 1556        wxString           func = measureParamsRegEx.GetMatch( 
text, 1 ).Upper();
 
 1557        wxString           signalType = measureParamsRegEx.GetMatch( 
text, 2 ).Upper();
 
 1558        wxString           deviceName = measureParamsRegEx.GetMatch( 
text, 3 );
 
 1562        if( signalType.EndsWith( wxS( 
"DB" ) ) )
 
 1564            units = wxS( 
"dB" );
 
 1566        else if( signalType.StartsWith( 
'I' ) )
 
 1570        else if( signalType.StartsWith( 
'P' ) )
 
 1574            text = func + 
" " + deviceName + 
":power";
 
 1581        if( func.EndsWith( wxS( 
"_AT" ) ) )
 
 1584                units = wxS( 
"Hz" );
 
 1588        else if( func.StartsWith( wxS( 
"INTEG" ) ) )
 
 1593                    if ( signalType.StartsWith( 
'P' ) )
 
 1596                        units += wxS( 
".s" );
 
 1606                    units += wxS( 
"·Hz" );
 
 1614                    units += wxS( 
"·?" );
 
 1627        wxString cmd = wxString::Format( wxS( 
"meas %s %s %s" ), simType, resultName, 
text );
 
 1633        if( resultVec.size() > 0 )
 
 
 1648                                         "the value of a passive R, L, C model or voltage or " 
 1649                                         "current source." ) );
 
 1653    wxString ref = aSymbol->
GetRef( &aSheetPath );
 
 1658        if( tuner->GetSymbolRef() == ref )
 
 
 1681                                           const wxString& aRef, 
const wxString& aValue )
 
 1689                                   + wxString::Format( 
_( 
"%s not found" ), aRef ) );
 
 1696    std::vector<EMBEDDED_FILES*> embeddedFilesStack;
 
 1697    embeddedFilesStack.push_back( 
m_schematicFrame->Schematic().GetEmbeddedFiles() );
 
 1700        embeddedFilesStack.push_back( symbolEmbeddedFiles );
 
 1711                                   + wxString::Format( 
_( 
"%s is not tunable" ), aRef ) );
 
 
 1783    wxString cmd = wxString::Format( wxS( 
"fourier %s %s" ),
 
 
 1801        m_simConsole->AppendText( 
_( 
"Error: no current simulation.\n" ) );
 
 1810        m_simConsole->AppendText( 
_( 
"Error: simulation type not defined.\n" ) );
 
 1816        m_simConsole->AppendText( 
_( 
"Error: simulation type doesn't support plotting.\n" ) );
 
 1823        if( simType == 
ST_AC )
 
 1828        else if( simType == 
ST_SP )
 
 1838        plotTab->GetPlotWin()->UpdateAll();
 
 
 1860            if( aNewSignals.count( 
id ) == 0 )
 
 1865                        plotTab->
DeleteTrace( vectorName, traceType | subType );
 
 1870                        plotTab->
DeleteTrace( vectorName, traceType | subType );
 
 1883                        if( 
TRACE* trace = plotTab->
GetTrace( vectorName, traceType | subType ) )
 
 1884                            trace->SetName( aNewSignals.at( 
id ) );
 
 1891                        if( 
TRACE* trace = plotTab->
GetTrace( vectorName, traceType | subType ) )
 
 1892                            trace->SetName( aNewSignals.at( 
id ) );
 
 1897                    if( 
TRACE* trace = plotTab->
GetTrace( vectorName, traceType ) )
 
 1898                        trace->SetName( aNewSignals.at( 
id ) );
 
 
 1932    wxString simVectorName = aVectorName;
 
 1935        simVectorName = simVectorName.AfterFirst( 
'(' ).BeforeLast( 
')' ) + wxS( 
":power" );
 
 1940        simulator()->
Command( wxString::Format( wxT( 
"print %s" ), aVectorName ).ToStdString() );
 
 1945    std::vector<double> data_x;
 
 1946    std::vector<double> data_y;
 
 1948    if( !aDataX || aClearData )
 
 1952    if( aDataX->empty() && !aClearData )
 
 1954        wxString xAxisName( 
simulator()->GetXAxis( simType ) );
 
 1956        if( xAxisName.IsEmpty() )
 
 1962    unsigned int size = aDataX->size();
 
 1972            wxFAIL_MSG( wxT( 
"Plot type missing AC_PHASE or AC_MAG bit" ) );
 
 1981            wxFAIL_MSG( wxT( 
"Plot type missing AC_PHASE or SPT_SP_AMP bit" ) );
 
 1996        wxFAIL_MSG( wxT( 
"Unhandled plot type" ) );
 
 2001    size_t          sweepSize = std::numeric_limits<size_t>::max();
 
 2003    if( simType == 
ST_DC 
 2010        sweepSize = aDataX->size() / sweepCount;
 
 2027                size_t sweepSizeMulti = traceData.
xValues.size();
 
 2028                size_t runCount = traceData.
yValues.size();
 
 2030                if( sweepSizeMulti > 0 && runCount > 0 )
 
 2032                    std::vector<double> combinedX;
 
 2033                    std::vector<double> combinedY;
 
 2035                    combinedX.reserve( sweepSizeMulti * runCount );
 
 2036                    combinedY.reserve( sweepSizeMulti * runCount );
 
 2038                    for( 
const std::vector<double>& runY : traceData.
yValues )
 
 2040                        if( runY.size() != sweepSizeMulti )
 
 2043                        combinedX.insert( combinedX.end(), traceData.
xValues.begin(), traceData.
xValues.end() );
 
 2044                        combinedY.insert( combinedY.end(), runY.begin(), runY.end() );
 
 2049                        if( combinedY.size() >= combinedX.size() && sweepSizeMulti > 0 )
 
 2051                            int sweepCountCombined = combinedX.empty() ? 0 : 
static_cast<int>( combinedY.size() / sweepSizeMulti );
 
 2053                            if( sweepCountCombined > 0 )
 
 2056                                std::vector<wxString> labels;
 
 2057                                labels.reserve( sweepCountCombined );
 
 2059                                for( 
int i = 0; i < sweepCountCombined && i < (int)
m_multiRunState.steps.size(); ++i )
 
 2067                                            label += wxS( 
", " );
 
 2070                                        double value = it->second;
 
 2076                                    labels.push_back( label );
 
 2079                                aPlotTab->
SetTraceData( trace, combinedX, combinedY, sweepCountCombined, 
 
 2080                                                       sweepSizeMulti, 
true, labels );
 
 2093        if( data_y.size() >= size )
 
 2094            aPlotTab->
SetTraceData( trace, *aDataX, data_y, sweepCount, sweepSize );
 
 
 2104template <
typename T, 
typename U, 
typename R>
 
 2113    wxGridCellAttrPtr attr = 
m_signalsGrid->GetOrCreateCellAttrPtr( r, 
static_cast<int>( t ) );
 
 2115    if( 
TRACE* trace = plotTab ? plotTab->
GetTrace( vectorName, traceType ) : 
nullptr )
 
 2117        attr->SetReadOnly(); 
 
 2121            attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
 2124        if constexpr ( std::is_enum<T>::value )
 
 2128                m_signalsGrid->SetCellValue( r, 
static_cast<int>( t ), wxS( 
"1" ) );
 
 2132                if( !attr->HasRenderer() )
 
 2135                if( !attr->HasEditor() )
 
 2138                attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
 2139                attr->SetReadOnly( 
false );
 
 2148                if( !attr->HasRenderer() )
 
 2149                    attr->SetRenderer( 
new wxGridCellBoolRenderer() );
 
 2151                if( u > 0 && trace->HasCursor( u ) )
 
 2152                    m_signalsGrid->SetCellValue( r, 
static_cast<int>( t ), wxS( 
"1" ) );
 
 2154                    m_signalsGrid->SetCellValue( r, 
static_cast<int>( t ), wxEmptyString );
 
 2160        if constexpr ( std::is_enum<T>::value )
 
 2164                m_signalsGrid->SetCellValue( r, 
static_cast<int>( t ), wxEmptyString );
 
 2171                attr->SetEditor( 
nullptr );
 
 2172                attr->SetRenderer( 
nullptr );
 
 2173                attr->SetReadOnly();
 
 2174                m_signalsGrid->SetCellValue( r, 
static_cast<int>( t ), wxEmptyString );
 
 
 2183    for( 
int row = 0; row < 
m_signalsGrid->GetNumberRows(); ++row )
 
 
 2208    auto quoteNetNames = [&]( wxString aExpression ) -> wxString
 
 2210        std::vector<bool> mask( aExpression.length(), 
false );
 
 2212        auto isNetnameChar = []( wxUniChar aChar ) -> 
bool 
 2214            wxUint32 value = aChar.GetValue();
 
 2216            if( ( value >= 
'0' && value <= 
'9' ) || ( value >= 
'A' && value <= 
'Z' )
 
 2217                || ( value >= 
'a' && value <= 
'z' ) )
 
 2240            size_t pos = aExpression.find( netname );
 
 2242            while( pos != wxString::npos )
 
 2244                for( 
size_t i = 0; i < netname.length(); ++i )
 
 2246                    mask[pos + i] = 
true; 
 
 2248                pos = aExpression.find( netname, pos + 1 ); 
 
 2252        for( 
size_t i = 0; i < aExpression.length(); ++i )
 
 2254            if( !mask[i] || ( i > 0 && mask[i - 1] ) )
 
 2259            while( j < aExpression.length() )
 
 2267                if( isNetnameChar( aExpression[j] ) )
 
 2279        wxString quotedNetnames = 
"";
 
 2280        bool     startQuote = 
true;
 
 2283        for( 
size_t i = 0; i < aExpression.length(); i++ )
 
 2285            if( mask[i] && startQuote )
 
 2287                quotedNetnames = quotedNetnames + 
"\"";
 
 2290            else if( !mask[i] && !startQuote )
 
 2292                quotedNetnames = quotedNetnames + 
"\"";
 
 2295            wxString ch = aExpression[i];
 
 2296            quotedNetnames = quotedNetnames + ch;
 
 2301            quotedNetnames = quotedNetnames + 
"\"";
 
 2303        return quotedNetnames;
 
 2308        constexpr const char* cmd = 
"let user{} = {}";
 
 2310        simulator()->
Command( 
"echo " + fmt::format( cmd, 
id, signal.ToStdString() ) );
 
 2311        simulator()->
Command( fmt::format( cmd, 
id, quoteNetNames( signal ).ToStdString() ) );
 
 
 2323        wxString       ref = tuner->GetSymbolRef();
 
 2324        KIID           symbolId = tuner->GetSymbol( &sheetPath );
 
 2330            reporter.
Report( wxString::Format( 
_( 
"%s not found" ), ref ) );
 
 2338            reporter.
Report( wxString::Format( 
_( 
"%s is not tunable" ), ref ) );
 
 2347            floatVal = overrideIt->second;
 
 2349            floatVal = tuner->GetValue().ToDouble();
 
 
 2361    wxTextFile file( aPath );
 
 2366    wxString firstLine = file.GetFirstLine();
 
 2368    bool     legacy = firstLine.StartsWith( wxT( 
"version " ) ) || firstLine.ToLong( &
dummy );
 
 2393    wxFileName filename( aPath );
 
 
 2405    wxFFileInputStream fp( aPath, wxT( 
"rt" ) );
 
 2406    wxStdInputStream   fstream( fp );
 
 2413        nlohmann::json js = nlohmann::json::parse( fstream, 
nullptr, 
true, 
true );
 
 2415        std::map<SIM_PLOT_TAB*, nlohmann::json> traceInfo;
 
 2417        for( 
const nlohmann::json& tab_js : js[ 
"tabs" ] )
 
 2419            wxString simCommand;
 
 2423            for( 
const nlohmann::json& cmd : tab_js[ 
"commands" ] )
 
 2425                if( cmd == 
".kicad adjustpaths" )
 
 2427                else if( cmd == 
".save all" )
 
 2429                else if( cmd == 
".probe alli" )
 
 2431                else if( cmd == 
".probe allp" )
 
 2433                else if( cmd == 
".kicad esavenone" )
 
 2436                    simCommand += wxString( cmd.get<wxString>() ).Trim();
 
 2446                if( tab_js.contains( 
"traces" ) )
 
 2447                    traceInfo[plotTab] = tab_js[ 
"traces" ];
 
 2449                if( tab_js.contains( 
"measurements" ) )
 
 2451                    for( 
const nlohmann::json& m_js : tab_js[ 
"measurements" ] )
 
 2452                        plotTab->
Measurements().emplace_back( m_js[ 
"expr" ], m_js[ 
"format" ] );
 
 2456                plotTab->
ShowGrid( tab_js[ 
"showGrid" ] );
 
 2458                if( tab_js.contains( 
"fixedY1scale" ) )
 
 2460                    const nlohmann::json& scale_js = tab_js[ 
"fixedY1scale" ];
 
 2461                    plotTab->
SetY1Scale( 
true, scale_js[ 
"min" ], scale_js[ 
"max" ] );
 
 2465                if( tab_js.contains( 
"fixedY2scale" ) )
 
 2467                    const nlohmann::json& scale_js = tab_js[ 
"fixedY2scale" ];
 
 2468                    plotTab->
SetY2Scale( 
true, scale_js[ 
"min" ], scale_js[ 
"max" ] );
 
 2472                if( tab_js.contains( 
"fixedY3scale" ) )
 
 2475                    const nlohmann::json& scale_js = tab_js[ 
"fixedY3scale" ];
 
 2476                    plotTab->
SetY3Scale( 
true, scale_js[ 
"min" ], scale_js[ 
"max" ] );
 
 2480                if( tab_js.contains( 
"legend" ) )
 
 2482                    const nlohmann::json& legend_js = tab_js[ 
"legend" ];
 
 2487                if( tab_js.contains( 
"margins" ) )
 
 2489                    const nlohmann::json& margins_js = tab_js[ 
"margins" ];
 
 2491                                                       margins_js[ 
"right" ],
 
 2492                                                       margins_js[ 
"bottom" ],
 
 2493                                                       margins_js[ 
"left" ] );
 
 2500        if( js.contains( 
"user_defined_signals" ) )
 
 2502            for( 
const nlohmann::json& signal_js : js[ 
"user_defined_signals" ] )
 
 2508            m_simulatorFrame->LoadSimulator( simTab->GetSimCommand(), simTab->GetSimOptions() );
 
 2511                firstTab->SetLastSchTextSimCommand( js[
"last_sch_text_sim_command"] );
 
 2514        int tempCustomCursorsCnt = 0;
 
 2516        if( js.contains( 
"custom_cursors" ) )
 
 2517            tempCustomCursorsCnt = js[
"custom_cursors"];
 
 2519            tempCustomCursorsCnt = 2; 
 
 2529                        int aCursorId, 
const nlohmann::json& aCursor_js )
 
 2531                    if( aCursorId >= 1 )
 
 2535                        cursor->SetName( aSignalName );
 
 2536                        cursor->SetCoordX( aCursor_js[ 
"position" ] );
 
 2538                        aTrace->SetCursor( aCursorId, 
cursor );
 
 2542                    if( aCursorId == -1 )
 
 2553                                    aCursor_js[
"x_format"] );
 
 2555                                    aCursor_js[
"y_format"] );
 
 2565        for( 
const auto& [ plotTab, traces_js ] : traceInfo )
 
 2567            for( 
const nlohmann::json& trace_js : traces_js )
 
 2569                wxString signalName = trace_js[ 
"signal" ];
 
 2571                TRACE*   trace = plotTab->GetOrAddTrace( vectorName, trace_js[ 
"trace_type" ] );
 
 2575                    if( trace_js.contains( 
"cursorD" ) )
 
 2576                        addCursor( plotTab, trace, signalName, -1, trace_js[ 
"cursorD" ] );
 
 2578                    std::vector<const char*> aVec;
 
 2581                    for( 
int i = 1; i <= tempCustomCursorsCnt; i++ )
 
 2583                        wxString str = 
"cursor" + std::to_string( i );
 
 2584                        aVec.emplace_back( str.c_str() );
 
 2586                        if( trace_js.contains( aVec[i - 1] ) )
 
 2587                            addCursor( plotTab, trace, signalName, i, trace_js[aVec[i - 1]] );
 
 2590                    if( trace_js.contains( 
"color" ) )
 
 2593                        color.Set( wxString( trace_js[
"color"].get<wxString>() ) );
 
 2595                        plotTab->UpdateTraceStyle( trace );
 
 2600            plotTab->UpdatePlotColors();
 
 2603    catch( nlohmann::json::parse_error& error )
 
 2605        wxLogTrace( 
traceSettings, wxT( 
"Json parse error reading %s: %s" ), aPath, error.what() );
 
 2609    catch( nlohmann::json::type_error& error )
 
 2611        wxLogTrace( 
traceSettings, wxT( 
"Json type error reading %s: %s" ), aPath, error.what() );
 
 2615    catch( nlohmann::json::invalid_iterator& error )
 
 2617        wxLogTrace( 
traceSettings, wxT( 
"Json invalid_iterator error reading %s: %s" ), aPath, error.what() );
 
 2621    catch( nlohmann::json::out_of_range& error )
 
 2623        wxLogTrace( 
traceSettings, wxT( 
"Json out_of_range error reading %s: %s" ), aPath, error.what() );
 
 2629        wxLogTrace( 
traceSettings, wxT( 
"Error reading %s" ), aPath );
 
 
 2638    int cursorIdAfterD = aCursorId;
 
 2641        cursorIdAfterD = cursorIdAfterD - 1;
 
 2646        aTraceJs[
"cursor" + wxString( 
"" ) << aCursorId] =
 
 2647                nlohmann::json( { { 
"position", 
cursor->GetCoords().x },
 
 2654        aTraceJs[
"cursorD"] =
 
 
 2665    wxFileName filename = aPath;
 
 2670    file.Create( filename.GetFullPath(), 
true  );
 
 2672    if( !file.IsOpened() )
 
 2675    nlohmann::json tabs_js = nlohmann::json::array();
 
 2686        nlohmann::json commands_js = nlohmann::json::array();
 
 2693            commands_js.push_back( 
".kicad adjustpaths" );
 
 2696            commands_js.push_back( 
".save all" );
 
 2699            commands_js.push_back( 
".probe alli" );
 
 2702            commands_js.push_back( 
".probe allp" );
 
 2705            commands_js.push_back( 
".kicad esavenone" );
 
 2707        nlohmann::json tab_js = nlohmann::json(
 
 2709                                      { 
"commands", commands_js } } );
 
 2713            nlohmann::json traces_js = nlohmann::json::array();
 
 2715            auto findSignalName =
 
 2716                    [&]( 
const wxString& aVectorName ) -> wxString
 
 2718                        wxString vectorName;
 
 2721                        if( aVectorName.EndsWith( 
_( 
" (phase)" ) ) )
 
 2722                            suffix = 
_( 
" (phase)" );
 
 2723                        else if( aVectorName.EndsWith( 
_( 
" (gain)" ) ) )
 
 2724                            suffix = 
_( 
" (gain)" );
 
 2726                        vectorName = aVectorName.Left( aVectorName.Length() - suffix.Length() );
 
 2731                                return signal + suffix;
 
 2737            for( 
const auto& [
name, trace] : plotTab->GetTraces() )
 
 2739                nlohmann::json trace_js = nlohmann::json(
 
 2740                            { { 
"trace_type", (int) trace->GetType() },
 
 2741                              { 
"signal",     findSignalName( trace->GetDisplayName() ) },
 
 2747                if( trace->GetCursor( 1 ) || trace->GetCursor( 2 ) )
 
 2749                    trace_js[
"cursorD"] = nlohmann::json(
 
 2754                traces_js.push_back( trace_js );
 
 2757            nlohmann::json measurements_js = nlohmann::json::array();
 
 2759            for( 
const auto& [ 
measurement, format ] : plotTab->Measurements() )
 
 2761                measurements_js.push_back( nlohmann::json( { { 
"expr",   
measurement },
 
 2762                                                             { 
"format", format } } ) );
 
 2765            tab_js[ 
"traces" ]          = traces_js;
 
 2766            tab_js[ 
"measurements" ]    = measurements_js;
 
 2767            tab_js[ 
"dottedSecondary" ] = plotTab->GetDottedSecondary();
 
 2768            tab_js[ 
"showGrid" ]        = plotTab->IsGridShown();
 
 2772            if( plotTab->GetY1Scale( &min, &max ) )
 
 2773                tab_js[ 
"fixedY1scale" ] = nlohmann::json( { { 
"min", min }, { 
"max", max } } );
 
 2775            if( plotTab->GetY2Scale( &min, &max ) )
 
 2776                tab_js[ 
"fixedY2scale" ] = nlohmann::json( { { 
"min", min }, { 
"max", max } } );
 
 2778            if( plotTab->GetY3Scale( &min, &max ) )
 
 2779                tab_js[ 
"fixedY3scale" ] = nlohmann::json( { { 
"min", min }, { 
"max", max } } );
 
 2781            if( plotTab->IsLegendShown() )
 
 2783                tab_js[ 
"legend" ] = nlohmann::json( { { 
"x", plotTab->GetLegendPosition().x },
 
 2784                                                       { 
"y", plotTab->GetLegendPosition().y } } );
 
 2787            mpWindow* plotWin = plotTab->GetPlotWin();
 
 2789            tab_js[ 
"margins" ] = nlohmann::json( { { 
"left",   plotWin->
GetMarginLeft() },
 
 2795        tabs_js.push_back( tab_js );
 
 2798    nlohmann::json userDefinedSignals_js = nlohmann::json::array();
 
 2801        userDefinedSignals_js.push_back( signal );
 
 2804    nlohmann::json js = nlohmann::json( { { 
"version",              7 },
 
 2805                                          { 
"tabs",                 tabs_js },
 
 2806                                          { 
"user_defined_signals", userDefinedSignals_js },
 
 2819    std::stringstream buffer;
 
 2820    buffer << std::setw( 2 ) << js << std::endl;
 
 2822    bool res = file.Write( buffer.str() );
 
 
 2849        wxFAIL_MSG( wxString::Format( wxS( 
"Unhandled simulation type: %d" ), (
int) aType ) );
 
 
 2869                                           &source, &
scale, &pts, &fStart, &fStop, &saveAll );
 
 
 2877                                      int& aSashPosition )
 
 2879    bool isShown = aPanel->IsShown();
 
 2882        aSashPosition = aSplitterWindow->GetSashPosition();
 
 2884    aPanel->Show( !isShown );
 
 2886    aSplitterWindow->SetSashInvisible( isShown );
 
 2887    aSplitterWindow->SetSashPosition( isShown ? -1 : aSashPosition, 
true );
 
 2889    aSplitterWindow->UpdateSize();
 
 2890    m_parent->Refresh();
 
 
 2927    for( 
size_t page = 0; page < 
m_plotNotebook->GetPageCount(); page++ )
 
 
 2972        std::vector<std::pair<wxString, wxString>>& measurements = plotTab->Measurements();
 
 2974        measurements.clear();
 
 
 3012        simulator()->
Command( 
"setplot " + simTab->GetSpicePlotName().ToStdString() );
 
 
 3026        for( 
const auto& [ 
measurement, format ] : plotTab->Measurements() )
 
 3034        if( plotTab->GetSimType() == 
ST_TRAN || plotTab->GetSimType() == 
ST_AC 
 3035            || plotTab->GetSimType() == 
ST_DC || plotTab->GetSimType() == 
ST_SP )
 
 
 3072    CURSOR*  cursor1 = 
nullptr;
 
 3073    wxString cursor1Name;
 
 3074    wxString cursor1Units;
 
 3075    CURSOR*  cursor2 = 
nullptr;
 
 3076    wxString cursor2Name;
 
 3077    wxString cursor2Units;
 
 3080            [&]( 
TRACE* aTrace ) -> wxString
 
 3101            [&]( 
TRACE* aTrace ) -> wxString
 
 3122            [
this]( 
double aValue, 
int aCursorId, 
int aCol ) -> wxString
 
 3124                if( ( !
m_simulatorFrame->SimFinished() && aCol == 1 ) || std::isnan( aValue ) )
 
 3135            cursor1Name = getNameY( trace );
 
 3136            cursor1Units = getUnitsY( trace );
 
 3138            wxRealPoint coords = 
cursor->GetCoords();
 
 3158            cursor2Name = getNameY( trace );
 
 3159            cursor2Units = getUnitsY( trace );
 
 3161            wxRealPoint coords = 
cursor->GetCoords();
 
 3176    if( cursor1 && cursor2 && cursor1Units == cursor2Units )
 
 3185            signal = wxString::Format( wxS( 
"%s[2 - 1]" ), cursor2->
GetName() );
 
 3187            signal = wxString::Format( wxS( 
"%s - %s" ), cursor2->
GetName(), cursor1->
GetName() );
 
 3198    wxString valColName = 
_( 
"Value" );
 
 3200    if( !cursor1Name.IsEmpty() )
 
 3202        if( cursor2Name.IsEmpty() || cursor1Name == cursor2Name )
 
 3203            valColName = cursor1Name;
 
 3205    else if( !cursor2Name.IsEmpty() )
 
 3207        valColName = cursor2Name;
 
 3221                    wxString cursName = getNameY( trace );
 
 3222                    wxString cursUnits = getUnitsY( trace );
 
 3224                    wxRealPoint coords = 
cursor->GetCoords();
 
 3239                    valColName = 
_( 
"Value" );
 
 3241                    if( !cursName.IsEmpty()
 
 3244                        valColName = cursName;
 
 
 3265        plotTab->ResetScales( 
true );
 
 
 3287    std::vector<wxString> signals;
 
 3289    for( 
const std::string& vec : 
simulator()->AllVectors() )
 
 3290        signals.emplace_back( vec );
 
 
 3298    std::vector<wxString> signals;
 
 3300    for( 
const wxString& signal : 
m_signals )
 
 3301        signals.emplace_back( signal );
 
 3304        signals.emplace_back( signal );
 
 
 3322    bool storeMultiRun = 
false;
 
 3328            storeMultiRun = 
true;
 
 3351        if( simType == 
ST_NOISE && aFinal )
 
 3353            m_simConsole->AppendText( 
_( 
"\n\nSimulation results:\n\n" ) );
 
 3362            for( 
const std::string& vec : 
simulator()->AllVectors() )
 
 3367                msg.Printf( wxS( 
"%s: %sV\n" ), vec, value );
 
 3378        wxCHECK_RET( plotTab, wxString::Format( wxT( 
"No SIM_PLOT_TAB for: %s" ),
 
 3379                                                magic_enum::enum_name( simType ) ) );
 
 3388        std::map<TRACE*, TRACE_INFO> traceMap;
 
 3391            traceMap[ trace ] = { wxEmptyString, 
SPT_UNKNOWN, 
false };
 
 3396        for( 
const wxString& signal : 
m_signals )
 
 3401            if( 
TRACE* trace = plotTab->
GetTrace( vectorName, traceType ) )
 
 3402                traceMap[ trace ] = { vectorName, traceType, 
false };
 
 3410            if( simType == 
ST_AC )
 
 3416                    if( 
TRACE* trace = plotTab->
GetTrace( vectorName, subType ) )
 
 3417                        traceMap[ trace ] = { vectorName, subType, !aFinal };
 
 3420            else if( simType == 
ST_SP )
 
 3426                    if( 
TRACE* trace = plotTab->
GetTrace( vectorName, subType ) )
 
 3427                        traceMap[trace] = { vectorName, subType, !aFinal };
 
 3432                if( 
TRACE* trace = plotTab->
GetTrace( vectorName, traceType ) )
 
 3433                    traceMap[ trace ] = { vectorName, traceType, !aFinal };
 
 3439        for( 
const auto& [ trace, traceInfo ] : traceMap )
 
 3441            if( traceInfo.Vector.IsEmpty() )
 
 3445        for( 
const auto& [ trace, 
info ] : traceMap )
 
 3447            std::vector<double> data_x;
 
 3449            if( !
info.Vector.IsEmpty() )
 
 3467    else if( simType == 
ST_OP && aFinal )
 
 3469        m_simConsole->AppendText( 
_( 
"\n\nSimulation results:\n\n" ) );
 
 3472        for( 
const std::string& vec : 
simulator()->AllVectors() )
 
 3476            if( val_list.empty() )
 
 3483            const size_t tab = 25; 
 
 3484            size_t       padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
 
 3488            case SPT_VOLTAGE: value.Append( wxS( 
"V" ) ); 
break;
 
 3489            case SPT_CURRENT: value.Append( wxS( 
"A" ) ); 
break;
 
 3490            case SPT_POWER:   value.Append( wxS( 
"W" ) ); 
break;
 
 3491            default:          value.Append( wxS( 
"?" ) ); 
break;
 
 3494            msg.Printf( wxT( 
"%s%s\n" ),
 
 3495                        ( signal + wxT( 
":" ) ).Pad( padding, wxUniChar( 
' ' ) ),
 
 3502                signal = signal.SubString( 2, signal.Length() - 2 );
 
 3505                signal += wxS( 
":power" );
 
 3507            m_schematicFrame->Schematic().SetOperatingPoint( signal, val_list.at( 0 ) );
 
 3510    else if( simType == 
ST_PZ && aFinal )
 
 3512        m_simConsole->AppendText( 
_( 
"\n\nSimulation results:\n\n" ) );
 
 
 3573    std::vector<TUNER_SLIDER*> multiTuners;
 
 3578            multiTuners.push_back( tuner );
 
 3581    if( multiTuners.empty() )
 
 3615    else if( tunersChanged )
 
 3624        for( 
const auto& entry : step.
overrides )
 
 
 3631        const std::vector<TUNER_SLIDER*>& aTuners )
 const 
 3633    std::vector<MULTI_RUN_STEP> steps;
 
 3635    if( aTuners.empty() )
 
 3638    std::vector<std::vector<double>> tunerValues;
 
 3639    tunerValues.reserve( aTuners.size() );
 
 3646        double startValue = tuner->GetMin().ToDouble();
 
 3647        double endValue = tuner->GetMax().ToDouble();
 
 3648        int    stepCount = std::max( 2, tuner->GetStepCount() );
 
 3653        double increment = ( endValue - startValue ) / 
static_cast<double>( stepCount - 1 );
 
 3655        std::vector<double> values;
 
 3656        values.reserve( stepCount );
 
 3658        for( 
int ii = 0; ii < stepCount; ++ii )
 
 3659            values.push_back( startValue + increment * ii );
 
 3661        tunerValues.push_back( std::move( values ) );
 
 3669    std::vector<double> currentValues( aTuners.size(), 0.0 );
 
 3671    auto generate = [&]( 
auto&& self, 
size_t depth ) -> 
void 
 3673        if( steps.size() >= 
static_cast<size_t>( limit ) )
 
 3676        if( depth == aTuners.size() )
 
 3680            for( 
size_t ii = 0; ii < aTuners.size(); ++ii )
 
 3681                step.
overrides.emplace( aTuners[ii], currentValues[ii] );
 
 3683            steps.push_back( std::move( step ) );
 
 3687        for( 
double value : tunerValues[depth] )
 
 3689            currentValues[depth] = value;
 
 3690            self( self, depth + 1 );
 
 3692            if( steps.size() >= 
static_cast<size_t>( limit ) )
 
 3697    generate( generate, 0 );
 
 
 3705    return fmt::format( 
"{}|{}", aVectorName.ToStdString(), aTraceType );
 
 
 3710                                             const std::vector<double>& aX,
 
 3711                                             const std::vector<double>& aY )
 
 3713    if( aX.empty() || aY.empty() )
 
 3724    if( trace.
xValues.size() != aX.size() )
 
 3729    if( trace.
yValues.size() <= index )
 
 3730        trace.
yValues.resize( index + 1 );
 
 
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
 
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
 
void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent) override
 
void doPopupSelection(wxCommandEvent &event) override
 
SIMULATOR_FRAME_UI * m_parent
 
CURSORS_GRID_TRICKS(SIMULATOR_FRAME_UI *aParent, WX_GRID *aGrid)
 
The SIMULATOR_FRAME holds the main user-interface for running simulations.
 
const wxRealPoint & GetCoords() const
 
void SetCoordX(double aValue)
 
bool Find(const wxString &aTerm, int &aMatchersTriggered, int &aPosition)
Look in all existing matchers, return the earliest match of any of the existing.
 
GRID_TRICKS(WX_GRID *aGrid)
 
virtual void doPopupSelection(wxCommandEvent &event)
 
virtual void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent)
 
WX_GRID * m_grid
I don't own the grid, but he owns me.
 
A color representation with 4 components: red, green, blue, alpha.
 
wxString ToCSSString() const
 
Hold a translatable error message and may be used when throwing exceptions containing a translated er...
 
const wxString What() const
 
void doPopupSelection(wxCommandEvent &event) override
 
void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent) override
 
SIMULATOR_FRAME_UI * m_parent
 
MEASUREMENTS_GRID_TRICKS(SIMULATOR_FRAME_UI *aParent, WX_GRID *aGrid)
 
static void ConvertToSpiceMarkup(wxString *aNetName)
Remove formatting wrappers and replace illegal spice net name characters with underscores.
 
@ OPTION_SAVE_ALL_CURRENTS
 
@ OPTION_SAVE_ALL_VOLTAGES
 
@ OPTION_SAVE_ALL_DISSIPATIONS
 
@ OPTION_ADJUST_INCLUDE_PATHS
 
@ OPTION_ADJUST_PASSIVE_VALS
 
const SPICE_ITEM * FindItem(const wxString &aRefName) const
Find and return the item corresponding to aRefName.
 
A singleton reporter that reports to nowhere.
 
virtual bool HasMessage() const
Returns true if any messages were reported.
 
Holds all the data relating to one schematic.
 
void ClearOperatingPoints()
Clear operating points from a .op simulation.
 
Schematic editor (Eeschema) main window.
 
Base class for any item which can be embedded within the SCHEMATIC container class,...
 
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
 
SCH_ITEM * ResolveItem(const KIID &aID) const
Fetch a SCH_ITEM by ID.
 
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SYMBOLs don't currently support embedded files, but their LIB_SYMBOL counterparts do.
 
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
 
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
 
void doPopupSelection(wxCommandEvent &event) override
 
void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent) override
 
SIMULATOR_FRAME_UI * m_parent
 
SIGNALS_GRID_TRICKS(SIMULATOR_FRAME_UI *aParent, WX_GRID *aGrid)
 
wxBoxSizer * m_sizerTuners
 
WX_GRID * m_measurementsGrid
 
wxSplitterWindow * m_splitterLeftRight
 
wxSplitterWindow * m_splitterMeasurements
 
wxTextCtrl * m_simConsole
 
wxSplitterWindow * m_splitterCursors
 
wxSplitterWindow * m_splitterPlotAndConsole
 
SIMULATOR_FRAME_UI_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
 
wxSplitterWindow * m_splitterSignals
 
wxAuiNotebook * m_plotNotebook
 
The SIMULATOR_FRAME_UI holds the main user-interface for running simulations.
 
SIM_TAB * NewSimTab(const wxString &aSimCommand)
Create a new simulation tab for a given simulation type.
 
std::string multiRunTraceKey(const wxString &aVectorName, int aTraceType) const
 
void SetUserDefinedSignals(const std::map< int, wxString > &aSignals)
 
void updatePlotCursors()
Update the cursor values (in the grid) and graphics (in the plot window).
 
void OnSimRefresh(bool aFinal)
 
void onPlotClose(wxAuiNotebookEvent &event) override
 
void CustomCursorsInit()
Init handler for custom cursors.
 
void recordMultiRunData(const wxString &aVectorName, int aTraceType, const std::vector< double > &aX, const std::vector< double > &aY)
 
std::vector< MULTI_RUN_STEP > calculateMultiRunSteps(const std::vector< TUNER_SLIDER * > &aTuners) const
 
int m_splitterTuneValuesSashPosition
 
void TogglePanel(wxPanel *aPanel, wxSplitterWindow *aSplitterWindow, int &aSashPosition)
A common toggler for the two main wxSplitterWindow s.
 
void onPlotChanged(wxAuiNotebookEvent &event) override
 
void rebuildSignalsGrid(wxString aFilter)
Rebuild the filtered list of signals in the signals grid.
 
std::vector< std::vector< SPICE_VALUE_FORMAT > > m_cursorFormatsDyn
 
void DoFourier(const wxString &aSignal, const wxString &aFundamental)
 
void rebuildMeasurementsGrid()
Rebuild the measurements grid for the current plot.
 
std::list< TUNER_SLIDER * > m_tuners
 
void rebuildSignalsList()
Rebuild the list of signals available from the netlist.
 
bool loadLegacyWorkbook(const wxString &aPath)
 
int m_splitterCursorsSashPosition
 
MULTI_RUN_STATE m_multiRunState
SPICE expressions need quoted versions of the netnames since KiCad allows '-' and '/' in netnames.
 
void ToggleSimSidePanel()
 
void UpdateMeasurement(int aRow)
Update a measurement in the measurements grid.
 
wxString getNoiseSource() const
 
std::vector< wxString > SimPlotVectors() const
 
unsigned int m_plotNumber
 
void SetSubWindowsSashSize()
Adjust the sash dimension of splitter windows after reading the config settings must be called after ...
 
void applyUserDefinedSignals()
Apply user-defined signals to the SPICE session.
 
SIM_PREFERENCES m_preferences
 
void DeleteMeasurement(int aRow)
Delete a row from the measurements grid.
 
SCH_EDIT_FRAME * m_schematicFrame
 
wxString vectorNameFromSignalName(SIM_PLOT_TAB *aPlotTab, const wxString &aSignalName, int *aTraceType)
Get the simulator output vector name for a given signal name and type.
 
void updateSignalsGrid()
Update the values in the signals grid.
 
int m_splitterLeftRightSashPosition
 
void onCursorsGridCellChanged(wxGridEvent &aEvent) override
 
void onPlotDragged(wxAuiNotebookEvent &event) override
 
std::vector< wxString > Signals() const
 
bool SaveWorkbook(const wxString &aPath)
Save plot, signal, cursor, measurement, etc.
 
bool hasMultiRunTrace(const wxString &aVectorName, int aTraceType) const
 
std::vector< wxString > m_signals
 
SIM_TAB * GetCurrentSimTab() const
Return the currently opened plot panel (or NULL if there is none).
 
void SaveCursorToWorkbook(nlohmann::json &aTraceJs, TRACE *aTrace, int aCursorId)
 
void updateMeasurementsFromGrid()
 
bool LoadWorkbook(const wxString &aPath)
Load plot, signal, cursor, measurement, etc.
 
SPICE_VALUE_FORMAT GetMeasureFormat(int aRow) const
Get/Set the format of a value in the measurements grid.
 
std::map< int, wxString > m_userDefinedSignals
 
void UpdateTunerValue(const SCH_SHEET_PATH &aSheetPath, const KIID &aSymbol, const wxString &aRef, const wxString &aValue)
Safely update a field of the associated symbol without dereferencing the symbol.
 
std::vector< wxString > m_netnames
 
void AddTrace(const wxString &aName, SIM_TRACE_TYPE aType)
Add a new trace to the current plot.
 
void onPlotClosed(wxAuiNotebookEvent &event) override
 
void RemoveTuner(TUNER_SLIDER *aTuner)
Remove an existing tuner.
 
void SaveSettings(EESCHEMA_SETTINGS *aCfg)
 
std::shared_ptr< SPICE_CIRCUIT_MODEL > circuitModel() const
 
void OnFilterText(wxCommandEvent &aEvent) override
 
void onMeasurementsGridCellChanged(wxGridEvent &aEvent) override
 
void DeleteCursor()
Deletes last m_signalsGrid "Cursor n" column, removes vector's m_cursorFormatsDyn last entry,...
 
void CreateNewCursor()
Creates a column at the end of m_signalsGrid named "Cursor n" ( n = m_customCursorsCnt ),...
 
void applyTuners()
Apply component values specified using tuner sliders to the current netlist.
 
bool loadJsonWorkbook(const wxString &aPath)
 
void clearMultiRunState(bool aClearTraces)
 
void OnFilterMouseMoved(wxMouseEvent &aEvent) override
 
void AddMeasurement(const wxString &aCmd)
Add a measurement to the measurements grid.
 
void onPlotChanging(wxAuiNotebookEvent &event) override
 
std::map< const TUNER_SLIDER *, double > m_tunerOverrides
 
std::shared_ptr< SPICE_SIMULATOR > simulator() const
 
void onPlotCursorUpdate(wxCommandEvent &aEvent)
 
void onSignalsGridCellChanged(wxGridEvent &aEvent) override
 
void InitWorkbook()
Load the currently active workbook stored in the project settings.
 
void ToggleDarkModePlots()
 
SIM_TRACE_TYPE getXAxisType(SIM_TYPE aType) const
Return X axis for a given simulation type.
 
void prepareMultiRunState()
 
void OnPlotSettingsChanged()
 
void signalsGridCursorUpdate(T t, U u, R r)
Updates m_signalsGrid cursor widget, column rendering and attributes.
 
void SetMeasureFormat(int aRow, const SPICE_VALUE_FORMAT &aFormat)
 
int m_splitterSignalsSashPosition
 
void OnSimReport(const wxString &aMsg)
 
void ApplyPreferences(const SIM_PREFERENCES &aPrefs)
Called when settings are changed via the common Preferences dialog.
 
const SPICE_CIRCUIT_MODEL * GetExporter() const
Return the netlist exporter object used for simulations.
 
int m_splitterPlotAndConsoleSashPosition
 
SIMULATOR_FRAME * m_simulatorFrame
 
void ShowChangedLanguage()
 
void AddTuner(const SCH_SHEET_PATH &aSheetPath, SCH_SYMBOL *aSymbol)
Add a tuner for a symbol.
 
bool IsSimSidePanelShown()
 
void OnUpdateUI(wxUpdateUIEvent &event) override
 
void updateTrace(const wxString &aVectorName, int aTraceType, SIM_PLOT_TAB *aPlotTab, std::vector< double > *aDataX=nullptr, bool aClearData=false)
Update a trace in a particular SIM_PLOT_TAB.
 
SIMULATOR_FRAME_UI(SIMULATOR_FRAME *aSimulatorFrame, SCH_EDIT_FRAME *aSchematicFrame)
 
SPICE_VALUE_FORMAT m_cursorFormats[3][2]
 
void LoadSettings(EESCHEMA_SETTINGS *aCfg)
 
The SIMULATOR_FRAME holds the main user-interface for running simulations.
 
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, const std::vector< SCH_PIN * > &aPins, REPORTER &aReporter)
 
void SetFilesStack(std::vector< EMBEDDED_FILES * > aFilesStack)
 
virtual const PARAM * GetTunerParam() const
 
const SPICE_GENERATOR & SpiceGenerator() const
 
void WriteFields(std::vector< SCH_FIELD > &aFields) const
 
void SetParamValue(int aParamIndex, const std::string &aValue, SIM_VALUE::NOTATION aNotation=SIM_VALUE::NOTATION::SI)
 
static void FillDefaultColorList(bool aWhiteBg)
Fills m_colorList by a default set of colors.
 
bool DeleteTrace(const wxString &aVectorName, int aTraceType)
 
wxString GetLabelY1() const
 
mpWindow * GetPlotWin() const
 
void ShowGrid(bool aEnable)
 
void SetTraceData(TRACE *aTrace, std::vector< double > &aX, std::vector< double > &aY, int aSweepCount, size_t aSweepSize, bool aIsMultiRun=false, const std::vector< wxString > &aMultiRunLabels={})
 
wxString GetUnitsY2() const
 
void SetY2Scale(bool aLock, double aMin, double aMax)
 
TRACE * GetTrace(const wxString &aVecName, int aType) const
 
wxString GetLabelX() const
 
const std::map< wxString, TRACE * > & GetTraces() const
 
wxString GetLabelY3() const
 
void SetY1Scale(bool aLock, double aMin, double aMax)
 
void SetY3Scale(bool aLock, double aMin, double aMax)
 
std::vector< std::pair< wxString, wxString > > & Measurements()
 
void UpdateTraceStyle(TRACE *trace)
Update plot colors.
 
void SetLegendPosition(const wxPoint &aPosition)
 
void ResetScales(bool aIncludeX)
Update trace line style.
 
void ShowLegend(bool aEnable)
 
wxString GetLabelY2() const
 
void EnableCursor(TRACE *aTrace, int aCursorId, const wxString &aSignalName)
 
wxString GetUnitsX() const
 
void EnsureThirdYAxisExists()
 
TRACE * GetOrAddTrace(const wxString &aVectorName, int aType)
 
void SetDottedSecondary(bool aEnable)
Draw secondary signal traces (current or phase) with dotted lines.
 
void ApplyPreferences(const SIM_PREFERENCES &aPrefs) override
 
wxString GetUnitsY1() const
 
void DisableCursor(TRACE *aTrace, int aCursorId)
Reset scale ranges to fit the current traces.
 
wxString GetUnitsY3() const
 
int GetSimOptions() const
 
SIM_TYPE GetSimType() const
 
const wxString & GetSimCommand() const
 
static bool IsPlottable(SIM_TYPE aSimType)
 
void SetSimOptions(int aOptions)
 
wxString GetLastSchTextSimCommand() const
 
void SetSpicePlotName(const wxString &aPlotName)
 
static std::string ToSpice(const std::string &aString)
 
Special netlist exporter flavor that allows one to override simulation commands.
 
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Return simulation type basing on a simulation command directive.
 
bool ParseNoiseCommand(const wxString &aCmd, wxString *aOutput, wxString *aRef, wxString *aSource, wxString *aScale, SPICE_VALUE *aPts, SPICE_VALUE *aFStart, SPICE_VALUE *aFStop, bool *aSaveAll)
 
wxString GetSchTextSimCommand()
Return simulation command directives placed in schematic sheets (if any).
 
SIM_TRACE_TYPE VectorToSignal(const std::string &aVector, wxString &aSignal) const
Return name of Spice dataset for a specific trace.
 
virtual std::string TunerCommand(const SPICE_ITEM &aItem, double aValue) const
 
wxString GetWorkbookFilename() const
 
void SetWorkbookFilename(const wxString &aFilename)
 
virtual bool Command(const std::string &aCmd)=0
Execute a Spice command as if it was typed into console.
 
static wxString TypeToName(SIM_TYPE aType, bool aShortName)
Return a string with simulation name based on enum.
 
std::shared_ptr< SPICE_SETTINGS > & Settings()
Return the simulator configuration settings.
 
virtual wxString CurrentPlotName() const =0
 
virtual std::vector< double > GetRealVector(const std::string &aName, int aMaxLen=-1)=0
Return a requested vector with real values.
 
virtual std::vector< double > GetGainVector(const std::string &aName, int aMaxLen=-1)=0
Return a requested vector with magnitude values.
 
virtual std::vector< double > GetPhaseVector(const std::string &aName, int aMaxLen=-1)=0
Return a requested vector with phase values.
 
Helper class to recognize Spice formatted values.
 
wxString ToString() const
Return string value as when converting double to string (e.g.
 
wxString ToSpiceString() const
Return string value in Spice format (e.g.
 
~SUPPRESS_GRID_CELL_EVENTS()
 
SUPPRESS_GRID_CELL_EVENTS(SIMULATOR_FRAME_UI *aFrame)
 
SIMULATOR_FRAME_UI * m_frame
 
void SetTraceColour(const wxColour &aColour)
 
bool HasCursor(int aCursorId)
 
CURSOR * GetCursor(int aCursorId)
 
Custom widget to handle quick component values modification and simulation on the fly.
 
wxString GetSymbolRef() const
 
A wrapper for reporting to a wxString object.
 
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
 
const wxString & GetMessages() const
 
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
 
wxString GetValue() const
 
const wxString & GetName() const
Get layer name.
 
const wxPen & GetPen() const
Get pen set for this layer.
 
Canvas for plotting mpLayer implementations.
 
int GetMarginLeft() const
 
void SetMargins(int top, int right, int bottom, int left)
Set window margins, creating a blank area where some kinds of layers cannot draw.
 
void UpdateAll()
Refresh display.
 
int GetMarginRight() const
 
int GetMarginBottom() const
 
bool AddLayer(mpLayer *layer, bool refreshDisplay=true)
Add a plot layer to the canvas.
 
void Fit() override
Set view to fit global bounding box of all plot layers and refresh display.
 
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
 
This file is part of the common library.
 
Abstract pattern-matching tool and implementations.
 
@ GRIDTRICKS_FIRST_CLIENT_ID
 
int m_SimulatorMultiRunCombinationLimit
Maximum number of tuner combinations simulated when using multi-run mode.
 
static const std::string WorkbookFileExtension
 
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
 
SIM_TYPE
< Possible simulation types
 
void sortSignals(std::vector< wxString > &signals)
 
wxString vectorNameFromSignalId(int aUserDefinedSignalId)
 
MEASUREMENTS_GIRD_COLUMNS
 
@ MYID_DELETE_MEASUREMENT
 
SIM_TRACE_TYPE operator|(SIM_TRACE_TYPE aFirst, SIM_TRACE_TYPE aSecond)
 
std::vector< FAB_LAYER_COLOR > dummy
 
wxString UnescapeString(const wxString &aSource)
 
int measurements_panel_height
 
SIM_PREFERENCES preferences
 
std::map< const TUNER_SLIDER *, double > overrides
 
std::vector< std::vector< double > > yValues
 
std::vector< double > xValues
 
Contains preferences pertaining to the simulator.
 
wxString result
Test unit parsing edge cases and error handling.
 
Definition of file extensions used in Kicad.