KiCad PCB EDA Suite
sim_plot_frame.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 CERN
5  * Copyright (C) 2016-2018 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  * @author Maciej Suminski <maciej.suminski@cern.ch>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 3
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * https://www.gnu.org/licenses/gpl-3.0.html
22  * or you may search the http://www.gnu.org website for the version 3 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <sch_edit_frame.h>
28 #include <eeschema_id.h>
29 #include <kiway.h>
30 #include <confirm.h>
31 #include <bitmaps.h>
33 
34 #include <widgets/tuner_slider.h>
37 #include <pgm_base.h>
38 
39 #include "sim_plot_frame.h"
40 #include "sim_plot_panel.h"
41 #include "spice_simulator.h"
42 #include "spice_reporter.h"
43 
44 #include <menus_helpers.h>
45 
47 {
48  int res = (int) aFirst | (int) aSecond;
49 
50  return (SIM_PLOT_TYPE) res;
51 }
52 
53 
55 {
56 public:
58  : m_parent( aParent )
59  {
60  }
61 
62  REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_UNDEFINED ) override
63  {
64  wxCommandEvent* event = new wxCommandEvent( EVT_SIM_REPORT );
65  event->SetString( aText );
66  wxQueueEvent( m_parent, event );
67  return *this;
68  }
69 
70  bool HasMessage() const override
71  {
72  return false; // Technically "indeterminate" rather than false.
73  }
74 
75  void OnSimStateChange( SPICE_SIMULATOR* aObject, SIM_STATE aNewState ) override
76  {
77  wxCommandEvent* event = NULL;
78 
79  switch( aNewState )
80  {
81  case SIM_IDLE:
82  event = new wxCommandEvent( EVT_SIM_FINISHED );
83  break;
84 
85  case SIM_RUNNING:
86  event = new wxCommandEvent( EVT_SIM_STARTED );
87  break;
88  }
89 
90  wxQueueEvent( m_parent, event );
91  }
92 
93 private:
95 };
96 
97 
98 TRACE_DESC::TRACE_DESC( const NETLIST_EXPORTER_PSPICE_SIM& aExporter, const wxString& aName,
99  SIM_PLOT_TYPE aType, const wxString& aParam )
100  : m_name( aName ), m_type( aType ), m_param( aParam )
101 {
102  // Title generation
103  m_title = wxString::Format( "%s(%s)", aParam, aName );
104 
105  if( aType & SPT_AC_MAG )
106  m_title += " (mag)";
107  else if( aType & SPT_AC_PHASE )
108  m_title += " (phase)";
109 }
110 
111 // Store the path of saved workbooks during the session
113 
114 SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
115  : SIM_PLOT_FRAME_BASE( aParent ), m_lastSimPlot( nullptr )
116 {
117  SetKiway( this, aKiway );
118  m_signalsIconColorList = NULL;
119 
121 
122  if( m_schematicFrame == NULL )
123  throw std::runtime_error( "There is no schematic window" );
124 
125  // Give an icon
126  wxIcon icon;
127  icon.CopyFromBitmap( KiBitmap( simulator_xpm ) );
128  SetIcon( icon );
129 
130  // Get the previous size and position of windows:
131  LoadSettings( config() );
132 
134 
135  if( !m_simulator )
136  {
137  throw std::runtime_error( "Could not create simulator instance" );
138  return;
139  }
140 
141  m_simulator->Init();
142 
143  if( m_savedWorkbooksPath.IsEmpty() )
144  {
146  }
147 
148  m_reporter = new SIM_THREAD_REPORTER( this );
150 
152 
153  Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SIM_PLOT_FRAME::onClose ), NULL, this );
154  Connect( EVT_SIM_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onSimUpdate ), NULL, this );
155  Connect( EVT_SIM_REPORT, wxCommandEventHandler( SIM_PLOT_FRAME::onSimReport ), NULL, this );
156  Connect( EVT_SIM_STARTED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimStarted ), NULL, this );
157  Connect( EVT_SIM_FINISHED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimFinished ), NULL, this );
158  Connect( EVT_SIM_CURSOR_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onCursorUpdate ), NULL, this );
159 
160  // Toolbar buttons
161  m_toolSimulate = m_toolBar->AddTool( ID_SIM_RUN, _( "Run/Stop Simulation" ),
162  KiBitmap( sim_run_xpm ), _( "Run Simulation" ), wxITEM_NORMAL );
163  m_toolAddSignals = m_toolBar->AddTool( ID_SIM_ADD_SIGNALS, _( "Add Signals" ),
164  KiBitmap( sim_add_signal_xpm ), _( "Add signals to plot" ), wxITEM_NORMAL );
165  m_toolProbe = m_toolBar->AddTool( ID_SIM_PROBE, _( "Probe" ),
166  KiBitmap( sim_probe_xpm ), _( "Probe signals on the schematic" ), wxITEM_NORMAL );
167  m_toolTune = m_toolBar->AddTool( ID_SIM_TUNE, _( "Tune" ),
168  KiBitmap( sim_tune_xpm ), _( "Tune component values" ), wxITEM_NORMAL );
169  m_toolSettings = m_toolBar->AddTool( wxID_ANY, _( "Settings" ),
170  KiBitmap( sim_settings_xpm ), _( "Simulation settings" ), wxITEM_NORMAL );
171 
172  Connect( m_toolSimulate->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
173  wxCommandEventHandler( SIM_PLOT_FRAME::onSimulate ), NULL, this );
174  Connect( m_toolAddSignals->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
175  wxCommandEventHandler( SIM_PLOT_FRAME::onAddSignal ), NULL, this );
176  Connect( m_toolProbe->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
177  wxCommandEventHandler( SIM_PLOT_FRAME::onProbe ), NULL, this );
178  Connect( m_toolTune->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
179  wxCommandEventHandler( SIM_PLOT_FRAME::onTune ), NULL, this );
180  Connect( m_toolSettings->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
181  wxCommandEventHandler( SIM_PLOT_FRAME::onSettings ), NULL, this );
182 
183  // Bind toolbar buttons event to existing menu event handlers, so they behave the same
184  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSimulate, this, m_runSimulation->GetId() );
185  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onAddSignal, this, m_addSignals->GetId() );
186  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onProbe, this, m_probeSignals->GetId() );
187  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onTune, this, m_tuneValue->GetId() );
188  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this, m_settings->GetId() );
189 
190  m_toolBar->Realize();
191  m_plotNotebook->SetPageText( 0, _( "Welcome!" ) );
192 
193  // the settings dialog will be created later, on demand.
194  // if created in the ctor, for some obscure reason, there is an issue
195  // on Windows: when open it, the simulator frame is sent to the background.
196  // instead of being behind the dialog frame (as it does)
197  m_settingsDlg = NULL;
198 
199  SetSize( ConvertDialogToPixels( wxSize( 400, 300 ) ) );
200 
201  // resize the subwindows size. At least on Windows, calling wxSafeYield before
202  // resizing the subwindows forces the wxSplitWindows size events automatically generated
203  // by wxWidgets to be executed before our resize code.
204  // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
205  // events
206  wxSafeYield();
208 }
209 
210 
212 {
213  m_simulator->SetReporter( nullptr );
214  delete m_reporter;
215  delete m_signalsIconColorList;
216 
217  if( m_settingsDlg )
218  m_settingsDlg->Destroy();
219 }
220 
221 #define PLOT_PANEL_WIDTH_ENTRY "SimPlotPanelWidth"
222 #define PLOT_PANEL_HEIGHT_ENTRY "SimPlotPanelHeight"
223 #define SIGNALS_PANEL_HEIGHT_ENTRY "SimSignalPanelHeight"
224 #define CURSORS_PANEL_HEIGHT_ENTRY "SimCursorsPanelHeight"
225 
226 void SIM_PLOT_FRAME::SaveSettings( wxConfigBase* aCfg )
227 {
228  // Save main frame size and position:
230 
231  // Save subwindows sizes
232  aCfg->Write( PLOT_PANEL_WIDTH_ENTRY, m_splitterLeftRight->GetSashPosition() );
233  aCfg->Write( PLOT_PANEL_HEIGHT_ENTRY, m_splitterPlotAndConsole->GetSashPosition() );
234  aCfg->Write( SIGNALS_PANEL_HEIGHT_ENTRY, m_splitterSignals->GetSashPosition() );
235  aCfg->Write( CURSORS_PANEL_HEIGHT_ENTRY, m_splitterTuneValues->GetSashPosition() );
236 }
237 
238 
239 void SIM_PLOT_FRAME::LoadSettings( wxConfigBase* aCfg )
240 {
241  // Read main frame size and position:
243  SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
244 
245  // Read subwindows sizes (should be > 0 )
250 }
251 
252 
254 {
257 
260 
263 
266 }
267 
268 
270 {
271  STRING_FORMATTER formatter;
272  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
273 
274  if( !m_settingsDlg )
275  m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
276 
277  m_simConsole->Clear();
279 
280  if( plotPanel )
281  m_exporter->SetSimCommand( m_plots[plotPanel].m_simCommand );
282 
283  if( !m_exporter->Format( &formatter, m_settingsDlg->GetNetlistOptions() ) )
284  {
285  DisplayError( this, _( "There were errors during netlist export, aborted." ) );
286  return;
287  }
288 
289  if( m_exporter->GetSimType() == ST_UNKNOWN )
290  {
291  DisplayInfoMessage( this, _( "You need to select the simulation settings first." ) );
292  return;
293  }
294 
295  m_simulator->LoadNetlist( formatter.GetString() );
296  updateTuners();
297  applyTuners();
298  m_simulator->Run();
299 }
300 
301 
303 {
304  m_simulator->Stop();
305 }
306 
307 
309 {
310  return m_simulator ? m_simulator->IsRunning() : false;
311 }
312 
313 
315 {
316  SIM_PLOT_PANEL* plotPanel = new SIM_PLOT_PANEL( aSimType, m_plotNotebook, wxID_ANY );
317 
318  if( m_welcomePanel )
319  {
320  m_plotNotebook->DeletePage( 0 );
321  m_welcomePanel = nullptr;
322  }
323 
324  m_plotNotebook->AddPage( plotPanel, wxString::Format( wxT( "Plot%u" ),
325  (unsigned int) m_plotNotebook->GetPageCount() + 1 ), true );
326 
327  m_plots[plotPanel] = PLOT_INFO();
328 
329  return plotPanel;
330 }
331 
332 
333 void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
334 {
335  addPlot( aNetName, SPT_VOLTAGE, "V" );
336 }
337 
338 
339 void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName, const wxString& aParam )
340 {
341  addPlot( aDeviceName, SPT_CURRENT, aParam );
342 }
343 
344 
346 {
347  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
348 
349  if( !plotPanel )
350  return;
351 
352  // For now limit the tuner tool to RLC components
353  char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aComponent, 0 )[0];
354 
355  if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR && primitiveType != SP_INDUCTOR )
356  return;
357 
358  const wxString& componentName = aComponent->GetField( REFERENCE )->GetText();
359 
360  // Do not add multiple instances for the same component
361  auto tunerIt = std::find_if( m_tuners.begin(), m_tuners.end(), [&]( const TUNER_SLIDER* t )
362  {
363  return t->GetComponentName() == componentName;
364  }
365  );
366 
367  if( tunerIt != m_tuners.end() )
368  return; // We already have it
369 
370  try
371  {
372  TUNER_SLIDER* tuner = new TUNER_SLIDER( this, m_tunePanel, aComponent );
373  m_tuneSizer->Add( tuner );
374  m_tuners.push_back( tuner );
375  m_tunePanel->Layout();
376  }
377  catch( ... )
378  {
379  // Sorry, no bonus
380  }
381 }
382 
383 
384 void SIM_PLOT_FRAME::RemoveTuner( TUNER_SLIDER* aTuner, bool aErase )
385 {
386  if( aErase )
387  m_tuners.remove( aTuner );
388 
389  aTuner->Destroy();
390  m_tunePanel->Layout();
391 }
392 
393 
395 {
396  wxWindow* curPage = m_plotNotebook->GetCurrentPage();
397 
398  return ( curPage == m_welcomePanel ) ? nullptr : static_cast<SIM_PLOT_PANEL*>( curPage );
399 }
400 
401 
402 void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam )
403 {
404  SIM_TYPE simType = m_exporter->GetSimType();
405 
406  if( !SIM_PLOT_PANEL::IsPlottable( simType ) )
407  return; // TODO else write out in console?
408 
409  // Create a new plot if the current one displays a different type
410  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
411 
412  if( !plotPanel || plotPanel->GetType() != simType )
413  plotPanel = NewPlotPanel( simType );
414 
415  TRACE_DESC descriptor( *m_exporter, aName, aType, aParam );
416 
417  bool updated = false;
418  SIM_PLOT_TYPE xAxisType = GetXAxisType( simType );
419 
420  if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY )
421  {
422  int baseType = descriptor.GetType() & ~( SPT_AC_MAG | SPT_AC_PHASE );
423 
424  // Add two plots: magnitude & phase
425  TRACE_DESC mag_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_MAG ) );
426  TRACE_DESC phase_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_PHASE ) );
427 
428  updated |= updatePlot( mag_desc, plotPanel );
429  updated |= updatePlot( phase_desc, plotPanel );
430  }
431  else
432  {
433  updated = updatePlot( descriptor, plotPanel );
434  }
435 
436  if( updated )
437  {
439  }
440 }
441 
442 
443 void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName, bool aErase )
444 {
445  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
446 
447  if( !plotPanel )
448  return;
449 
450  if( aErase )
451  {
452  auto& traceMap = m_plots[plotPanel].m_traces;
453  auto traceIt = traceMap.find( aPlotName );
454  wxASSERT( traceIt != traceMap.end() );
455  traceMap.erase( traceIt );
456  }
457 
458  wxASSERT( plotPanel->TraceShown( aPlotName ) );
459  plotPanel->DeleteTrace( aPlotName );
460  plotPanel->Fit();
461 
463  updateCursors();
464 }
465 
466 
468 {
470 }
471 
472 
473 bool SIM_PLOT_FRAME::updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL* aPanel )
474 {
475  SIM_TYPE simType = m_exporter->GetSimType();
476  wxString spiceVector = m_exporter->GetSpiceVector( aDescriptor.GetName(),
477  aDescriptor.GetType(), aDescriptor.GetParam() );
478 
479  if( !SIM_PLOT_PANEL::IsPlottable( simType ) )
480  {
481  // There is no plot to be shown
482  m_simulator->Command( wxString::Format( "print %s", spiceVector ).ToStdString() );
483 
484  return false;
485  }
486 
487  // First, handle the x axis
488  wxString xAxisName( m_simulator->GetXAxis( simType ) );
489 
490  if( xAxisName.IsEmpty() )
491  return false;
492 
493  auto data_x = m_simulator->GetMagPlot( (const char*) xAxisName.c_str() );
494  unsigned int size = data_x.size();
495 
496  if( data_x.empty() )
497  return false;
498 
499  SIM_PLOT_TYPE plotType = aDescriptor.GetType();
500  std::vector<double> data_y;
501 
502  // Now, Y axis data
503  switch( m_exporter->GetSimType() )
504  {
505  case ST_AC:
506  {
507  wxASSERT_MSG( !( ( plotType & SPT_AC_MAG ) && ( plotType & SPT_AC_PHASE ) ),
508  "Cannot set both AC_PHASE and AC_MAG bits" );
509 
510  if( plotType & SPT_AC_MAG )
511  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
512  else if( plotType & SPT_AC_PHASE )
513  data_y = m_simulator->GetPhasePlot( (const char*) spiceVector.c_str() );
514  else
515  wxASSERT_MSG( false, "Plot type missing AC_PHASE or AC_MAG bit" );
516  }
517  break;
518 
519  case ST_NOISE:
520  case ST_DC:
521  case ST_TRANSIENT:
522  {
523  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
524  }
525  break;
526 
527  default:
528  wxASSERT_MSG( false, "Unhandled plot type" );
529  return false;
530  }
531 
532  if( data_y.size() != size )
533  return false;
534 
535  if( aPanel->AddTrace( aDescriptor.GetTitle(), size,
536  data_x.data(), data_y.data(), aDescriptor.GetType() ) )
537  {
538  m_plots[aPanel].m_traces.insert( std::make_pair( aDescriptor.GetTitle(), aDescriptor ) );
539  }
540 
541  return true;
542 }
543 
544 
546 {
547  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
548 
549  if( !plotPanel )
550  return;
551 
552  m_signals->ClearAll();
553 
554  wxSize size = m_signals->GetClientSize();
555  m_signals->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x );
556 
557  // Build an image list, to show the color of the corresponding trace
558  // in the plot panel
559  // This image list is used for trace and cursor lists
560  wxMemoryDC bmDC;
561  const int isize = bmDC.GetCharHeight();
562 
563  if( m_signalsIconColorList == NULL )
564  m_signalsIconColorList = new wxImageList( isize, isize, false );
565  else
566  m_signalsIconColorList->RemoveAll();
567 
568  for( const auto& trace : CurrentPlot()->GetTraces() )
569  {
570  wxBitmap bitmap( isize, isize );
571  bmDC.SelectObject( bitmap );
572  wxColour tcolor = trace.second->GetTraceColour();
573 
574  wxColour bgColor = m_signals->wxWindow::GetBackgroundColour();
575  bmDC.SetPen( wxPen( bgColor ) );
576  bmDC.SetBrush( wxBrush( bgColor ) );
577  bmDC.DrawRectangle( 0, 0, isize, isize ); // because bmDC.Clear() does not work in wxGTK
578 
579  bmDC.SetPen( wxPen( tcolor ) );
580  bmDC.SetBrush( wxBrush( tcolor ) );
581  bmDC.DrawRectangle( 0, isize / 4 + 1, isize, isize / 2 );
582 
583  bmDC.SelectObject( wxNullBitmap ); // Needed to initialize bitmap
584 
585  bitmap.SetMask( new wxMask( bitmap, *wxBLACK ) );
586  m_signalsIconColorList->Add( bitmap );
587  }
588 
589  if( bmDC.IsOk() )
590  {
591  bmDC.SetBrush( wxNullBrush );
592  bmDC.SetPen( wxNullPen );
593  }
594 
595  m_signals->SetImageList( m_signalsIconColorList, wxIMAGE_LIST_SMALL );
596 
597  // Fill the signals listctrl. Keep the order of names and
598  // the order of icon color identical, because the icons
599  // are also used in cursor list, and the color index is
600  // calculated from the trace name index
601  int imgidx = 0;
602 
603  for( const auto& trace : m_plots[plotPanel].m_traces )
604  {
605  m_signals->InsertItem( imgidx, trace.first, imgidx );
606  imgidx++;
607  }
608 }
609 
610 
612 {
613  wxQueueEvent( this, new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
614 }
615 
616 
618 {
619  const auto& spiceItems = m_exporter->GetSpiceItems();
620 
621  for( auto it = m_tuners.begin(); it != m_tuners.end(); /* iteration inside the loop */ )
622  {
623  const wxString& ref = (*it)->GetComponentName();
624 
625  if( std::find_if( spiceItems.begin(), spiceItems.end(), [&]( const SPICE_ITEM& item )
626  {
627  return item.m_refName == ref;
628  }) == spiceItems.end() )
629  {
630  // The component does not exist anymore, remove the associated tuner
631  TUNER_SLIDER* tuner = *it;
632  it = m_tuners.erase( it );
633  RemoveTuner( tuner, false );
634  }
635  else
636  {
637  ++it;
638  }
639  }
640 }
641 
642 
644 {
645  for( auto& tuner : m_tuners )
646  {
648  std::string command( "alter @" + tuner->GetSpiceName()
649  + "=" + tuner->GetValue().ToSpiceString() );
650 
651  m_simulator->Command( command );
652  }
653 }
654 
655 
656 bool SIM_PLOT_FRAME::loadWorkbook( const wxString& aPath )
657 {
658  m_plots.clear();
659  m_plotNotebook->DeleteAllPages();
660 
661  wxTextFile file( aPath );
662 
663  if( !file.Open() )
664  return false;
665 
666  long plotsCount;
667 
668  if( !file.GetFirstLine().ToLong( &plotsCount ) ) // GetFirstLine instead of GetNextLine
669  return false;
670 
671  for( long i = 0; i < plotsCount; ++i )
672  {
673  long plotType, tracesCount;
674 
675  if( !file.GetNextLine().ToLong( &plotType ) )
676  return false;
677 
678  SIM_PLOT_PANEL* plotPanel = NewPlotPanel( (SIM_TYPE) plotType );
679  m_plots[plotPanel].m_simCommand = file.GetNextLine();
680  StartSimulation();
681 
682  // Perform simulation, so plots can be added with values
683  do
684  {
685  wxThread::This()->Sleep( 50 );
686  }
687  while( IsSimulationRunning() );
688 
689  if( !file.GetNextLine().ToLong( &tracesCount ) )
690  return false;
691 
692  for( long j = 0; j < tracesCount; ++j )
693  {
694  long traceType;
695  wxString name, param;
696 
697  if( !file.GetNextLine().ToLong( &traceType ) )
698  return false;
699 
700  name = file.GetNextLine();
701  param = file.GetNextLine();
702 
703  if( name.IsEmpty() || param.IsEmpty() )
704  return false;
705 
706  addPlot( name, (SIM_PLOT_TYPE) traceType, param );
707  }
708  }
709 
710  return true;
711 }
712 
713 
714 bool SIM_PLOT_FRAME::saveWorkbook( const wxString& aPath )
715 {
716 
717  wxString savePath = aPath;
718 
719  if( !savePath.Lower().EndsWith(".wbk"))
720  {
721  savePath += ".wbk";
722  };
723 
724 
725  wxTextFile file( savePath );
726 
727  if( file.Exists() )
728  {
729  if( !file.Open() )
730  return false;
731 
732  file.Clear();
733  }
734  else
735  {
736  file.Create();
737  }
738 
739  file.AddLine( wxString::Format( "%lu", m_plots.size() ) );
740 
741  for( const auto& plot : m_plots )
742  {
743  file.AddLine( wxString::Format( "%d", plot.first->GetType() ) );
744  file.AddLine( plot.second.m_simCommand );
745  file.AddLine( wxString::Format( "%lu", plot.second.m_traces.size() ) );
746 
747  for( const auto& trace : plot.second.m_traces )
748  {
749  file.AddLine( wxString::Format( "%d", trace.second.GetType() ) );
750  file.AddLine( trace.second.GetName() );
751  file.AddLine( trace.second.GetParam() );
752  }
753  }
754 
755  bool res = file.Write();
756  file.Close();
757 
758  return res;
759 }
760 
761 
763 {
764  switch( aType )
765  {
766  case ST_AC:
767  return SPT_LIN_FREQUENCY;
769 
770  case ST_DC:
771  return SPT_SWEEP;
772 
773  case ST_TRANSIENT:
774  return SPT_TIME;
775 
776  default:
777  wxASSERT_MSG( false, "Unhandled simulation type" );
778  return (SIM_PLOT_TYPE) 0;
779  }
780 }
781 
782 
783 void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent )
784 {
785  SIM_TYPE type = m_exporter->GetSimType();
786 
787  if( SIM_PLOT_PANEL::IsPlottable( type ) )
788  {
789  SIM_PLOT_PANEL* prevPlot = CurrentPlot();
790  SIM_PLOT_PANEL* newPlot = NewPlotPanel( type );
791 
792  // If the previous plot had the same type, copy the simulation command
793  if( prevPlot )
794  m_plots[newPlot].m_simCommand = m_plots[prevPlot].m_simCommand;
795  }
796 }
797 
798 
799 void SIM_PLOT_FRAME::menuOpenWorkbook( wxCommandEvent& event )
800 {
801  wxFileDialog openDlg( this, _( "Open simulation workbook" ), m_savedWorkbooksPath, "",
802  WorkbookFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
803 
804  if( openDlg.ShowModal() == wxID_CANCEL )
805  return;
806 
807  m_savedWorkbooksPath = openDlg.GetDirectory();
808 
809  if( !loadWorkbook( openDlg.GetPath() ) )
810  DisplayError( this, _( "There was an error while opening the workbook file" ) );
811 }
812 
813 
814 void SIM_PLOT_FRAME::menuSaveWorkbook( wxCommandEvent& event )
815 {
816  if( !CurrentPlot() )
817  return;
818 
819  wxFileDialog saveDlg( this, _( "Save Simulation Workbook" ), m_savedWorkbooksPath, "",
820  WorkbookFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
821 
822  if( saveDlg.ShowModal() == wxID_CANCEL )
823  return;
824 
825  m_savedWorkbooksPath = saveDlg.GetDirectory();
826 
827  if( !saveWorkbook( saveDlg.GetPath() ) )
828  DisplayError( this, _( "There was an error while saving the workbook file" ) );
829 }
830 
831 
832 void SIM_PLOT_FRAME::menuSaveImage( wxCommandEvent& event )
833 {
834  if( !CurrentPlot() )
835  return;
836 
837  wxFileDialog saveDlg( this, _( "Save Plot as Image" ), "", "",
838  PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
839 
840  if( saveDlg.ShowModal() == wxID_CANCEL )
841  return;
842 
843  CurrentPlot()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
844 }
845 
846 
847 void SIM_PLOT_FRAME::menuSaveCsv( wxCommandEvent& event )
848 {
849  if( !CurrentPlot() )
850  return;
851 
852  const wxChar SEPARATOR = ';';
853 
854  wxFileDialog saveDlg( this, _( "Save Plot Data" ), "", "",
855  CsvFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
856 
857  if( saveDlg.ShowModal() == wxID_CANCEL )
858  return;
859 
860  wxFile out( saveDlg.GetPath(), wxFile::write );
861  bool timeWritten = false;
862 
863  for( const auto& t : CurrentPlot()->GetTraces() )
864  {
865  const TRACE* trace = t.second;
866 
867  if( !timeWritten )
868  {
869  out.Write( wxString::Format( "Time%c", SEPARATOR ) );
870 
871  for( double v : trace->GetDataX() )
872  out.Write( wxString::Format( "%f%c", v, SEPARATOR ) );
873 
874  out.Write( "\r\n" );
875  timeWritten = true;
876  }
877 
878  out.Write( wxString::Format( "%s%c", t.first, SEPARATOR ) );
879 
880  for( double v : trace->GetDataY() )
881  out.Write( wxString::Format( "%f%c", v, SEPARATOR ) );
882 
883  out.Write( "\r\n" );
884  }
885 
886  out.Close();
887 }
888 
889 
890 void SIM_PLOT_FRAME::menuZoomIn( wxCommandEvent& event )
891 {
892  if( CurrentPlot() )
893  CurrentPlot()->ZoomIn();
894 }
895 
896 
897 void SIM_PLOT_FRAME::menuZoomOut( wxCommandEvent& event )
898 {
899  if( CurrentPlot() )
900  CurrentPlot()->ZoomOut();
901 }
902 
903 
904 void SIM_PLOT_FRAME::menuZoomFit( wxCommandEvent& event )
905 {
906  if( CurrentPlot() )
907  CurrentPlot()->Fit();
908 }
909 
910 
911 void SIM_PLOT_FRAME::menuShowGrid( wxCommandEvent& event )
912 {
913  SIM_PLOT_PANEL* plot = CurrentPlot();
914 
915  if( plot )
916  plot->ShowGrid( !plot->IsGridShown() );
917 }
918 
919 
920 void SIM_PLOT_FRAME::menuShowGridUpdate( wxUpdateUIEvent& event )
921 {
922  SIM_PLOT_PANEL* plot = CurrentPlot();
923 
924  event.Check( plot ? plot->IsGridShown() : false );
925 }
926 
927 
928 void SIM_PLOT_FRAME::menuShowLegend( wxCommandEvent& event )
929 {
930  SIM_PLOT_PANEL* plot = CurrentPlot();
931 
932  if( plot )
933  plot->ShowLegend( !plot->IsLegendShown() );
934 }
935 
936 
937 void SIM_PLOT_FRAME::menuShowLegendUpdate( wxUpdateUIEvent& event )
938 {
939  SIM_PLOT_PANEL* plot = CurrentPlot();
940  event.Check( plot ? plot->IsLegendShown() : false );
941 }
942 
943 
944 void SIM_PLOT_FRAME::onPlotClose( wxAuiNotebookEvent& event )
945 {
946  int idx = event.GetSelection();
947 
948  if( idx == wxNOT_FOUND )
949  return;
950 
951  SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetPage( idx ) );
952 
953  if( !plotPanel )
954  return;
955 
956  m_plots.erase( plotPanel );
958  updateCursors();
959 }
960 
961 
962 void SIM_PLOT_FRAME::onPlotChanged( wxAuiNotebookEvent& event )
963 {
965  updateCursors();
966 }
967 
968 
969 void SIM_PLOT_FRAME::onSignalDblClick( wxMouseEvent& event )
970 {
971  // Remove signal from the plot panel when double clicked
972  long idx = m_signals->GetFocusedItem();
973 
974  if( idx != wxNOT_FOUND )
975  removePlot( m_signals->GetItemText( idx, 0 ) );
976 }
977 
978 
979 void SIM_PLOT_FRAME::onSignalRClick( wxListEvent& event )
980 {
981  int idx = event.GetIndex();
982 
983  if( idx != wxNOT_FOUND )
984  m_signals->Select( idx );
985 
986  idx = m_signals->GetFirstSelected();
987 
988  if( idx != wxNOT_FOUND )
989  {
990  const wxString& netName = m_signals->GetItemText( idx, 0 );
991  SIGNAL_CONTEXT_MENU ctxMenu( netName, this );
992  m_signals->PopupMenu( &ctxMenu );
993  }
994 }
995 
996 
997 void SIM_PLOT_FRAME::onSimulate( wxCommandEvent& event )
998 {
999  if( IsSimulationRunning() )
1000  StopSimulation();
1001  else
1002  StartSimulation();
1003 }
1004 
1005 
1006 void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
1007 {
1008  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1009 
1010  // Initial processing is required to e.g. display a list of power sources
1012 
1013  if( !m_exporter->ProcessNetlist( NET_ALL_FLAGS ) )
1014  {
1015  DisplayError( this, _( "There were errors during netlist export, aborted." ) );
1016  return;
1017  }
1018 
1019  if( !m_settingsDlg )
1020  m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
1021 
1022  if( plotPanel )
1023  m_settingsDlg->SetSimCommand( m_plots[plotPanel].m_simCommand );
1024 
1026 
1027  if( m_settingsDlg->ShowModal() == wxID_OK )
1028  {
1029  wxString newCommand = m_settingsDlg->GetSimCommand();
1030  SIM_TYPE newSimType = NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( newCommand );
1031 
1032  // If it is a new simulation type, open a new plot
1033  if( !plotPanel || ( plotPanel && plotPanel->GetType() != newSimType ) )
1034  {
1035  plotPanel = NewPlotPanel( newSimType );
1036  }
1037 
1038  m_plots[plotPanel].m_simCommand = newCommand;
1039  }
1040 }
1041 
1042 
1043 void SIM_PLOT_FRAME::onAddSignal( wxCommandEvent& event )
1044 {
1045  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1046 
1047  if( !plotPanel || !m_exporter || plotPanel->GetType() != m_exporter->GetSimType() )
1048  {
1049  DisplayInfoMessage( this, _( "You need to run simulation first." ) );
1050  return;
1051  }
1052 
1053  DIALOG_SIGNAL_LIST dialog( this, m_exporter.get() );
1054  dialog.ShowModal();
1055 }
1056 
1057 
1058 void SIM_PLOT_FRAME::onProbe( wxCommandEvent& event )
1059 {
1060  if( m_schematicFrame == NULL )
1061  return;
1062 
1063  wxQueueEvent( m_schematicFrame, new wxCommandEvent( wxEVT_TOOL, ID_SIM_PROBE ) );
1064  m_schematicFrame->Raise();
1065 }
1066 
1067 
1068 void SIM_PLOT_FRAME::onTune( wxCommandEvent& event )
1069 {
1070  if( m_schematicFrame == NULL )
1071  return;
1072 
1073  wxQueueEvent( m_schematicFrame, new wxCommandEvent( wxEVT_TOOL, ID_SIM_TUNE ) );
1074  m_schematicFrame->Raise();
1075 }
1076 
1077 
1078 void SIM_PLOT_FRAME::onClose( wxCloseEvent& aEvent )
1079 {
1080  SaveSettings( config() );
1081 
1082  if( IsSimulationRunning() )
1083  m_simulator->Stop();
1084 
1085  Destroy();
1086 }
1087 
1088 
1089 void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
1090 {
1091  wxSize size = m_cursors->GetClientSize();
1092  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1093  m_cursors->ClearAll();
1094 
1095  if( !plotPanel )
1096  return;
1097 
1099  m_cursors->SetImageList(m_signalsIconColorList, wxIMAGE_LIST_SMALL);
1100 
1101  // Fill the signals listctrl
1102  m_cursors->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 );
1103  const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT, size.x / 4 );
1104 
1105  wxString labelY1 = plotPanel->GetLabelY1();
1106  wxString labelY2 = plotPanel->GetLabelY2();
1107  wxString labelY;
1108 
1109  if( !labelY2.IsEmpty() )
1110  labelY = labelY1 + " / " + labelY2;
1111  else
1112  labelY = labelY1;
1113 
1114  const long Y_COL = m_cursors->AppendColumn( labelY, wxLIST_FORMAT_LEFT, size.x / 4 );
1115 
1116  // Update cursor values
1117  int itemidx = 0;
1118  for( const auto& trace : plotPanel->GetTraces() )
1119  {
1120  if( CURSOR* cursor = trace.second->GetCursor() )
1121  {
1122  // Find the right icon color in list.
1123  // It is the icon used in m_signals list for the same trace
1124  long iconColor = m_signals->FindItem( -1, trace.first );
1125 
1126  const wxRealPoint coords = cursor->GetCoords();
1127  long idx = m_cursors->InsertItem( itemidx++, trace.first, iconColor );
1128  m_cursors->SetItem( idx, X_COL, SPICE_VALUE( coords.x ).ToSpiceString() );
1129  m_cursors->SetItem( idx, Y_COL, SPICE_VALUE( coords.y ).ToSpiceString() );
1130  }
1131  }
1132 }
1133 
1134 
1135 void SIM_PLOT_FRAME::onSimStarted( wxCommandEvent& aEvent )
1136 {
1137  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( sim_stop_xpm ) );
1138  SetCursor( wxCURSOR_ARROWWAIT );
1139 }
1140 
1141 
1142 void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
1143 {
1144  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( sim_run_xpm ) );
1145  SetCursor( wxCURSOR_ARROW );
1146 
1147  SIM_TYPE simType = m_exporter->GetSimType();
1148 
1149  if( simType == ST_UNKNOWN )
1150  return;
1151 
1152  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1153 
1154  if( !plotPanel || plotPanel->GetType() != simType )
1155  plotPanel = NewPlotPanel( simType );
1156 
1157  if( IsSimulationRunning() )
1158  return;
1159 
1160  // If there are any signals plotted, update them
1161  if( SIM_PLOT_PANEL::IsPlottable( simType ) )
1162  {
1163  TRACE_MAP& traceMap = m_plots[plotPanel].m_traces;
1164 
1165  for( auto it = traceMap.begin(); it != traceMap.end(); /* iteration occurs in the loop */)
1166  {
1167  if( !updatePlot( it->second, plotPanel ) )
1168  {
1169  removePlot( it->first, false );
1170  it = traceMap.erase( it ); // remove a plot that does not exist anymore
1171  }
1172  else
1173  {
1174  ++it;
1175  }
1176  }
1177 
1178  updateSignalList();
1179  plotPanel->UpdateAll();
1180  plotPanel->ResetScales();
1181  }
1182  else
1183  {
1185  for( const auto& net : m_exporter->GetNetIndexMap() )
1186  {
1187  int node = net.second;
1188 
1189  if( node > 0 )
1190  m_simulator->Command( wxString::Format( "print v(%d)", node ).ToStdString() );
1191  }
1192  }
1193 }
1194 
1195 
1196 void SIM_PLOT_FRAME::onSimUpdate( wxCommandEvent& aEvent )
1197 {
1198  if( IsSimulationRunning() )
1199  StopSimulation();
1200 
1201  if( CurrentPlot() != m_lastSimPlot )
1202  {
1203  // We need to rerun simulation, as the simulator currently stores
1204  // results for another plot
1205  StartSimulation();
1206  }
1207  else
1208  {
1209  // Incremental update
1210  m_simConsole->Clear();
1211  // Do not export netlist, it is already stored in the simulator
1212  applyTuners();
1213  m_simulator->Run();
1214  }
1215 }
1216 
1217 
1218 void SIM_PLOT_FRAME::onSimReport( wxCommandEvent& aEvent )
1219 {
1220  m_simConsole->AppendText( aEvent.GetString() + "\n" );
1221  m_simConsole->SetInsertionPointEnd();
1222 }
1223 
1224 
1226  SIM_PLOT_FRAME* aPlotFrame )
1227  : m_signal( aSignal ), m_plotFrame( aPlotFrame )
1228 {
1230 
1231  AddMenuItem( this, HIDE_SIGNAL, _( "Hide Signal" ),
1232  _( "Erase the signal from plot screen" ),
1233  KiBitmap( delete_xpm ) );
1234 
1235  TRACE* trace = plot->GetTrace( m_signal );
1236 
1237  if( trace->HasCursor() )
1238  AddMenuItem( this, HIDE_CURSOR, _( "Hide Cursor" ),
1239  wxEmptyString, KiBitmap( pcb_target_xpm ) );
1240  else
1241  AddMenuItem( this, SHOW_CURSOR, _( "Show Cursor" ),
1242  wxEmptyString, KiBitmap( pcb_target_xpm ) );
1243 
1244  Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ), NULL, this );
1245 }
1246 
1247 
1249 {
1251 
1252  switch( aEvent.GetId() )
1253  {
1254  case HIDE_SIGNAL:
1256  break;
1257 
1258  case SHOW_CURSOR:
1259  plot->EnableCursor( m_signal, true );
1260  break;
1261 
1262  case HIDE_CURSOR:
1263  plot->EnableCursor( m_signal, false );
1264  break;
1265  }
1266 }
1267 
1268 wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
1269 wxDEFINE_EVENT( EVT_SIM_REPORT, wxCommandEvent );
1270 
1271 wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
1272 wxDEFINE_EVENT( EVT_SIM_FINISHED, wxCommandEvent );
void onAddSignal(wxCommandEvent &event)
void ZoomOut(const wxPoint &centerPoint=wxDefaultPosition)
Zoom out current view and refresh display.
Definition: mathplot.cpp:2306
virtual std::string GetXAxis(SIM_TYPE aType) const =0
Returns X axis name for a given simulation type
bool saveWorkbook(const wxString &aPath)
Saves plot settings to a file.
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
Function SetKiway.
wxToolBarToolBase * m_toolProbe
void LoadSettings(wxConfigBase *aCfg) override
Function LoadSettings loads common frame parameters from a configuration file.
void onSimStarted(wxCommandEvent &aEvent)
NETLIST_OBJECT_LIST * BuildNetListBase(bool updateStatusText=true)
Create a flat list which stores all connected objects.
void RemoveTuner(TUNER_SLIDER *aTuner, bool aErase=true)
Removes an existing tuner.
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_player.h:60
const wxString & GetName() const
wxImageList * m_signalsIconColorList
imagelists uset to add a small coloured icon to signal names and cursors name, the same color as the ...
SIM_PLOT_TYPE operator|(SIM_PLOT_TYPE aFirst, SIM_PLOT_TYPE aSecond)
void onPlotChanged(wxAuiNotebookEvent &event) override
virtual bool IsRunning()=0
Checks if simulation is running at the moment.
long trace
Definition: solve.cpp:232
SIM_PLOT_FRAME * m_parent
void onSignalDblClick(wxMouseEvent &event) override
bool SetSimCommand(const wxString &aCommand)
wxString ToSpiceString() const
Returns string value in Spice format (e.g.
virtual std::vector< double > GetPhasePlot(const std::string &aName, int aMaxLen=-1)=0
Returns a requested vector with phase values.
This file is part of the common library.
virtual void SetReporter(SPICE_REPORTER *aReporter)
Sets a SPICE_REPORTER object to receive the simulation log.
wxSplitterWindow * m_splitterSignals
SIM_PLOT_TYPE GetXAxisType(SIM_TYPE aType) const
Returns X axis for a given simulation type.
bool TraceShown(const wxString &aName) const
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:174
const std::vector< double > & GetDataY() const
#define SIGNALS_PANEL_HEIGHT_ENTRY
void ShowLegend(bool aEnable)
int m_splitterPlotAndConsoleSashPosition
wxString GetLabelX() const
void menuZoomFit(wxCommandEvent &event) override
Structure to represent a schematic component in the Spice simulation.
virtual void SaveSettings(wxConfigBase *aCfg)
Function SaveSettings saves common frame parameters to a configuration data file. ...
static bool IsPlottable(SIM_TYPE aSimType)
SIM_PLOT_TYPE GetType() const
std::list< TUNER_SLIDER * > m_tuners
List of currently displayed tuners
wxString m_title
Title displayed in the signal list/plot legend
Class SIM_PLOT_FRAME_BASE.
const wxString & GetParam() const
void menuNewPlot(wxCommandEvent &aEvent) override
void applyTuners()
Applies component values specified using tunder sliders to the current netlist.
void AddVoltagePlot(const wxString &aNetName)
Adds a voltage plot for a given net name.
virtual wxConfigBase * config()
Function config returns the wxConfigBase used in SaveSettings(), and is overloaded in KICAD_MANAGER_F...
void AddCurrentPlot(const wxString &aDeviceName, const wxString &aParam)
Adds a current plot for a particular device.
Trace descriptor class
Schematic editor (Eeschema) main window.
wxString CsvFileWildcard()
void onSimUpdate(wxCommandEvent &aEvent)
void menuOpenWorkbook(wxCommandEvent &event) override
void menuShowGrid(wxCommandEvent &event) override
void menuZoomIn(wxCommandEvent &event) override
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
void menuZoomOut(wxCommandEvent &event) override
SIM_THREAD_REPORTER * m_reporter
void OnSimStateChange(SPICE_SIMULATOR *aObject, SIM_STATE aNewState) override
bool updatePlot(const TRACE_DESC &aDescriptor, SIM_PLOT_PANEL *aPanel)
Updates plot in a particular SIM_PLOT_PANEL.
Field Reference of part, i.e. "IC21".
void updateCursors()
Updates the cursor values list.
wxSplitterWindow * m_splitterTuneValues
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Returns simulation type basing on a simulation command directive.
void menuSaveCsv(wxCommandEvent &event) override
void onPlotClose(wxAuiNotebookEvent &event) override
wxAuiNotebook * m_plotNotebook
SCH_EDIT_FRAME * m_schematicFrame
bool DeleteTrace(const wxString &aName)
void UpdateAll()
Refresh display.
Definition: mathplot.cpp:2814
bool IsGridShown() const
int GetNetlistOptions() const
void EnableCursor(const wxString &aName, bool aEnable)
Toggles cursor for a particular trace.
SIM_STATE
void setSubWindowsSashSize()
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:78
virtual void Init()=0
Intializes the simulator
bool IsLegendShown() const
#define PLOT_PANEL_WIDTH_ENTRY
SEVERITY
Severity of the reported messages.
Definition: reporter.h:65
wxString GetLabelY2() const
std::map< SIM_PLOT_PANEL *, PLOT_INFO > m_plots
Map of plot panels and associated data
SIM_PLOT_PANEL * m_lastSimPlot
Panel that was used as the most recent one for simulations
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:300
const std::map< wxString, TRACE * > & GetTraces() const
wxString GetLabelY1() const
Helper class to handle Spice way of expressing values (e.g. 10.5 Meg)
Definition: spice_value.h:32
wxSplitterWindow * m_splitterLeftRight
void ZoomIn(const wxPoint &centerPoint=wxDefaultPosition)
Zoom into current view and refresh display.
Definition: mathplot.cpp:2249
#define CURSORS_PANEL_HEIGHT_ENTRY
wxMenuItem * m_runSimulation
void onSimReport(wxCommandEvent &aEvent)
SIM_TYPE
Possible simulation types
Definition: sim_types.h:29
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:128
virtual void LoadSettings(wxConfigBase *aCfg)
Function LoadSettings loads common frame parameters from a configuration file.
void onSimFinished(wxCommandEvent &aEvent)
Interface to receive simulation updates from SPICE_SIMULATOR class.
virtual bool Command(const std::string &aCmd)=0
Executes a Spice command as if it was typed into console.
bool AddTrace(const wxString &aName, int aPoints, const double *aX, const double *aY, SIM_PLOT_TYPE aFlags)
The common library.
SIM_THREAD_REPORTER(SIM_PLOT_FRAME *aParent)
void menuShowLegendUpdate(wxUpdateUIEvent &event) override
Class KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within...
Definition: kiway.h:258
wxToolBarToolBase * m_toolAddSignals
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
int m_splitterTuneValuesSashPosition
TRACE_DESC(const NETLIST_EXPORTER_PSPICE_SIM &aExporter, const wxString &aName, SIM_PLOT_TYPE aType, const wxString &aParam)
const std::string & GetString()
Definition: richio.h:475
void onSignalRClick(wxListEvent &event) override
void ResetScales()
Resets scale ranges to fit the current traces
bool IsSimulationRunning()
SPICE_SIMULATOR * m_simulator
void menuShowLegend(wxCommandEvent &event) override
#define PLOT_PANEL_HEIGHT_ENTRY
void ShowGrid(bool aEnable)
void onTune(wxCommandEvent &event)
wxToolBarToolBase * m_toolSimulate
SIM_TYPE GetType() const
void menuSaveImage(wxCommandEvent &event) override
wxString PngFileWildcard()
Implementing SIM_PLOT_FRAME_BASE.
bool loadWorkbook(const wxString &aPath)
Loads plot settings from a file.
void SetNetlistExporter(NETLIST_EXPORTER_PSPICE_SIM *aExporter)
static wxString m_savedWorkbooksPath
A string to store the path of saved workbooks during a session
virtual bool LoadNetlist(const std::string &aNetlist)=0
void onCursorUpdate(wxCommandEvent &aEvent)
DIALOG_SIM_SETTINGS * m_settingsDlg
void Fit() override
Set view to fit global bounding box of all plot layers and refresh display.
Definition: mathplot.cpp:2006
virtual bool Run()=0
Executes the simulation with currently loaded netlist.
const wxString & GetSimCommand() const
bool HasCursor() const
std::unique_ptr< NETLIST_EXPORTER_PSPICE_SIM > m_exporter
void updateNetlistExporter()
Reloads the current schematic for the netlist exporter.
see class PGM_BASE
void onSimulate(wxCommandEvent &event)
const char * name
Definition: DXF_plotter.cpp:61
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
SIGNAL_CONTEXT_MENU(const wxString &aSignal, SIM_PLOT_FRAME *aPlotFrame)
void onProbe(wxCommandEvent &event)
void updateSignalList()
Updates the list of currently plotted signals.
TRACE * GetTrace(const wxString &aName) const
const wxString & GetTitle() const
static wxString GetSpiceField(SPICE_FIELD aField, SCH_COMPONENT *aComponent, unsigned aCtl)
Retrieves either the requested field value or the default value.
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
int m_splitterSignalsSashPosition
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:100
SIM_PLOT_PANEL * CurrentPlot() const
Returns the currently opened plot panel (or NULL if there is none).
std::map< wxString, TRACE_DESC > TRACE_MAP
wxDEFINE_EVENT(EVT_SIM_UPDATE, wxCommandEvent)
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
int m_splitterLeftRightSashPosition
virtual bool Stop()=0
Halts the simulation.
const std::vector< double > & GetDataX() const
void removePlot(const wxString &aPlotName, bool aErase=true)
Removes a plot with a specific title.
void SaveSettings(wxConfigBase *aCfg) override
Function SaveSettings saves common frame parameters to a configuration data file. ...
Custom widget to handle quick component values modification and simulation on the fly...
Definition: tuner_slider.h:40
void AddTuner(SCH_COMPONENT *aComponent)
Adds a tuner for a component.
wxString WorkbookFileWildcard()
bool SaveScreenshot(const wxString &filename, wxBitmapType type=wxBITMAP_TYPE_BMP, wxSize imageSize=wxDefaultSize, bool fit=false)
Draw the window on a wxBitmap, then save it to a file.
Definition: mathplot.cpp:3044
wxSplitterWindow * m_splitterPlotAndConsole
void menuShowGridUpdate(wxUpdateUIEvent &event) override
bool HasMessage() const override
Function HasMessage Returns true if the reporter client is non-empty.
void menuSaveWorkbook(wxCommandEvent &event) override
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:272
Class STRING_FORMATTER implements OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:445
SIM_PLOT_TYPE
Possible plot types
Definition: sim_types.h:35
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED) override
Function Report is a pure virtual function to override in the derived object.
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:241
static SPICE_SIMULATOR * CreateInstance(const std::string &aName)
Creates a simulator instance of particular type (currently only ngspice is handled) ...
void addPlot(const wxString &aName, SIM_PLOT_TYPE aType, const wxString &aParam)
Adds a new plot to the current panel.
void onSettings(wxCommandEvent &event)
void onClose(wxCloseEvent &aEvent)
wxToolBarToolBase * m_toolTune
void onMenuEvent(wxMenuEvent &aEvent)
SIM_PLOT_PANEL * NewPlotPanel(SIM_TYPE aSimType)
Creates a new plot panel for a given simulation type and adds it to the main notebook.
virtual std::vector< double > GetMagPlot(const std::string &aName, int aMaxLen=-1)=0
Returns a requested vector with magnitude values.
Cursor attached to a trace to follow its values:
Special netlist exporter flavor that allows to override simulation commands.
void updateTuners()
Filters out tuners for components that do not exist anymore.
wxToolBarToolBase * m_toolSettings
SIM_PLOT_FRAME(KIWAY *aKiway, wxWindow *aParent)
Constructor.