28#include <fmt/format.h>
29#include <wx/wfstream.h>
30#include <wx/stdstream.h>
32#include <wx/clipbrd.h>
34#include <wx/tokenzr.h>
55#include <magic_enum.hpp>
61 int res =
static_cast<int>( aFirst ) |
static_cast<int>( aSecond);
122 void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
override;
173 menu.AppendSeparator();
174 menu.Append(
MYID_FOURIER,
_(
"Perform Fourier Analysis..." ) );
177 menu.AppendSeparator();
180 menu.AppendSeparator();
183 m_grid->PopupMenu( &menu );
190 menu.AppendSeparator();
192 wxString msg =
m_grid->GetColLabelValue(
m_grid->GetNumberCols() - 1 );
194 menu.AppendSeparator();
197 m_grid->PopupMenu( &menu );
203 m_grid->PopupMenu( &menu );
210 std::vector<wxString> signals;
212 wxGridCellCoordsArray cells1 =
m_grid->GetSelectionBlockTopLeft();
213 wxGridCellCoordsArray cells2 =
m_grid->GetSelectionBlockBottomRight();
215 for(
size_t i = 0; i < cells1.Count(); i++ )
219 for(
int j = cells1[i].GetRow(); j < cells2[i].GetRow() + 1; j++ )
221 signals.push_back(
m_grid->GetCellValue( j, cells1[i].GetCol() ) );
226 wxGridCellCoordsArray cells3 =
m_grid->GetSelectedCells();
228 for(
size_t i = 0; i < cells3.Count(); i++ )
231 signals.push_back(
m_grid->GetCellValue( cells3[i].GetRow(), cells3[i].GetCol() ) );
234 if( signals.size() < 1 )
237 auto addMeasurement =
238 [
this](
const wxString& cmd, wxString signal )
240 if( signal.EndsWith(
_(
" (phase)" ) ) )
243 if( signal.EndsWith(
_(
" (gain)" ) ) || signal.EndsWith(
_(
" (amplitude)" ) ) )
245 signal = signal.Left( signal.length() - 7 );
247 if( signal.Upper().StartsWith( wxS(
"V(" ) ) )
248 signal = wxS(
"vdb" ) + signal.Mid( 1 );
251 m_parent->AddMeasurement( cmd + wxS(
" " ) + signal );
256 for(
const wxString& signal : signals )
257 addMeasurement( wxS(
"MIN" ), signal );
261 for(
const wxString& signal : signals )
262 addMeasurement( wxS(
"MAX" ), signal );
266 for(
const wxString& signal : signals )
267 addMeasurement( wxS(
"AVG" ), signal );
271 for(
const wxString& signal : signals )
272 addMeasurement( wxS(
"RMS" ), signal );
276 for(
const wxString& signal : signals )
277 addMeasurement( wxS(
"PP" ), signal );
281 for(
const wxString& signal : signals )
282 addMeasurement( wxS(
"MIN_AT" ), signal );
286 for(
const wxString& signal : signals )
287 addMeasurement( wxS(
"MAX_AT" ), signal );
291 for(
const wxString& signal : signals )
292 addMeasurement( wxS(
"INTEG" ), signal );
297 wxString fundamental = wxT(
"1K" );
299 if( signals.size() == 1 )
300 title.Printf(
_(
"Fourier Analysis of %s" ), signals[0] );
302 title =
_(
"Fourier Analyses of Multiple Signals" );
312 for(
const wxString& signal : signals )
313 m_parent->DoFourier( signal, fundamental );
320 for(
const wxString& signal : signals )
328 if( wxTheClipboard->Open() )
330 wxTheClipboard->SetData(
new wxTextDataObject( txt ) );
331 wxTheClipboard->Flush();
332 wxTheClipboard->Close();
357 void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
override;
377 menu.AppendSeparator();
387 [
this](
int row ) -> wxString
391 if( signal.EndsWith(
"[2 - 1]" ) )
392 signal = signal.Left( signal.length() - 7 );
403 if( formatDialog.
ShowModal() == wxID_OK )
405 for(
int row = 0; row <
m_grid->GetNumberRows(); ++row )
407 if( getSignalName( row ) == getSignalName(
m_menuRow ) )
408 m_parent->SetCursorFormat( row, axis, format );
430 void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
override;
456 menu.AppendSeparator();
469 if( formatDialog.
ShowModal() == wxID_OK )
478 std::vector<int> measurements;
480 wxGridCellCoordsArray cells1 =
m_grid->GetSelectionBlockTopLeft();
481 wxGridCellCoordsArray cells2 =
m_grid->GetSelectionBlockBottomRight();
483 for(
size_t i = 0; i < cells1.Count(); i++ )
487 for(
int j = cells1[i].GetRow(); j < cells2[i].GetRow() + 1; j++ )
488 measurements.push_back( j );
492 wxGridCellCoordsArray cells3 =
m_grid->GetSelectedCells();
494 for(
size_t i = 0; i < cells3.Count(); i++ )
497 measurements.push_back( cells3[i].GetRow() );
500 if( measurements.size() < 1 )
505 sort( measurements.begin(), measurements.end(), std::greater<>() );
507 for(
int row : measurements )
527 m_frame->m_SuppressGridEvents++;
532 m_frame->m_SuppressGridEvents--;
540#define ID_SIM_REFRESH 10207
541#define REFRESH_INTERVAL 50
566 wxGridCellAttr* attr =
new wxGridCellAttr;
570 attr =
new wxGridCellAttr;
574 attr =
new wxGridCellAttr;
578 attr =
new wxGridCellAttr;
584 attr =
new wxGridCellAttr;
594 [&]( wxTimerEvent& aEvent )
603#ifndef wxHAS_NATIVE_TABART
623 m_cursorFormat[0] = { 3, wxS(
"~s" ) };
624 m_cursorFormat[1] = { 3, wxS(
"~V" ) };
635 for(
size_t index2 = 0; index2 < std::size(
m_cursorFormats[0] ); index2++ )
649 maxCursor.Replace(
_(
"Cursor " ),
"" );
651 int tmpMax = wxAtoi( maxCursor );
653 if( nameMax < tmpMax )
663 std::vector<SPICE_VALUE_FORMAT> tmp;
675 wxGridCellAttr* attr =
new wxGridCellAttr;
695 for(
int i = 0; i < rows; i++ )
697 if(
m_signalsGrid->GetCellValue( i, col - 1 ) == wxS(
"1" ) )
700 wxGridEvent aDummy( wxID_ANY, wxEVT_GRID_CELL_CHANGED,
m_signalsGrid, i, col - 1 );
720 for(
int ii = 0; ii < static_cast<int>(
m_plotNotebook->GetPageCount() ); ++ii )
724 simTab->OnLanguageChanged();
726 wxString pageTitle(
simulator()->TypeToName( simTab->GetSimType(),
true ) );
727 pageTitle.Prepend( wxString::Format(
_(
"Analysis %u - " ), ii+1 ) );
748 tuner->ShowChangedLanguage();
788 simTab->ApplyPreferences( aPrefs );
796 bool loadFromSchematic =
false;
798 if( !workbookFilename.IsEmpty() )
800 wxFileName filename = workbookFilename;
803 if( !filename.FileExists() )
806 wxString::Format(
_(
"Workbook file '%s' not found. "
807 "Loading simulation settings from schematic." ),
808 filename.GetFullPath() ),
809 8000, wxICON_WARNING );
812 loadFromSchematic =
true;
821 loadFromSchematic =
true;
824 if( loadFromSchematic &&
m_simulatorFrame->LoadSimulator( wxEmptyString, 0 ) )
828 if( !schTextSimCommand.IsEmpty() )
861 std::sort( signals.begin(), signals.end(),
862 [](
const wxString& lhs,
const wxString& rhs )
865 if( lhs.Upper().StartsWith(
'V' ) && !rhs.Upper().StartsWith(
'V' ) )
867 else if( !lhs.Upper().StartsWith(
'V' ) && rhs.Upper().StartsWith(
'V' ) )
870 return StrNumCmp( lhs, rhs, true ) < 0;
887 std::vector<wxString> signals;
891 wxStringTokenizer tokenizer( plotPanel->
GetSimCommand(),
" \t\r\n", wxTOKEN_STRTOK );
893 while( tokenizer.HasMoreTokens() && tokenizer.GetNextToken().Lower() != wxT(
"fft" ) )
896 while( tokenizer.HasMoreTokens() )
897 signals.emplace_back( tokenizer.GetNextToken() );
904 for(
const wxString& signal :
m_signals )
905 signals.push_back( signal );
909 if( simType ==
ST_AC )
911 signals.push_back( signal +
_(
" (gain)" ) );
912 signals.push_back( signal +
_(
" (phase)" ) );
914 else if( simType ==
ST_SP )
916 signals.push_back( signal +
_(
" (amplitude)" ) );
917 signals.push_back( signal +
_(
" (phase)" ) );
921 signals.push_back( signal );
928 if( aFilter.IsEmpty() )
929 aFilter = wxS(
"*" );
934 for(
const wxString& signal : signals )
936 if( matcher.
Find( signal.Upper() ) )
945 wxGridCellAttr* attr =
new wxGridCellAttr;
946 attr->SetRenderer(
new wxGridCellBoolRenderer() );
948 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
953 attr =
new wxGridCellAttr;
958 attr =
new wxGridCellAttr;
962 attr =
new wxGridCellAttr;
970 attr =
new wxGridCellAttr;
980 attr =
new wxGridCellAttr;
983 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
988 attr =
new wxGridCellAttr;
989 attr->SetRenderer(
new wxGridCellBoolRenderer() );
991 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
995 attr =
new wxGridCellAttr;
996 attr->SetRenderer(
new wxGridCellBoolRenderer() );
998 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
1006 attr =
new wxGridCellAttr;
1007 attr->SetRenderer(
new wxGridCellBoolRenderer() );
1008 attr->SetReadOnly();
1009 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
1027 wxString unconnected = wxString( wxS(
"unconnected-(" ) );
1032 unconnected.Replace(
'(',
'_' );
1035 [&](
const wxString& aSignalName )
1037 if( simType ==
ST_AC )
1039 m_signals.push_back( aSignalName +
_(
" (gain)" ) );
1040 m_signals.push_back( aSignalName +
_(
" (phase)" ) );
1042 else if( simType ==
ST_SP )
1044 m_signals.push_back( aSignalName +
_(
" (amplitude)" ) );
1045 m_signals.push_back( aSignalName +
_(
" (phase)" ) );
1062 if( netname ==
"GND" || netname ==
"0" || netname.StartsWith( unconnected ) )
1066 addSignal( wxString::Format( wxS(
"V(%s)" ), netname ) );
1076 for(
const std::string&
name : item.model->SpiceGenerator().CurrentNames( item ) )
1086 if( item.model->GetPinCount() >= 2 )
1088 wxString
name = item.model->SpiceGenerator().ItemName( item );
1089 addSignal( wxString::Format( wxS(
"P(%s)" ),
name ) );
1096 addSignal( wxS(
"inoise_spectrum" ) );
1097 addSignal( wxS(
"onoise_spectrum" ) );
1100 if( simType ==
ST_SP )
1102 std::vector<std::string> portnums;
1106 wxString
name = item.model->SpiceGenerator().ItemName( item );
1109 if( !
name.StartsWith(
"V" ) )
1112 std::string portnum =
"";
1114 if(
const SIM_MODEL::PARAM* portnum_param = item.model->FindParam(
"portnum" ) )
1118 portnums.push_back( portnum );
1121 for(
const std::string& portnum1 : portnums )
1123 for(
const std::string& portnum2 : portnums )
1124 addSignal( wxString::Format( wxS(
"S_%s_%s" ), portnum1, portnum2 ) );
1129 for(
const wxString& directive :
circuitModel()->GetDirectives() )
1131 wxStringTokenizer directivesTokenizer( directive,
"\r\n", wxTOKEN_STRTOK );
1133 while( directivesTokenizer.HasMoreTokens() )
1135 wxString line = directivesTokenizer.GetNextToken().Upper();
1136 wxString directiveParams;
1138 if( line.StartsWith( wxS(
".SAVE" ), &directiveParams )
1139 || line.StartsWith( wxS(
".PROBE" ), &directiveParams ) )
1141 wxStringTokenizer paramsTokenizer( directiveParams,
" \t", wxTOKEN_STRTOK );
1143 while( paramsTokenizer.HasMoreTokens() )
1144 addSignal( paramsTokenizer.GetNextToken() );
1167 wxString pageTitle(
simulator()->TypeToName( simType,
true ) );
1168 pageTitle.Prepend( wxString::Format(
_(
"Analysis %u - " ),
static_cast<unsigned int>( ++
m_plotNumber ) ) );
1184#if defined( __WXOSX__ )
1185 wxPoint pos = aEvent.GetPosition();
1186 wxRect ctrlRect =
m_filter->GetScreenRect();
1187 int buttonWidth = ctrlRect.GetHeight();
1189 if(
m_filter->IsSearchButtonVisible() && pos.x < buttonWidth )
1190 SetCursor( wxCURSOR_ARROW );
1191 else if(
m_filter->IsCancelButtonVisible() && pos.x > ctrlRect.GetWidth() - buttonWidth )
1192 SetCursor( wxCURSOR_ARROW );
1194 SetCursor( wxCURSOR_IBEAM );
1201 return wxString::Format( wxS(
"user%d" ), aUserDefinedSignalId );
1212 auto looksLikePower = [](
const wxString& aExpression ) ->
bool
1214 wxString exprUpper = aExpression.Upper();
1216 if( exprUpper.Contains( wxS(
":POWER" ) ) )
1219 if( exprUpper.Find(
'*' ) == wxNOT_FOUND )
1222 if( !exprUpper.Contains( wxS(
"V(" ) ) )
1225 if( !exprUpper.Contains( wxS(
"I(" ) ) )
1231 std::map<wxString, int> suffixes;
1247 wxUniChar firstChar = aSignalName.Upper()[0];
1249 if( firstChar ==
'V' )
1251 else if( firstChar ==
'I' )
1253 else if( firstChar ==
'P' )
1258 wxString
name = aSignalName;
1260 for(
const auto& [ candidate, type ] : suffixes )
1262 if(
name.EndsWith( candidate ) )
1264 name =
name.Left(
name.Length() - candidate.Length() );
1267 *aTraceType |= type;
1275 if(
name == signal )
1277 if( aTraceType && looksLikePower( signal ) )
1301 int row = aEvent.GetRow();
1302 int col = aEvent.GetCol();
1310 if(
text == wxS(
"1" ) )
1345 TRACE* activeTrace =
nullptr;
1347 if(
text == wxS(
"1" ) )
1351 activeTrace = plotTab->
GetTrace( vectorName, traceType );
1362 if( trace != activeTrace && trace->
HasCursor(
id ) )
1385 int row = aEvent.GetRow();
1386 int col = aEvent.GetCol();
1394 CURSOR* cursor1 =
nullptr;
1395 CURSOR* cursor2 =
nullptr;
1397 std::vector<CURSOR*> cursorsVec;
1419 cursorsVec.emplace_back(
cursor );
1421 if( cursorName == ( wxString(
"" ) << i ) &&
cursor )
1422 cursor->SetCoordX( value );
1429 if( cursorName == wxS(
"1" ) && cursor1 )
1431 else if( cursorName == wxS(
"2" ) && cursor2 )
1433 else if( cursorName ==
_(
"Diff" ) && cursor1 && cursor2 )
1441 wxFAIL_MSG( wxT(
"All other columns are supposed to be read-only!" ) );
1474 int row = aEvent.GetRow();
1475 int col = aEvent.GetCol();
1485 wxFAIL_MSG( wxT(
"All other columns are supposed to be read-only!" ) );
1493 for( row = rowCount - 1; row >= 0; row-- )
1503 int killRows = emptyRows - 1;
1506 else if( emptyRows == 0 )
1517 if( plotTab->GetLegendPosition() != plotTab->m_LastLegendPosition )
1519 plotTab->m_LastLegendPosition = plotTab->GetLegendPosition();
1542 static wxRegEx measureParamsRegEx( wxT(
"^"
1546 "([a-zA-Z]*)\\(([^\\)]+)\\)" ) );
1555 if(
text.IsEmpty() )
1562 wxString resultName = wxString::Format( wxS(
"meas_result_%u" ), aRow );
1563 wxString
result = wxS(
"?" );
1565 if( measureParamsRegEx.Matches(
text ) )
1567 wxString func = measureParamsRegEx.GetMatch(
text, 1 ).Upper();
1568 wxString signalType = measureParamsRegEx.GetMatch(
text, 2 ).Upper();
1569 wxString deviceName = measureParamsRegEx.GetMatch(
text, 3 );
1573 if( signalType.EndsWith( wxS(
"DB" ) ) )
1575 units = wxS(
"dB" );
1577 else if( signalType.StartsWith(
'I' ) )
1581 else if( signalType.StartsWith(
'P' ) )
1585 text = func +
" " + deviceName +
":power";
1592 if( func.EndsWith( wxS(
"_AT" ) ) )
1595 units = wxS(
"Hz" );
1599 else if( func.StartsWith( wxS(
"INTEG" ) ) )
1604 if ( signalType.StartsWith(
'P' ) )
1607 units += wxS(
".s" );
1617 units += wxS(
"·Hz" );
1625 units += wxS(
"·?" );
1638 wxString cmd = wxString::Format( wxS(
"meas %s %s %s" ), simType, resultName,
text );
1644 if( resultVec.size() > 0 )
1659 "the value of a passive R, L, C model or voltage or "
1660 "current source." ) );
1664 wxString ref = aSymbol->
GetRef( &aSheetPath );
1669 if( tuner->GetSymbolRef() == ref )
1692 const wxString& aRef,
const wxString& aValue )
1695 wxString variant = schematic.GetCurrentVariant();
1702 + wxString::Format(
_(
"%s not found" ), aRef ) );
1709 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
1710 embeddedFilesStack.push_back(
m_schematicFrame->Schematic().GetEmbeddedFiles() );
1714 embeddedFilesStack.push_back( symbolEmbeddedFiles );
1727 + wxString::Format(
_(
"%s is not tunable" ), aRef ) );
1731 model.SetParamValue( tunerParam->
info.
name, std::string( aValue.ToUTF8() ) );
1801 wxString cmd = wxString::Format( wxS(
"fourier %s %s" ),
1819 m_simConsole->AppendText(
_(
"Error: no current simulation.\n" ) );
1828 m_simConsole->AppendText(
_(
"Error: simulation type not defined.\n" ) );
1834 m_simConsole->AppendText(
_(
"Error: simulation type doesn't support plotting.\n" ) );
1841 if( simType ==
ST_AC )
1846 else if( simType ==
ST_SP )
1856 plotTab->GetPlotWin()->UpdateAll();
1878 if( aNewSignals.count(
id ) == 0 )
1883 plotTab->
DeleteTrace( vectorName, traceType | subType );
1888 plotTab->
DeleteTrace( vectorName, traceType | subType );
1901 if(
TRACE* trace = plotTab->
GetTrace( vectorName, traceType | subType ) )
1902 trace->SetName( aNewSignals.at(
id ) );
1909 if(
TRACE* trace = plotTab->
GetTrace( vectorName, traceType | subType ) )
1910 trace->SetName( aNewSignals.at(
id ) );
1915 if(
TRACE* trace = plotTab->
GetTrace( vectorName, traceType ) )
1916 trace->SetName( aNewSignals.at(
id ) );
1936 std::vector<double>* aDataX,
bool aClearData )
1949 wxString simVectorName = aVectorName;
1952 simVectorName = simVectorName.AfterFirst(
'(' ).BeforeLast(
')' ) + wxS(
":power" );
1957 simulator()->
Command( wxString::Format( wxT(
"print %s" ), aVectorName ).ToStdString() );
1962 std::vector<double> data_x;
1963 std::vector<double> data_y;
1965 if( !aDataX || aClearData )
1969 if( aDataX->empty() && !aClearData )
1971 wxString xAxisName(
simulator()->GetXAxis( simType ) );
1973 if( xAxisName.IsEmpty() )
1979 unsigned int size = aDataX->size();
1989 wxFAIL_MSG( wxT(
"Plot type missing AC_PHASE or AC_MAG bit" ) );
1998 wxFAIL_MSG( wxT(
"Plot type missing AC_PHASE or SPT_SP_AMP bit" ) );
2013 wxFAIL_MSG( wxT(
"Unhandled plot type" ) );
2018 size_t sweepSize = std::numeric_limits<size_t>::max();
2020 if( simType ==
ST_DC
2027 sweepSize = aDataX->size() / sweepCount;
2044 size_t sweepSizeMulti = traceData.
xValues.size();
2045 size_t runCount = traceData.
yValues.size();
2047 if( sweepSizeMulti > 0 && runCount > 0 )
2049 std::vector<double> combinedX;
2050 std::vector<double> combinedY;
2052 combinedX.reserve( sweepSizeMulti * runCount );
2053 combinedY.reserve( sweepSizeMulti * runCount );
2055 for(
const std::vector<double>& runY : traceData.
yValues )
2057 if( runY.size() != sweepSizeMulti )
2060 combinedX.insert( combinedX.end(), traceData.
xValues.begin(), traceData.
xValues.end() );
2061 combinedY.insert( combinedY.end(), runY.begin(), runY.end() );
2066 if( combinedY.size() >= combinedX.size() && sweepSizeMulti > 0 )
2068 int sweepCountCombined = combinedX.empty() ? 0 :
static_cast<int>( combinedY.size() / sweepSizeMulti );
2070 if( sweepCountCombined > 0 )
2073 std::vector<wxString> labels;
2074 labels.reserve( sweepCountCombined );
2076 for(
int i = 0; i < sweepCountCombined && i < (int)
m_multiRunState.steps.size(); ++i )
2084 label += wxS(
", " );
2087 double value = it->second;
2093 labels.push_back( label );
2096 aPlotTab->
SetTraceData( trace, combinedX, combinedY, sweepCountCombined,
2097 sweepSizeMulti,
true, labels );
2110 if( data_y.size() >= size )
2111 aPlotTab->
SetTraceData( trace, *aDataX, data_y, sweepCount, sweepSize );
2121template <
typename T,
typename U,
typename R>
2129 wxGridCellAttrPtr attr =
m_signalsGrid->GetOrCreateCellAttrPtr( r,
static_cast<int>( t ) );
2131 if(
TRACE* trace = plotTab ? plotTab->
GetTrace( vectorName, traceType ) :
nullptr )
2133 attr->SetReadOnly();
2137 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
2140 if constexpr ( std::is_enum<T>::value )
2144 m_signalsGrid->SetCellValue( r,
static_cast<int>( t ), wxS(
"1" ) );
2148 if( !attr->HasRenderer() )
2151 if( !attr->HasEditor() )
2154 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
2155 attr->SetReadOnly(
false );
2164 if( !attr->HasRenderer() )
2165 attr->SetRenderer(
new wxGridCellBoolRenderer() );
2167 if( u > 0 && trace->HasCursor( u ) )
2168 m_signalsGrid->SetCellValue( r,
static_cast<int>( t ), wxS(
"1" ) );
2170 m_signalsGrid->SetCellValue( r,
static_cast<int>( t ), wxEmptyString );
2176 if constexpr ( std::is_enum<T>::value )
2180 m_signalsGrid->SetCellValue( r,
static_cast<int>( t ), wxEmptyString );
2187 attr->SetEditor(
nullptr );
2188 attr->SetRenderer(
nullptr );
2189 attr->SetReadOnly();
2190 m_signalsGrid->SetCellValue( r,
static_cast<int>( t ), wxEmptyString );
2199 for(
int row = 0; row <
m_signalsGrid->GetNumberRows(); ++row )
2221 auto quoteNetNames =
2222 [&]( wxString aExpression ) -> wxString
2224 std::vector<bool> mask( aExpression.length(),
false );
2226 auto isNetnameChar =
2227 []( wxUniChar aChar ) ->
bool
2229 wxUint32 value = aChar.GetValue();
2231 if( ( value >=
'0' && value <=
'9' ) || ( value >=
'A' && value <=
'Z' )
2232 || ( value >=
'a' && value <=
'z' ) )
2255 size_t pos = aExpression.find( netname );
2257 while( pos != wxString::npos )
2259 for(
size_t i = 0; i < netname.length(); ++i )
2260 mask[pos + i] =
true;
2262 pos = aExpression.find( netname, pos + 1 );
2266 for(
size_t i = 0; i < aExpression.length(); ++i )
2268 if( !mask[i] || ( i > 0 && mask[i - 1] ) )
2273 while( j < aExpression.length() )
2281 if( isNetnameChar( aExpression[j] ) )
2293 wxString quotedNetnames =
"";
2294 bool startQuote =
true;
2297 for(
size_t i = 0; i < aExpression.length(); i++ )
2299 if( mask[i] && startQuote )
2301 quotedNetnames = quotedNetnames +
"\"";
2304 else if( !mask[i] && !startQuote )
2306 quotedNetnames = quotedNetnames +
"\"";
2310 wxString ch = aExpression[i];
2311 quotedNetnames = quotedNetnames + ch;
2315 quotedNetnames = quotedNetnames +
"\"";
2317 return quotedNetnames;
2322 constexpr const char* cmd =
"let user{} = {}";
2324 simulator()->
Command(
"echo " + fmt::format( cmd,
id, signal.ToStdString() ) );
2325 simulator()->
Command( fmt::format( cmd,
id, quoteNetNames( signal ).ToStdString() ) );
2337 wxString ref = tuner->GetSymbolRef();
2338 KIID symbolId = tuner->GetSymbol( &sheetPath );
2344 reporter.Report( wxString::Format(
_(
"%s not found" ), ref ) );
2352 reporter.Report( wxString::Format(
_(
"%s is not tunable" ), ref ) );
2361 floatVal = overrideIt->second;
2363 floatVal = tuner->GetValue().ToDouble();
2374 wxTextFile file( aPath );
2379 wxString firstLine = file.GetFirstLine();
2381 bool legacy = firstLine.StartsWith( wxT(
"version " ) ) || firstLine.ToLong( &
dummy );
2406 wxFileName filename( aPath );
2418 wxFFileInputStream fp( aPath, wxT(
"rt" ) );
2419 wxStdInputStream fstream( fp );
2426 nlohmann::json js = nlohmann::json::parse( fstream,
nullptr,
true,
true );
2428 std::map<SIM_PLOT_TAB*, nlohmann::json> traceInfo;
2430 for(
const nlohmann::json& tab_js : js[
"tabs" ] )
2432 wxString simCommand;
2436 for(
const nlohmann::json& cmd : tab_js[
"commands" ] )
2438 if( cmd ==
".kicad adjustpaths" )
2440 else if( cmd ==
".save all" )
2442 else if( cmd ==
".probe alli" )
2444 else if( cmd ==
".probe allp" )
2446 else if( cmd ==
".kicad esavenone" )
2449 simCommand += wxString( cmd.get<wxString>() ).Trim();
2459 if( tab_js.contains(
"traces" ) )
2460 traceInfo[plotTab] = tab_js[
"traces" ];
2462 if( tab_js.contains(
"measurements" ) )
2464 for(
const nlohmann::json& m_js : tab_js[
"measurements" ] )
2465 plotTab->
Measurements().emplace_back( m_js[
"expr" ], m_js[
"format" ] );
2469 plotTab->
ShowGrid( tab_js[
"showGrid" ] );
2471 if( tab_js.contains(
"fixedY1scale" ) )
2473 const nlohmann::json& scale_js = tab_js[
"fixedY1scale" ];
2474 plotTab->
SetY1Scale(
true, scale_js[
"min" ], scale_js[
"max" ] );
2478 if( tab_js.contains(
"fixedY2scale" ) )
2480 const nlohmann::json& scale_js = tab_js[
"fixedY2scale" ];
2481 plotTab->
SetY2Scale(
true, scale_js[
"min" ], scale_js[
"max" ] );
2485 if( tab_js.contains(
"fixedY3scale" ) )
2488 const nlohmann::json& scale_js = tab_js[
"fixedY3scale" ];
2489 plotTab->
SetY3Scale(
true, scale_js[
"min" ], scale_js[
"max" ] );
2493 if( tab_js.contains(
"legend" ) )
2495 const nlohmann::json& legend_js = tab_js[
"legend" ];
2500 if( tab_js.contains(
"margins" ) )
2502 const nlohmann::json& margins_js = tab_js[
"margins" ];
2504 margins_js[
"right" ],
2505 margins_js[
"bottom" ],
2506 margins_js[
"left" ] );
2513 if( js.contains(
"user_defined_signals" ) )
2515 for(
const nlohmann::json& signal_js : js[
"user_defined_signals" ] )
2521 m_simulatorFrame->LoadSimulator( simTab->GetSimCommand(), simTab->GetSimOptions() );
2524 firstTab->SetLastSchTextSimCommand( js[
"last_sch_text_sim_command"] );
2527 int tempCustomCursorsCnt = 0;
2529 if( js.contains(
"custom_cursors" ) )
2530 tempCustomCursorsCnt = js[
"custom_cursors"];
2532 tempCustomCursorsCnt = 2;
2542 int aCursorId,
const nlohmann::json& aCursor_js )
2544 if( aCursorId >= 1 )
2548 cursor->SetName( aSignalName );
2549 cursor->SetCoordX( aCursor_js[
"position" ] );
2551 aTrace->SetCursor( aCursorId,
cursor );
2555 if( aCursorId == -1 )
2576 for(
const auto& [ plotTab, traces_js ] : traceInfo )
2578 for(
const nlohmann::json& trace_js : traces_js )
2580 wxString signalName = trace_js[
"signal" ];
2582 TRACE* trace = plotTab->GetOrAddTrace( vectorName, trace_js[
"trace_type" ] );
2586 if( trace_js.contains(
"cursorD" ) )
2587 addCursor( plotTab, trace, signalName, -1, trace_js[
"cursorD" ] );
2589 std::vector<const char*> aVec;
2592 for(
int i = 1; i <= tempCustomCursorsCnt; i++ )
2594 wxString str =
"cursor" + std::to_string( i );
2595 aVec.emplace_back( str.c_str() );
2597 if( trace_js.contains( aVec[i - 1] ) )
2598 addCursor( plotTab, trace, signalName, i, trace_js[aVec[i - 1]] );
2601 if( trace_js.contains(
"color" ) )
2604 color.Set( wxString( trace_js[
"color"].get<wxString>() ) );
2606 plotTab->UpdateTraceStyle( trace );
2611 plotTab->UpdatePlotColors();
2614 catch( nlohmann::json::parse_error& error )
2616 wxLogTrace(
traceSettings, wxT(
"Json parse error reading %s: %s" ), aPath, error.what() );
2620 catch( nlohmann::json::type_error& error )
2622 wxLogTrace(
traceSettings, wxT(
"Json type error reading %s: %s" ), aPath, error.what() );
2626 catch( nlohmann::json::invalid_iterator& error )
2628 wxLogTrace(
traceSettings, wxT(
"Json invalid_iterator error reading %s: %s" ), aPath, error.what() );
2632 catch( nlohmann::json::out_of_range& error )
2634 wxLogTrace(
traceSettings, wxT(
"Json out_of_range error reading %s: %s" ), aPath, error.what() );
2640 wxLogTrace(
traceSettings, wxT(
"Error reading %s" ), aPath );
2649 int cursorIdAfterD = aCursorId;
2652 cursorIdAfterD = cursorIdAfterD - 1;
2657 aTraceJs[
"cursor" + wxString(
"" ) << aCursorId] =
2658 nlohmann::json( { {
"position",
cursor->GetCoords().x },
2665 aTraceJs[
"cursorD"] =
2676 wxFileName filename = aPath;
2681 file.Create( filename.GetFullPath(),
true );
2683 if( !file.IsOpened() )
2686 nlohmann::json tabs_js = nlohmann::json::array();
2697 nlohmann::json commands_js = nlohmann::json::array();
2704 commands_js.push_back(
".kicad adjustpaths" );
2707 commands_js.push_back(
".save all" );
2710 commands_js.push_back(
".probe alli" );
2713 commands_js.push_back(
".probe allp" );
2716 commands_js.push_back(
".kicad esavenone" );
2718 nlohmann::json tab_js = nlohmann::json(
2720 {
"commands", commands_js } } );
2724 nlohmann::json traces_js = nlohmann::json::array();
2726 auto findSignalName =
2727 [&](
const wxString& aVectorName ) -> wxString
2729 wxString vectorName;
2732 if( aVectorName.EndsWith(
_(
" (phase)" ) ) )
2733 suffix =
_(
" (phase)" );
2734 else if( aVectorName.EndsWith(
_(
" (gain)" ) ) )
2735 suffix =
_(
" (gain)" );
2737 vectorName = aVectorName.Left( aVectorName.Length() - suffix.Length() );
2742 return signal + suffix;
2748 for(
const auto& [
name, trace] : plotTab->GetTraces() )
2750 nlohmann::json trace_js = nlohmann::json(
2751 { {
"trace_type", (int) trace->GetType() },
2752 {
"signal", findSignalName( trace->GetDisplayName() ) },
2758 if( trace->GetCursor( 1 ) || trace->GetCursor( 2 ) )
2760 trace_js[
"cursorD"] = nlohmann::json(
2765 traces_js.push_back( trace_js );
2768 nlohmann::json measurements_js = nlohmann::json::array();
2770 for(
const auto& [
measurement, format ] : plotTab->Measurements() )
2772 measurements_js.push_back( nlohmann::json( { {
"expr",
measurement },
2773 {
"format", format } } ) );
2776 tab_js[
"traces" ] = traces_js;
2777 tab_js[
"measurements" ] = measurements_js;
2778 tab_js[
"dottedSecondary" ] = plotTab->GetDottedSecondary();
2779 tab_js[
"showGrid" ] = plotTab->IsGridShown();
2783 if( plotTab->GetY1Scale( &min, &max ) )
2784 tab_js[
"fixedY1scale" ] = nlohmann::json( { {
"min", min }, {
"max", max } } );
2786 if( plotTab->GetY2Scale( &min, &max ) )
2787 tab_js[
"fixedY2scale" ] = nlohmann::json( { {
"min", min }, {
"max", max } } );
2789 if( plotTab->GetY3Scale( &min, &max ) )
2790 tab_js[
"fixedY3scale" ] = nlohmann::json( { {
"min", min }, {
"max", max } } );
2792 if( plotTab->IsLegendShown() )
2794 tab_js[
"legend" ] = nlohmann::json( { {
"x", plotTab->GetLegendPosition().x },
2795 {
"y", plotTab->GetLegendPosition().y } } );
2798 mpWindow* plotWin = plotTab->GetPlotWin();
2800 tab_js[
"margins" ] = nlohmann::json( { {
"left", plotWin->
GetMarginLeft() },
2806 tabs_js.push_back( tab_js );
2809 nlohmann::json userDefinedSignals_js = nlohmann::json::array();
2812 userDefinedSignals_js.push_back( signal );
2815 nlohmann::json js = nlohmann::json( { {
"version", 7 },
2816 {
"tabs", tabs_js },
2817 {
"user_defined_signals", userDefinedSignals_js },
2830 std::stringstream buffer;
2831 buffer << std::setw( 2 ) << js << std::endl;
2833 bool res = file.Write( buffer.str() );
2860 wxFAIL_MSG( wxString::Format( wxS(
"Unhandled simulation type: %d" ), (
int) aType ) );
2880 &source, &
scale, &pts, &fStart, &fStop, &saveAll );
2888 int& aSashPosition )
2890 bool isShown = aPanel->IsShown();
2893 aSashPosition = aSplitterWindow->GetSashPosition();
2895 aPanel->Show( !isShown );
2897 aSplitterWindow->SetSashInvisible( isShown );
2898 aSplitterWindow->SetSashPosition( isShown ? -1 : aSashPosition,
true );
2900 aSplitterWindow->UpdateSize();
2901 m_parent->Refresh();
2938 for(
size_t page = 0; page <
m_plotNotebook->GetPageCount(); page++ )
2974 schematic.ClearOperatingPoints();
2986 std::vector<std::pair<wxString, wxString>>& measurements = plotTab->Measurements();
2988 measurements.clear();
3026 simulator()->
Command(
"setplot " + simTab->GetSpicePlotName().ToStdString() );
3043 for(
const auto& [
measurement, format ] : plotTab->Measurements() )
3051 if( plotTab->GetSimType() ==
ST_TRAN || plotTab->GetSimType() ==
ST_AC
3052 || plotTab->GetSimType() ==
ST_DC || plotTab->GetSimType() ==
ST_SP )
3089 CURSOR* cursor1 =
nullptr;
3090 wxString cursor1Name;
3091 wxString cursor1Units;
3092 CURSOR* cursor2 =
nullptr;
3093 wxString cursor2Name;
3094 wxString cursor2Units;
3097 [&](
TRACE* aTrace ) -> wxString
3118 [&](
TRACE* aTrace ) -> wxString
3139 [
this](
double aValue,
int aCursorId,
int aCol ) -> wxString
3141 if( ( !
m_simulatorFrame->SimFinished() && aCol == 1 ) || std::isnan( aValue ) )
3152 cursor1Name = getNameY( trace );
3153 cursor1Units = getUnitsY( trace );
3155 wxRealPoint coords =
cursor->GetCoords();
3175 cursor2Name = getNameY( trace );
3176 cursor2Units = getUnitsY( trace );
3178 wxRealPoint coords =
cursor->GetCoords();
3193 if( cursor1 && cursor2 && cursor1Units == cursor2Units )
3202 signal = wxString::Format( wxS(
"%s[2 - 1]" ), cursor2->
GetName() );
3204 signal = wxString::Format( wxS(
"%s - %s" ), cursor2->
GetName(), cursor1->
GetName() );
3215 wxString valColName =
_(
"Value" );
3217 if( !cursor1Name.IsEmpty() )
3219 if( cursor2Name.IsEmpty() || cursor1Name == cursor2Name )
3220 valColName = cursor1Name;
3222 else if( !cursor2Name.IsEmpty() )
3224 valColName = cursor2Name;
3238 wxString cursName = getNameY( trace );
3239 wxString cursUnits = getUnitsY( trace );
3241 wxRealPoint coords =
cursor->GetCoords();
3256 valColName =
_(
"Value" );
3259 valColName = cursName;
3280 plotTab->ResetScales(
true );
3302 std::vector<wxString> signals;
3304 for(
const std::string& vec :
simulator()->AllVectors() )
3305 signals.emplace_back( vec );
3313 std::vector<wxString> signals;
3315 for(
const wxString& signal :
m_signals )
3316 signals.emplace_back( signal );
3319 signals.emplace_back( signal );
3337 bool storeMultiRun =
false;
3343 storeMultiRun =
true;
3358 if( aFinal && simType ==
ST_FFT )
3362 if( !spicePlotName.IsEmpty() )
3377 if( simType ==
ST_NOISE && aFinal )
3379 m_simConsole->AppendText(
_(
"\n\nSimulation results:\n\n" ) );
3388 for(
const std::string& vec :
simulator()->AllVectors() )
3393 msg.Printf( wxS(
"%s: %sV\n" ), vec, value );
3404 wxCHECK_RET( plotTab, wxString::Format( wxT(
"No SIM_PLOT_TAB for: %s" ),
3405 magic_enum::enum_name( simType ) ) );
3414 std::map<TRACE*, TRACE_INFO> traceMap;
3417 traceMap[ trace ] = { wxEmptyString,
SPT_UNKNOWN,
false };
3422 for(
const wxString& signal :
m_signals )
3427 if(
TRACE* trace = plotTab->
GetTrace( vectorName, traceType ) )
3428 traceMap[ trace ] = { vectorName, traceType,
false };
3436 if( simType ==
ST_AC )
3442 if(
TRACE* trace = plotTab->
GetTrace( vectorName, subType ) )
3443 traceMap[ trace ] = { vectorName, subType, !aFinal };
3446 else if( simType ==
ST_SP )
3452 if(
TRACE* trace = plotTab->
GetTrace( vectorName, subType ) )
3453 traceMap[trace] = { vectorName, subType, !aFinal };
3458 if(
TRACE* trace = plotTab->
GetTrace( vectorName, traceType ) )
3459 traceMap[ trace ] = { vectorName, traceType, !aFinal };
3465 for(
const auto& [ trace, traceInfo ] : traceMap )
3467 if( traceInfo.Vector.IsEmpty() )
3471 for(
const auto& [ trace,
info ] : traceMap )
3473 std::vector<double> data_x;
3475 if( !
info.Vector.IsEmpty() )
3493 else if( simType ==
ST_OP && aFinal )
3495 m_simConsole->AppendText(
_(
"\n\nSimulation results:\n\n" ) );
3498 for(
const std::string& vec :
simulator()->AllVectors() )
3502 if( val_list.empty() )
3509 const size_t tab = 25;
3510 size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
3514 case SPT_VOLTAGE: value.Append( wxS(
"V" ) );
break;
3515 case SPT_CURRENT: value.Append( wxS(
"A" ) );
break;
3516 case SPT_POWER: value.Append( wxS(
"W" ) );
break;
3517 default: value.Append( wxS(
"?" ) );
break;
3520 msg.Printf( wxT(
"%s%s\n" ),
3521 ( signal + wxT(
":" ) ).Pad( padding, wxUniChar(
' ' ) ),
3528 signal = signal.SubString( 2, signal.Length() - 2 );
3531 signal += wxS(
":power" );
3533 m_schematicFrame->Schematic().SetOperatingPoint( signal, val_list.at( 0 ) );
3536 else if( simType ==
ST_PZ && aFinal )
3538 m_simConsole->AppendText(
_(
"\n\nSimulation results:\n\n" ) );
3599 std::vector<TUNER_SLIDER*> multiTuners;
3604 multiTuners.push_back( tuner );
3607 if( multiTuners.empty() )
3639 else if( tunersChanged )
3648 for(
const auto& entry : step.
overrides )
3655 const std::vector<TUNER_SLIDER*>& aTuners )
const
3657 std::vector<MULTI_RUN_STEP> steps;
3659 if( aTuners.empty() )
3662 std::vector<std::vector<double>> tunerValues;
3663 tunerValues.reserve( aTuners.size() );
3670 double startValue = tuner->GetMin().ToDouble();
3671 double endValue = tuner->GetMax().ToDouble();
3672 int stepCount = std::max( 2, tuner->GetStepCount() );
3677 double increment = ( endValue - startValue ) /
static_cast<double>( stepCount - 1 );
3679 std::vector<double> values;
3680 values.reserve( stepCount );
3682 for(
int ii = 0; ii < stepCount; ++ii )
3683 values.push_back( startValue + increment * ii );
3685 tunerValues.push_back( std::move( values ) );
3693 std::vector<double> currentValues( aTuners.size(), 0.0 );
3695 auto generate = [&](
auto&& self,
size_t depth ) ->
void
3697 if( steps.size() >=
static_cast<size_t>( limit ) )
3700 if( depth == aTuners.size() )
3704 for(
size_t ii = 0; ii < aTuners.size(); ++ii )
3705 step.
overrides.emplace( aTuners[ii], currentValues[ii] );
3707 steps.push_back( std::move( step ) );
3711 for(
double value : tunerValues[depth] )
3713 currentValues[depth] = value;
3714 self( self, depth + 1 );
3716 if( steps.size() >=
static_cast<size_t>( limit ) )
3721 generate( generate, 0 );
3729 return fmt::format(
"{}|{}", aVectorName.ToStdString(), aTraceType );
3734 const std::vector<double>& aX,
3735 const std::vector<double>& aY )
3737 if( aX.empty() || aY.empty() )
3748 if( trace.
xValues.size() != aX.size() )
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
wxColour ToColour() const
Hold a translatable error message and may be used when throwing exceptions containing a translated er...
const wxString What() const
void AppendParentEmbeddedFiles(std::vector< EMBEDDED_FILES * > &aStack) 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.
Holds all the data relating to one schematic.
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.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
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
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
const wxString & GetSpicePlotName() 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.
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.
IbisParser parser & reporter
table push_back({ "Source", "Layer", "Vertices", "Strategy", "Build(us)", "ns/query", "Mquery/s", "Inside" })
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.