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 <wx/stc/stc.h>
28 
29 #include <sch_edit_frame.h>
30 #include <eeschema_id.h>
31 #include <kiway.h>
32 #include <confirm.h>
33 #include <bitmaps.h>
35 
36 #include <widgets/tuner_slider.h>
39 #include <pgm_base.h>
40 
41 #include "sim_plot_frame.h"
42 #include "sim_plot_panel.h"
43 #include "spice_simulator.h"
44 #include "spice_reporter.h"
45 
46 #include <menus_helpers.h>
47 
49 {
50  int res = (int) aFirst | (int) aSecond;
51 
52  return (SIM_PLOT_TYPE) res;
53 }
54 
55 
57 {
58 public:
60  : m_parent( aParent )
61  {
62  }
63 
64  REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_UNDEFINED ) override
65  {
66  wxCommandEvent* event = new wxCommandEvent( EVT_SIM_REPORT );
67  event->SetString( aText );
68  wxQueueEvent( m_parent, event );
69  return *this;
70  }
71 
72  bool HasMessage() const override
73  {
74  return false; // Technically "indeterminate" rather than false.
75  }
76 
77  void OnSimStateChange( SPICE_SIMULATOR* aObject, SIM_STATE aNewState ) override
78  {
79  wxCommandEvent* event = NULL;
80 
81  switch( aNewState )
82  {
83  case SIM_IDLE:
84  event = new wxCommandEvent( EVT_SIM_FINISHED );
85  break;
86 
87  case SIM_RUNNING:
88  event = new wxCommandEvent( EVT_SIM_STARTED );
89  break;
90 
91  default:
92  wxFAIL;
93  return;
94  }
95 
96  wxQueueEvent( m_parent, event );
97  }
98 
99 private:
101 };
102 
103 
104 TRACE_DESC::TRACE_DESC( const NETLIST_EXPORTER_PSPICE_SIM& aExporter, const wxString& aName,
105  SIM_PLOT_TYPE aType, const wxString& aParam )
106  : m_name( aName ), m_type( aType ), m_param( aParam )
107 {
108  // Title generation
109  m_title = wxString::Format( "%s(%s)", aParam, aName );
110 
111  if( aType & SPT_AC_MAG )
112  m_title += " (mag)";
113  else if( aType & SPT_AC_PHASE )
114  m_title += " (phase)";
115 }
116 
117 // Store the path of saved workbooks during the session
119 
120 SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
121  : SIM_PLOT_FRAME_BASE( aParent ), m_lastSimPlot( nullptr )
122 {
123  SetKiway( this, aKiway );
124  m_signalsIconColorList = NULL;
125 
127 
128  if( m_schematicFrame == NULL )
129  throw std::runtime_error( "There is no schematic window" );
130 
131  // Give an icon
132  wxIcon icon;
133  icon.CopyFromBitmap( KiBitmap( simulator_xpm ) );
134  SetIcon( icon );
135 
136  // Gives a minimal size
137  SetSizeHints( 500, 400, -1, -1, -1, -1 );
138 
139  // Get the previous size and position of windows:
140  LoadSettings( config() );
141 
143 
144  if( !m_simulator )
145  {
146  throw std::runtime_error( "Could not create simulator instance" );
147  return;
148  }
149 
150  m_simulator->Init();
151 
152  if( m_savedWorkbooksPath.IsEmpty() )
153  {
155  }
156 
157  m_reporter = new SIM_THREAD_REPORTER( this );
158  m_simulator->SetReporter( m_reporter );
159 
161 
162  Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SIM_PLOT_FRAME::onClose ), NULL, this );
163  Connect( EVT_SIM_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onSimUpdate ), NULL, this );
164  Connect( EVT_SIM_REPORT, wxCommandEventHandler( SIM_PLOT_FRAME::onSimReport ), NULL, this );
165  Connect( EVT_SIM_STARTED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimStarted ), NULL, this );
166  Connect( EVT_SIM_FINISHED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimFinished ), NULL, this );
167  Connect( EVT_SIM_CURSOR_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onCursorUpdate ), NULL, this );
168 
169  // Toolbar buttons
170  m_toolSimulate = m_toolBar->AddTool( ID_SIM_RUN, _( "Run/Stop Simulation" ),
171  KiBitmap( sim_run_xpm ), _( "Run Simulation" ), wxITEM_NORMAL );
172  m_toolAddSignals = m_toolBar->AddTool( ID_SIM_ADD_SIGNALS, _( "Add Signals" ),
173  KiBitmap( sim_add_signal_xpm ), _( "Add signals to plot" ), wxITEM_NORMAL );
174  m_toolProbe = m_toolBar->AddTool( ID_SIM_PROBE, _( "Probe" ),
175  KiBitmap( sim_probe_xpm ), _( "Probe signals on the schematic" ), wxITEM_NORMAL );
176  m_toolTune = m_toolBar->AddTool( ID_SIM_TUNE, _( "Tune" ),
177  KiBitmap( sim_tune_xpm ), _( "Tune component values" ), wxITEM_NORMAL );
178  m_toolSettings = m_toolBar->AddTool( wxID_ANY, _( "Settings" ),
179  KiBitmap( sim_settings_xpm ), _( "Simulation settings" ), wxITEM_NORMAL );
180 
181  Connect( m_toolSimulate->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
182  wxCommandEventHandler( SIM_PLOT_FRAME::onSimulate ), NULL, this );
183  Connect( m_toolAddSignals->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
184  wxCommandEventHandler( SIM_PLOT_FRAME::onAddSignal ), NULL, this );
185  Connect( m_toolProbe->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
186  wxCommandEventHandler( SIM_PLOT_FRAME::onProbe ), NULL, this );
187  Connect( m_toolTune->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
188  wxCommandEventHandler( SIM_PLOT_FRAME::onTune ), NULL, this );
189  Connect( m_toolSettings->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
190  wxCommandEventHandler( SIM_PLOT_FRAME::onSettings ), NULL, this );
191 
192  // Bind toolbar buttons event to existing menu event handlers, so they behave the same
193  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSimulate, this, m_runSimulation->GetId() );
194  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onAddSignal, this, m_addSignals->GetId() );
195  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onProbe, this, m_probeSignals->GetId() );
196  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onTune, this, m_tuneValue->GetId() );
197  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onShowNetlist, this, m_showNetlist->GetId() );
198  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this, m_settings->GetId() );
199 
200  m_toolBar->Realize();
201  m_plotNotebook->SetPageText( 0, _( "Welcome!" ) );
202 
203  // the settings dialog will be created later, on demand.
204  // if created in the ctor, for some obscure reason, there is an issue
205  // on Windows: when open it, the simulator frame is sent to the background.
206  // instead of being behind the dialog frame (as it does)
207  m_settingsDlg = NULL;
208 
209  // resize the subwindows size. At least on Windows, calling wxSafeYield before
210  // resizing the subwindows forces the wxSplitWindows size events automatically generated
211  // by wxWidgets to be executed before our resize code.
212  // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
213  // events
214  wxSafeYield();
216 }
217 
218 
220 {
221  m_simulator->SetReporter( nullptr );
222  delete m_reporter;
223  delete m_signalsIconColorList;
224 
225  if( m_settingsDlg )
226  m_settingsDlg->Destroy();
227 }
228 
229 #define PLOT_PANEL_WIDTH_ENTRY "SimPlotPanelWidth"
230 #define PLOT_PANEL_HEIGHT_ENTRY "SimPlotPanelHeight"
231 #define SIGNALS_PANEL_HEIGHT_ENTRY "SimSignalPanelHeight"
232 #define CURSORS_PANEL_HEIGHT_ENTRY "SimCursorsPanelHeight"
233 
234 void SIM_PLOT_FRAME::SaveSettings( wxConfigBase* aCfg )
235 {
236  // Save main frame size and position:
238 
239  // Save subwindows sizes
240  aCfg->Write( PLOT_PANEL_WIDTH_ENTRY, m_splitterLeftRight->GetSashPosition() );
241  aCfg->Write( PLOT_PANEL_HEIGHT_ENTRY, m_splitterPlotAndConsole->GetSashPosition() );
242  aCfg->Write( SIGNALS_PANEL_HEIGHT_ENTRY, m_splitterSignals->GetSashPosition() );
243  aCfg->Write( CURSORS_PANEL_HEIGHT_ENTRY, m_splitterTuneValues->GetSashPosition() );
244 }
245 
246 
247 void SIM_PLOT_FRAME::LoadSettings( wxConfigBase* aCfg )
248 {
249  // Read main frame size and position:
251  SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
252 
253  // Read subwindows sizes (should be > 0 )
258 }
259 
260 
262 {
265 
268 
271 
274 }
275 
276 
278 {
279  STRING_FORMATTER formatter;
280  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
281 
282  if( !m_settingsDlg )
283  m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
284 
285  m_simConsole->Clear();
287 
288  if( plotPanel )
289  m_exporter->SetSimCommand( m_plots[plotPanel].m_simCommand );
290 
291  if( !m_exporter->Format( &formatter, m_settingsDlg->GetNetlistOptions() ) )
292  {
293  DisplayError( this, _( "There were errors during netlist export, aborted." ) );
294  return;
295  }
296 
297  if( m_exporter->GetSimType() == ST_UNKNOWN )
298  {
299  DisplayInfoMessage( this, _( "You need to select the simulation settings first." ) );
300  return;
301  }
302 
303  m_simulator->LoadNetlist( formatter.GetString() );
304  updateTuners();
305  applyTuners();
306  m_simulator->Run();
307 }
308 
309 
311 {
312  m_simulator->Stop();
313 }
314 
315 
317 {
318  return m_simulator ? m_simulator->IsRunning() : false;
319 }
320 
321 
323 {
324  SIM_PLOT_PANEL* plotPanel = new SIM_PLOT_PANEL( aSimType, m_plotNotebook, wxID_ANY );
325 
326  if( m_welcomePanel )
327  {
328  m_plotNotebook->DeletePage( 0 );
329  m_welcomePanel = nullptr;
330  }
331 
332  m_plotNotebook->AddPage( plotPanel, wxString::Format( _( "Plot%u" ),
333  (unsigned int) m_plotNotebook->GetPageCount() + 1 ), true );
334 
335  m_plots[plotPanel] = PLOT_INFO();
336 
337  return plotPanel;
338 }
339 
340 
341 void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
342 {
343  addPlot( aNetName, SPT_VOLTAGE, "V" );
344 }
345 
346 
347 void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName, const wxString& aParam )
348 {
349  addPlot( aDeviceName, SPT_CURRENT, aParam );
350 }
351 
352 
354 {
355  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
356 
357  if( !plotPanel )
358  return;
359 
360  // For now limit the tuner tool to RLC components
361  char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aComponent, 0 )[0];
362 
363  if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR && primitiveType != SP_INDUCTOR )
364  return;
365 
366  const wxString& componentName = aComponent->GetField( REFERENCE )->GetText();
367 
368  // Do not add multiple instances for the same component
369  auto tunerIt = std::find_if( m_tuners.begin(), m_tuners.end(), [&]( const TUNER_SLIDER* t )
370  {
371  return t->GetComponentName() == componentName;
372  }
373  );
374 
375  if( tunerIt != m_tuners.end() )
376  return; // We already have it
377 
378  try
379  {
380  TUNER_SLIDER* tuner = new TUNER_SLIDER( this, m_tunePanel, aComponent );
381  m_tuneSizer->Add( tuner );
382  m_tuners.push_back( tuner );
383  m_tunePanel->Layout();
384  }
385  catch( const KI_PARAM_ERROR& e )
386  {
387  // Sorry, no bonus
388  DisplayError( nullptr, e.What() );
389  }
390 }
391 
392 
393 void SIM_PLOT_FRAME::RemoveTuner( TUNER_SLIDER* aTuner, bool aErase )
394 {
395  if( aErase )
396  m_tuners.remove( aTuner );
397 
398  aTuner->Destroy();
399  m_tunePanel->Layout();
400 }
401 
402 
404 {
405  wxWindow* curPage = m_plotNotebook->GetCurrentPage();
406 
407  return ( curPage == m_welcomePanel ) ? nullptr : static_cast<SIM_PLOT_PANEL*>( curPage );
408 }
409 
410 
412 {
413  return m_exporter.get();
414 }
415 
416 
417 void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam )
418 {
419  SIM_TYPE simType = m_exporter->GetSimType();
420 
421  if( !SIM_PLOT_PANEL::IsPlottable( simType ) )
422  return; // TODO else write out in console?
423 
424  // Create a new plot if the current one displays a different type
425  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
426 
427  if( !plotPanel || plotPanel->GetType() != simType )
428  plotPanel = NewPlotPanel( simType );
429 
430  TRACE_DESC descriptor( *m_exporter, aName, aType, aParam );
431 
432  bool updated = false;
433  SIM_PLOT_TYPE xAxisType = GetXAxisType( simType );
434 
435  if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY )
436  {
437  int baseType = descriptor.GetType() & ~( SPT_AC_MAG | SPT_AC_PHASE );
438 
439  // Add two plots: magnitude & phase
440  TRACE_DESC mag_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_MAG ) );
441  TRACE_DESC phase_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_PHASE ) );
442 
443  updated |= updatePlot( mag_desc, plotPanel );
444  updated |= updatePlot( phase_desc, plotPanel );
445  }
446  else
447  {
448  updated = updatePlot( descriptor, plotPanel );
449  }
450 
451  if( updated )
452  {
454  }
455 }
456 
457 
458 void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName, bool aErase )
459 {
460  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
461 
462  if( !plotPanel )
463  return;
464 
465  if( aErase )
466  {
467  auto& traceMap = m_plots[plotPanel].m_traces;
468  auto traceIt = traceMap.find( aPlotName );
469  wxASSERT( traceIt != traceMap.end() );
470  traceMap.erase( traceIt );
471  }
472 
473  wxASSERT( plotPanel->TraceShown( aPlotName ) );
474  plotPanel->DeleteTrace( aPlotName );
475  plotPanel->Fit();
476 
478  updateCursors();
479 }
480 
481 
483 {
485 }
486 
487 
488 bool SIM_PLOT_FRAME::updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL* aPanel )
489 {
490  SIM_TYPE simType = m_exporter->GetSimType();
491  wxString spiceVector = m_exporter->GetSpiceVector( aDescriptor.GetName(),
492  aDescriptor.GetType(), aDescriptor.GetParam() );
493 
494  if( !SIM_PLOT_PANEL::IsPlottable( simType ) )
495  {
496  // There is no plot to be shown
497  m_simulator->Command( wxString::Format( "print %s", spiceVector ).ToStdString() );
498 
499  return false;
500  }
501 
502  // First, handle the x axis
503  wxString xAxisName( m_simulator->GetXAxis( simType ) );
504 
505  if( xAxisName.IsEmpty() )
506  return false;
507 
508  auto data_x = m_simulator->GetMagPlot( (const char*) xAxisName.c_str() );
509  unsigned int size = data_x.size();
510 
511  if( data_x.empty() )
512  return false;
513 
514  SIM_PLOT_TYPE plotType = aDescriptor.GetType();
515  std::vector<double> data_y;
516 
517  // Now, Y axis data
518  switch( m_exporter->GetSimType() )
519  {
520  case ST_AC:
521  {
522  wxASSERT_MSG( !( ( plotType & SPT_AC_MAG ) && ( plotType & SPT_AC_PHASE ) ),
523  "Cannot set both AC_PHASE and AC_MAG bits" );
524 
525  if( plotType & SPT_AC_MAG )
526  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
527  else if( plotType & SPT_AC_PHASE )
528  data_y = m_simulator->GetPhasePlot( (const char*) spiceVector.c_str() );
529  else
530  wxASSERT_MSG( false, "Plot type missing AC_PHASE or AC_MAG bit" );
531  }
532  break;
533 
534  case ST_NOISE:
535  case ST_DC:
536  case ST_TRANSIENT:
537  {
538  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
539  }
540  break;
541 
542  default:
543  wxASSERT_MSG( false, "Unhandled plot type" );
544  return false;
545  }
546 
547  if( data_y.size() != size )
548  return false;
549 
550  if( aPanel->AddTrace( aDescriptor.GetTitle(), size,
551  data_x.data(), data_y.data(), aDescriptor.GetType() ) )
552  {
553  m_plots[aPanel].m_traces.insert( std::make_pair( aDescriptor.GetTitle(), aDescriptor ) );
554  }
555 
556  return true;
557 }
558 
559 
561 {
562  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
563 
564  if( !plotPanel )
565  return;
566 
567  m_signals->ClearAll();
568 
569  wxSize size = m_signals->GetClientSize();
570  m_signals->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x );
571 
572  // Build an image list, to show the color of the corresponding trace
573  // in the plot panel
574  // This image list is used for trace and cursor lists
575  wxMemoryDC bmDC;
576  const int isize = bmDC.GetCharHeight();
577 
578  if( m_signalsIconColorList == NULL )
579  m_signalsIconColorList = new wxImageList( isize, isize, false );
580  else
581  m_signalsIconColorList->RemoveAll();
582 
583  for( const auto& trace : CurrentPlot()->GetTraces() )
584  {
585  wxBitmap bitmap( isize, isize );
586  bmDC.SelectObject( bitmap );
587  wxColour tcolor = trace.second->GetTraceColour();
588 
589  wxColour bgColor = m_signals->wxWindow::GetBackgroundColour();
590  bmDC.SetPen( wxPen( bgColor ) );
591  bmDC.SetBrush( wxBrush( bgColor ) );
592  bmDC.DrawRectangle( 0, 0, isize, isize ); // because bmDC.Clear() does not work in wxGTK
593 
594  bmDC.SetPen( wxPen( tcolor ) );
595  bmDC.SetBrush( wxBrush( tcolor ) );
596  bmDC.DrawRectangle( 0, isize / 4 + 1, isize, isize / 2 );
597 
598  bmDC.SelectObject( wxNullBitmap ); // Needed to initialize bitmap
599 
600  bitmap.SetMask( new wxMask( bitmap, *wxBLACK ) );
601  m_signalsIconColorList->Add( bitmap );
602  }
603 
604  if( bmDC.IsOk() )
605  {
606  bmDC.SetBrush( wxNullBrush );
607  bmDC.SetPen( wxNullPen );
608  }
609 
610  m_signals->SetImageList( m_signalsIconColorList, wxIMAGE_LIST_SMALL );
611 
612  // Fill the signals listctrl. Keep the order of names and
613  // the order of icon color identical, because the icons
614  // are also used in cursor list, and the color index is
615  // calculated from the trace name index
616  int imgidx = 0;
617 
618  for( const auto& trace : m_plots[plotPanel].m_traces )
619  {
620  m_signals->InsertItem( imgidx, trace.first, imgidx );
621  imgidx++;
622  }
623 }
624 
625 
627 {
628  wxQueueEvent( this, new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
629 }
630 
631 
633 {
634  const auto& spiceItems = m_exporter->GetSpiceItems();
635 
636  for( auto it = m_tuners.begin(); it != m_tuners.end(); /* iteration inside the loop */ )
637  {
638  const wxString& ref = (*it)->GetComponentName();
639 
640  if( std::find_if( spiceItems.begin(), spiceItems.end(), [&]( const SPICE_ITEM& item )
641  {
642  return item.m_refName == ref;
643  }) == spiceItems.end() )
644  {
645  // The component does not exist anymore, remove the associated tuner
646  TUNER_SLIDER* tuner = *it;
647  it = m_tuners.erase( it );
648  RemoveTuner( tuner, false );
649  }
650  else
651  {
652  ++it;
653  }
654  }
655 }
656 
657 
659 {
660  for( auto& tuner : m_tuners )
661  {
663  std::string command( "alter @" + tuner->GetSpiceName()
664  + "=" + tuner->GetValue().ToSpiceString() );
665 
666  m_simulator->Command( command );
667  }
668 }
669 
670 
671 bool SIM_PLOT_FRAME::loadWorkbook( const wxString& aPath )
672 {
673  m_plots.clear();
674  m_plotNotebook->DeleteAllPages();
675 
676  wxTextFile file( aPath );
677 
678  if( !file.Open() )
679  return false;
680 
681  long plotsCount;
682 
683  if( !file.GetFirstLine().ToLong( &plotsCount ) ) // GetFirstLine instead of GetNextLine
684  return false;
685 
686  for( long i = 0; i < plotsCount; ++i )
687  {
688  long plotType, tracesCount;
689 
690  if( !file.GetNextLine().ToLong( &plotType ) )
691  return false;
692 
693  SIM_PLOT_PANEL* plotPanel = NewPlotPanel( (SIM_TYPE) plotType );
694  m_plots[plotPanel].m_simCommand = file.GetNextLine();
695  StartSimulation();
696 
697  // Perform simulation, so plots can be added with values
698  do
699  {
700  wxThread::This()->Sleep( 50 );
701  }
702  while( IsSimulationRunning() );
703 
704  if( !file.GetNextLine().ToLong( &tracesCount ) )
705  return false;
706 
707  for( long j = 0; j < tracesCount; ++j )
708  {
709  long traceType;
710  wxString name, param;
711 
712  if( !file.GetNextLine().ToLong( &traceType ) )
713  return false;
714 
715  name = file.GetNextLine();
716  param = file.GetNextLine();
717 
718  if( name.IsEmpty() || param.IsEmpty() )
719  return false;
720 
721  addPlot( name, (SIM_PLOT_TYPE) traceType, param );
722  }
723  }
724 
725  return true;
726 }
727 
728 
729 bool SIM_PLOT_FRAME::saveWorkbook( const wxString& aPath )
730 {
731 
732  wxString savePath = aPath;
733 
734  if( !savePath.Lower().EndsWith(".wbk"))
735  {
736  savePath += ".wbk";
737  };
738 
739 
740  wxTextFile file( savePath );
741 
742  if( file.Exists() )
743  {
744  if( !file.Open() )
745  return false;
746 
747  file.Clear();
748  }
749  else
750  {
751  file.Create();
752  }
753 
754  file.AddLine( wxString::Format( "%lu", m_plots.size() ) );
755 
756  for( const auto& plot : m_plots )
757  {
758  file.AddLine( wxString::Format( "%d", plot.first->GetType() ) );
759  file.AddLine( plot.second.m_simCommand );
760  file.AddLine( wxString::Format( "%lu", plot.second.m_traces.size() ) );
761 
762  for( const auto& trace : plot.second.m_traces )
763  {
764  file.AddLine( wxString::Format( "%d", trace.second.GetType() ) );
765  file.AddLine( trace.second.GetName() );
766  file.AddLine( trace.second.GetParam() );
767  }
768  }
769 
770  bool res = file.Write();
771  file.Close();
772 
773  return res;
774 }
775 
776 
778 {
779  switch( aType )
780  {
781  case ST_AC:
782  return SPT_LIN_FREQUENCY;
784 
785  case ST_DC:
786  return SPT_SWEEP;
787 
788  case ST_TRANSIENT:
789  return SPT_TIME;
790 
791  default:
792  wxASSERT_MSG( false, "Unhandled simulation type" );
793  return (SIM_PLOT_TYPE) 0;
794  }
795 }
796 
797 
798 void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent )
799 {
800  SIM_TYPE type = m_exporter->GetSimType();
801 
802  if( SIM_PLOT_PANEL::IsPlottable( type ) )
803  {
804  SIM_PLOT_PANEL* prevPlot = CurrentPlot();
805  SIM_PLOT_PANEL* newPlot = NewPlotPanel( type );
806 
807  // If the previous plot had the same type, copy the simulation command
808  if( prevPlot )
809  m_plots[newPlot].m_simCommand = m_plots[prevPlot].m_simCommand;
810  }
811 }
812 
813 
814 void SIM_PLOT_FRAME::menuOpenWorkbook( wxCommandEvent& event )
815 {
816  wxFileDialog openDlg( this, _( "Open simulation workbook" ), m_savedWorkbooksPath, "",
817  WorkbookFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
818 
819  if( openDlg.ShowModal() == wxID_CANCEL )
820  return;
821 
822  m_savedWorkbooksPath = openDlg.GetDirectory();
823 
824  if( !loadWorkbook( openDlg.GetPath() ) )
825  DisplayError( this, _( "There was an error while opening the workbook file" ) );
826 }
827 
828 
829 void SIM_PLOT_FRAME::menuSaveWorkbook( wxCommandEvent& event )
830 {
831  if( !CurrentPlot() )
832  return;
833 
834  wxFileDialog saveDlg( this, _( "Save Simulation Workbook" ), m_savedWorkbooksPath, "",
835  WorkbookFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
836 
837  if( saveDlg.ShowModal() == wxID_CANCEL )
838  return;
839 
840  m_savedWorkbooksPath = saveDlg.GetDirectory();
841 
842  if( !saveWorkbook( saveDlg.GetPath() ) )
843  DisplayError( this, _( "There was an error while saving the workbook file" ) );
844 }
845 
846 
847 void SIM_PLOT_FRAME::menuSaveImage( wxCommandEvent& event )
848 {
849  if( !CurrentPlot() )
850  return;
851 
852  wxFileDialog saveDlg( this, _( "Save Plot as Image" ), "", "",
853  PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
854 
855  if( saveDlg.ShowModal() == wxID_CANCEL )
856  return;
857 
858  CurrentPlot()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
859 }
860 
861 
862 void SIM_PLOT_FRAME::menuSaveCsv( wxCommandEvent& event )
863 {
864  if( !CurrentPlot() )
865  return;
866 
867  const wxChar SEPARATOR = ';';
868 
869  wxFileDialog saveDlg( this, _( "Save Plot Data" ), "", "",
870  CsvFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
871 
872  if( saveDlg.ShowModal() == wxID_CANCEL )
873  return;
874 
875  wxFile out( saveDlg.GetPath(), wxFile::write );
876  bool timeWritten = false;
877 
878  for( const auto& t : CurrentPlot()->GetTraces() )
879  {
880  const TRACE* trace = t.second;
881 
882  if( !timeWritten )
883  {
884  out.Write( wxString::Format( "Time%c", SEPARATOR ) );
885 
886  for( double v : trace->GetDataX() )
887  out.Write( wxString::Format( "%f%c", v, SEPARATOR ) );
888 
889  out.Write( "\r\n" );
890  timeWritten = true;
891  }
892 
893  out.Write( wxString::Format( "%s%c", t.first, SEPARATOR ) );
894 
895  for( double v : trace->GetDataY() )
896  out.Write( wxString::Format( "%f%c", v, SEPARATOR ) );
897 
898  out.Write( "\r\n" );
899  }
900 
901  out.Close();
902 }
903 
904 
905 void SIM_PLOT_FRAME::menuZoomIn( wxCommandEvent& event )
906 {
907  if( CurrentPlot() )
908  CurrentPlot()->ZoomIn();
909 }
910 
911 
912 void SIM_PLOT_FRAME::menuZoomOut( wxCommandEvent& event )
913 {
914  if( CurrentPlot() )
915  CurrentPlot()->ZoomOut();
916 }
917 
918 
919 void SIM_PLOT_FRAME::menuZoomFit( wxCommandEvent& event )
920 {
921  if( CurrentPlot() )
922  CurrentPlot()->Fit();
923 }
924 
925 
926 void SIM_PLOT_FRAME::menuShowGrid( wxCommandEvent& event )
927 {
928  SIM_PLOT_PANEL* plot = CurrentPlot();
929 
930  if( plot )
931  plot->ShowGrid( !plot->IsGridShown() );
932 }
933 
934 
935 void SIM_PLOT_FRAME::menuShowGridUpdate( wxUpdateUIEvent& event )
936 {
937  SIM_PLOT_PANEL* plot = CurrentPlot();
938 
939  event.Check( plot ? plot->IsGridShown() : false );
940 }
941 
942 
943 void SIM_PLOT_FRAME::menuShowLegend( wxCommandEvent& event )
944 {
945  SIM_PLOT_PANEL* plot = CurrentPlot();
946 
947  if( plot )
948  plot->ShowLegend( !plot->IsLegendShown() );
949 }
950 
951 
952 void SIM_PLOT_FRAME::menuShowLegendUpdate( wxUpdateUIEvent& event )
953 {
954  SIM_PLOT_PANEL* plot = CurrentPlot();
955  event.Check( plot ? plot->IsLegendShown() : false );
956 }
957 
958 
959 void SIM_PLOT_FRAME::onPlotClose( wxAuiNotebookEvent& event )
960 {
961  int idx = event.GetSelection();
962 
963  if( idx == wxNOT_FOUND )
964  return;
965 
966  SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetPage( idx ) );
967 
968  if( !plotPanel )
969  return;
970 
971  m_plots.erase( plotPanel );
973  updateCursors();
974 }
975 
976 
977 void SIM_PLOT_FRAME::onPlotChanged( wxAuiNotebookEvent& event )
978 {
980  updateCursors();
981 }
982 
983 
984 void SIM_PLOT_FRAME::onSignalDblClick( wxMouseEvent& event )
985 {
986  // Remove signal from the plot panel when double clicked
987  long idx = m_signals->GetFocusedItem();
988 
989  if( idx != wxNOT_FOUND )
990  removePlot( m_signals->GetItemText( idx, 0 ) );
991 }
992 
993 
994 void SIM_PLOT_FRAME::onSignalRClick( wxListEvent& event )
995 {
996  int idx = event.GetIndex();
997 
998  if( idx != wxNOT_FOUND )
999  m_signals->Select( idx );
1000 
1001  idx = m_signals->GetFirstSelected();
1002 
1003  if( idx != wxNOT_FOUND )
1004  {
1005  const wxString& netName = m_signals->GetItemText( idx, 0 );
1006  SIGNAL_CONTEXT_MENU ctxMenu( netName, this );
1007  m_signals->PopupMenu( &ctxMenu );
1008  }
1009 }
1010 
1011 
1012 void SIM_PLOT_FRAME::onSimulate( wxCommandEvent& event )
1013 {
1014  if( IsSimulationRunning() )
1015  StopSimulation();
1016  else
1017  StartSimulation();
1018 }
1019 
1020 
1021 void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
1022 {
1023  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1024 
1025  // Initial processing is required to e.g. display a list of power sources
1027 
1028  if( !m_exporter->ProcessNetlist( NET_ALL_FLAGS ) )
1029  {
1030  DisplayError( this, _( "There were errors during netlist export, aborted." ) );
1031  return;
1032  }
1033 
1034  if( !m_settingsDlg )
1035  m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
1036 
1037  if( plotPanel )
1038  m_settingsDlg->SetSimCommand( m_plots[plotPanel].m_simCommand );
1039 
1041 
1042  if( m_settingsDlg->ShowModal() == wxID_OK )
1043  {
1044  wxString newCommand = m_settingsDlg->GetSimCommand();
1045  SIM_TYPE newSimType = NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( newCommand );
1046 
1047  // If it is a new simulation type, open a new plot
1048  if( !plotPanel || ( plotPanel && plotPanel->GetType() != newSimType ) )
1049  {
1050  plotPanel = NewPlotPanel( newSimType );
1051  }
1052 
1053  m_plots[plotPanel].m_simCommand = newCommand;
1054  }
1055 }
1056 
1057 
1058 void SIM_PLOT_FRAME::onAddSignal( wxCommandEvent& event )
1059 {
1060  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1061 
1062  if( !plotPanel || !m_exporter || plotPanel->GetType() != m_exporter->GetSimType() )
1063  {
1064  DisplayInfoMessage( this, _( "You need to run simulation first." ) );
1065  return;
1066  }
1067 
1068  DIALOG_SIGNAL_LIST dialog( this, m_exporter.get() );
1069  dialog.ShowModal();
1070 }
1071 
1072 
1073 void SIM_PLOT_FRAME::onProbe( wxCommandEvent& event )
1074 {
1075  if( m_schematicFrame == NULL )
1076  return;
1077 
1078  wxQueueEvent( m_schematicFrame, new wxCommandEvent( wxEVT_TOOL, ID_SIM_PROBE ) );
1079  m_schematicFrame->Raise();
1080 }
1081 
1082 
1083 void SIM_PLOT_FRAME::onTune( wxCommandEvent& event )
1084 {
1085  if( m_schematicFrame == NULL )
1086  return;
1087 
1088  wxQueueEvent( m_schematicFrame, new wxCommandEvent( wxEVT_TOOL, ID_SIM_TUNE ) );
1089  m_schematicFrame->Raise();
1090 }
1091 
1092 void SIM_PLOT_FRAME::onShowNetlist( wxCommandEvent& event )
1093 {
1094  class NETLIST_VIEW_DIALOG : public wxDialog
1095  {
1096  public:
1097  enum
1098  {
1099  MARGIN_LINE_NUMBERS
1100  };
1101 
1102  void onClose( wxCloseEvent& evt )
1103  {
1104  EndModal( GetReturnCode() );
1105  }
1106 
1107  NETLIST_VIEW_DIALOG(wxWindow* parent, wxString source) :
1108  wxDialog(parent, wxID_ANY, "SPICE Netlist",
1109  wxDefaultPosition, wxSize(1500,900),
1110  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
1111  {
1112  wxStyledTextCtrl* text = new wxStyledTextCtrl( this, wxID_ANY );
1113 
1114  text->SetMarginWidth( MARGIN_LINE_NUMBERS, 50 );
1115  text->StyleSetForeground( wxSTC_STYLE_LINENUMBER, wxColour( 75, 75, 75 ) );
1116  text->StyleSetBackground( wxSTC_STYLE_LINENUMBER, wxColour( 220, 220, 220 ) );
1117  text->SetMarginType( MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER );
1118 
1119  text->SetWrapMode( wxSTC_WRAP_WORD );
1120 
1121  text->SetText( source );
1122 
1123  text->StyleClearAll();
1124  text->SetLexer( wxSTC_LEX_SPICE );
1125 
1126  wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
1127  sizer->Add( text, 1, wxEXPAND );
1128  SetSizer( sizer );
1129 
1130  Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( NETLIST_VIEW_DIALOG::onClose ), NULL,
1131  this );
1132  }
1133  };
1134 
1135  if( m_schematicFrame == NULL || m_simulator == NULL )
1136  return;
1137 
1138  NETLIST_VIEW_DIALOG dlg( this, m_simulator->GetNetlist() );
1139  dlg.ShowModal();
1140 }
1141 
1142 
1143 void SIM_PLOT_FRAME::onClose( wxCloseEvent& aEvent )
1144 {
1145  SaveSettings( config() );
1146 
1147  if( IsSimulationRunning() )
1148  m_simulator->Stop();
1149 
1150  Destroy();
1151 }
1152 
1153 
1154 void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
1155 {
1156  wxSize size = m_cursors->GetClientSize();
1157  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1158  m_cursors->ClearAll();
1159 
1160  if( !plotPanel )
1161  return;
1162 
1164  m_cursors->SetImageList(m_signalsIconColorList, wxIMAGE_LIST_SMALL);
1165 
1166  // Fill the signals listctrl
1167  m_cursors->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 );
1168  const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT, size.x / 4 );
1169 
1170  wxString labelY1 = plotPanel->GetLabelY1();
1171  wxString labelY2 = plotPanel->GetLabelY2();
1172  wxString labelY;
1173 
1174  if( !labelY2.IsEmpty() )
1175  labelY = labelY1 + " / " + labelY2;
1176  else
1177  labelY = labelY1;
1178 
1179  const long Y_COL = m_cursors->AppendColumn( labelY, wxLIST_FORMAT_LEFT, size.x / 4 );
1180 
1181  // Update cursor values
1182  int itemidx = 0;
1183  for( const auto& trace : plotPanel->GetTraces() )
1184  {
1185  if( CURSOR* cursor = trace.second->GetCursor() )
1186  {
1187  // Find the right icon color in list.
1188  // It is the icon used in m_signals list for the same trace
1189  long iconColor = m_signals->FindItem( -1, trace.first );
1190 
1191  const wxRealPoint coords = cursor->GetCoords();
1192  long idx = m_cursors->InsertItem( itemidx++, trace.first, iconColor );
1193  m_cursors->SetItem( idx, X_COL, SPICE_VALUE( coords.x ).ToSpiceString() );
1194  m_cursors->SetItem( idx, Y_COL, SPICE_VALUE( coords.y ).ToSpiceString() );
1195  }
1196  }
1197 }
1198 
1199 
1200 void SIM_PLOT_FRAME::onSimStarted( wxCommandEvent& aEvent )
1201 {
1202  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( sim_stop_xpm ) );
1203  SetCursor( wxCURSOR_ARROWWAIT );
1204 }
1205 
1206 
1207 void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
1208 {
1209  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( sim_run_xpm ) );
1210  SetCursor( wxCURSOR_ARROW );
1211 
1212  SIM_TYPE simType = m_exporter->GetSimType();
1213 
1214  if( simType == ST_UNKNOWN )
1215  return;
1216 
1217  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1218 
1219  if( !plotPanel || plotPanel->GetType() != simType )
1220  plotPanel = NewPlotPanel( simType );
1221 
1222  if( IsSimulationRunning() )
1223  return;
1224 
1225  // If there are any signals plotted, update them
1226  if( SIM_PLOT_PANEL::IsPlottable( simType ) )
1227  {
1228  TRACE_MAP& traceMap = m_plots[plotPanel].m_traces;
1229 
1230  for( auto it = traceMap.begin(); it != traceMap.end(); /* iteration occurs in the loop */)
1231  {
1232  if( !updatePlot( it->second, plotPanel ) )
1233  {
1234  removePlot( it->first, false );
1235  it = traceMap.erase( it ); // remove a plot that does not exist anymore
1236  }
1237  else
1238  {
1239  ++it;
1240  }
1241  }
1242 
1243  updateSignalList();
1244  plotPanel->UpdateAll();
1245  plotPanel->ResetScales();
1246  }
1247  else
1248  {
1250  for( const auto& net : m_exporter->GetNetIndexMap() )
1251  {
1252  int node = net.second;
1253 
1254  if( node > 0 )
1255  m_simulator->Command( wxString::Format( "print v(%d)", node ).ToStdString() );
1256  }
1257  }
1258 }
1259 
1260 
1261 void SIM_PLOT_FRAME::onSimUpdate( wxCommandEvent& aEvent )
1262 {
1263  if( IsSimulationRunning() )
1264  StopSimulation();
1265 
1266  if( CurrentPlot() != m_lastSimPlot )
1267  {
1268  // We need to rerun simulation, as the simulator currently stores
1269  // results for another plot
1270  StartSimulation();
1271  }
1272  else
1273  {
1274  // Incremental update
1275  m_simConsole->Clear();
1276  // Do not export netlist, it is already stored in the simulator
1277  applyTuners();
1278  m_simulator->Run();
1279  }
1280 }
1281 
1282 
1283 void SIM_PLOT_FRAME::onSimReport( wxCommandEvent& aEvent )
1284 {
1285  m_simConsole->AppendText( aEvent.GetString() + "\n" );
1286  m_simConsole->SetInsertionPointEnd();
1287 }
1288 
1289 
1291  SIM_PLOT_FRAME* aPlotFrame )
1292  : m_signal( aSignal ), m_plotFrame( aPlotFrame )
1293 {
1295 
1296  AddMenuItem( this, HIDE_SIGNAL, _( "Hide Signal" ),
1297  _( "Erase the signal from plot screen" ),
1298  KiBitmap( delete_xpm ) );
1299 
1300  TRACE* trace = plot->GetTrace( m_signal );
1301 
1302  if( trace->HasCursor() )
1303  AddMenuItem( this, HIDE_CURSOR, _( "Hide Cursor" ),
1304  wxEmptyString, KiBitmap( pcb_target_xpm ) );
1305  else
1306  AddMenuItem( this, SHOW_CURSOR, _( "Show Cursor" ),
1307  wxEmptyString, KiBitmap( pcb_target_xpm ) );
1308 
1309  Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ), NULL, this );
1310 }
1311 
1312 
1314 {
1316 
1317  switch( aEvent.GetId() )
1318  {
1319  case HIDE_SIGNAL:
1321  break;
1322 
1323  case SHOW_CURSOR:
1324  plot->EnableCursor( m_signal, true );
1325  break;
1326 
1327  case HIDE_CURSOR:
1328  plot->EnableCursor( m_signal, false );
1329  break;
1330  }
1331 }
1332 
1333 wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
1334 wxDEFINE_EVENT( EVT_SIM_REPORT, wxCommandEvent );
1335 
1336 wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
1337 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
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
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.
This file is part of the common library.
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
std::shared_ptr< SPICE_SIMULATOR > m_simulator
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.
const NETLIST_EXPORTER_PSPICE_SIM * GetExporter() const
Returns the netlist exporter object used for simulations.
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
bool IsLegendShown() const
#define PLOT_PANEL_WIDTH_ENTRY
SEVERITY
Severity of the reported messages.
Definition: reporter.h:74
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.
const wxString What() const
Definition: ki_exception.h:58
bool AddTrace(const wxString &aName, int aPoints, const double *aX, const double *aY, SIM_PLOT_TYPE aFlags)
The common library.
void onShowNetlist(wxCommandEvent &event)
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
static std::shared_ptr< SPICE_SIMULATOR > CreateInstance(const std::string &aName)
Creates a simulator instance of particular type (currently only ngspice is handled) ...
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()
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
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
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
size_t i
Definition: json11.cpp:597
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:102
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
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:216
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:185
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.
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.
class KI_PARAM_ERROR is a class used to hold a translatable error message and may be used when throwi...
Definition: ki_exception.h:45
wxToolBarToolBase * m_toolSettings
SIM_PLOT_FRAME(KIWAY *aKiway, wxWindow *aParent)
Constructor.