diff --git a/common/widgets/mathplot.cpp b/common/widgets/mathplot.cpp index 8f1e2e541f..d1c8fae372 100644 --- a/common/widgets/mathplot.cpp +++ b/common/widgets/mathplot.cpp @@ -1436,6 +1436,9 @@ void mpScaleY::Plot( wxDC& dc, mpWindow& w ) orgx = w.GetScrX() - w.GetMarginRight(); } + if( m_flags == mpALIGN_FAR_RIGHT ) + orgx = w.GetScrX() - ( w.GetMarginRight() / 2 ); + if( m_flags == mpALIGN_BORDER_RIGHT ) orgx = w.GetScrX() - 1; // dc.LogicalToDeviceX(0) - 1; @@ -1514,7 +1517,7 @@ void mpScaleY::Plot( wxDC& dc, mpWindow& w ) s = getLabel( n ); dc.GetTextExtent( s, &tx, &ty ); - if( (m_flags == mpALIGN_BORDER_LEFT) || (m_flags == mpALIGN_RIGHT) ) + if( m_flags == mpALIGN_BORDER_LEFT || m_flags == mpALIGN_RIGHT || m_flags == mpALIGN_FAR_RIGHT ) dc.DrawText( s, orgx + 4, p - ty / 2 ); else dc.DrawText( s, orgx - 4 - tx, p - ty / 2 ); // ( s, orgx+4, p-ty/2); @@ -1537,7 +1540,7 @@ void mpScaleY::Plot( wxDC& dc, mpWindow& w ) // if ((!m_drawOutsideMargins) && (w.GetMarginLeft() > (ty + labelW + 8))) { // dc.DrawRotatedText( m_name, orgx - 6 - labelW - ty, (maxYpx + minYpx) / 2 + tx / 2, 90); // } else { - dc.DrawText( m_name, orgx + 4, minYpx - ty - 4 ); + dc.DrawText( m_name, orgx - ( tx / 2 ), minYpx - ty - 4 ); // } } break; @@ -1547,13 +1550,14 @@ void mpScaleY::Plot( wxDC& dc, mpWindow& w ) break; case mpALIGN_RIGHT: + case mpALIGN_FAR_RIGHT: { // dc.DrawRotatedText( m_name, orgx + 6, (maxYpx + minYpx) / 2 + tx / 2, 90); /*if ((!m_drawOutsideMargins) && (w.GetMarginRight() > (ty + labelW + 8))) { * dc.DrawRotatedText( m_name, orgx + 6 + labelW, (maxYpx - minYpx + tx)>>1, 90); * } else {*/ - dc.DrawText( m_name, orgx - tx - 4, minYpx - ty - 4 ); + dc.DrawText( m_name, orgx - ( tx / 2 ), minYpx - ty - 4 ); // } } break; diff --git a/eeschema/dialogs/dialog_export_netlist.cpp b/eeschema/dialogs/dialog_export_netlist.cpp index e5b76c96aa..d087db822a 100644 --- a/eeschema/dialogs/dialog_export_netlist.cpp +++ b/eeschema/dialogs/dialog_export_netlist.cpp @@ -98,6 +98,7 @@ public: wxCheckBox* m_CurSheetAsRoot; wxCheckBox* m_SaveAllVoltages; wxCheckBox* m_SaveAllCurrents; + wxCheckBox* m_SaveAllDissipations; wxCheckBox* m_RunExternalSpiceCommand; wxTextCtrl* m_CommandStringCtrl; wxTextCtrl* m_TitleStringCtrl; @@ -195,6 +196,7 @@ enum id_netlist { ID_CUR_SHEET_AS_ROOT, ID_SAVE_ALL_VOLTAGES, ID_SAVE_ALL_CURRENTS, + ID_SAVE_ALL_DISSIPATIONS, ID_RUN_SIMULATOR }; @@ -210,6 +212,7 @@ EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& a m_TitleStringCtrl = nullptr; m_SaveAllVoltages = nullptr; m_SaveAllCurrents = nullptr; + m_SaveAllDissipations = nullptr; m_custom = aCustom; aParent->AddPage( this, aTitle, false ); @@ -298,6 +301,12 @@ void DIALOG_EXPORT_NETLIST::InstallPageSpice() page->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents ); page->m_LeftBoxSizer->Add( page->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 ); + page->m_SaveAllDissipations = new wxCheckBox( page, ID_SAVE_ALL_DISSIPATIONS, + _( "Save all power dissipations" ) ); + page->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all items (.probe p())" ) ); + page->m_SaveAllDissipations->SetValue( settings.m_SpiceSaveAllDissipations ); + page->m_LeftBoxSizer->Add( page->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 ); + page->m_RunExternalSpiceCommand = new wxCheckBox( page, ID_RUN_SIMULATOR, _( "Run external simulator command:" ) ); @@ -397,8 +406,9 @@ void DIALOG_EXPORT_NETLIST::OnNetlistTypeSelection( wxNotebookEvent& event ) void DIALOG_EXPORT_NETLIST::NetlistUpdateOpt() { - bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked(); - bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked(); + bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked(); + bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked(); + bool saveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked(); wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue(); bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue(); bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue(); @@ -407,6 +417,7 @@ void DIALOG_EXPORT_NETLIST::NetlistUpdateOpt() settings.m_SpiceSaveAllVoltages = saveAllVoltages; settings.m_SpiceSaveAllCurrents = saveAllCurrents; + settings.m_SpiceSaveAllDissipations = saveAllDissipations; settings.m_SpiceCommandString = spiceCmdString; settings.m_SpiceCurSheetAsRoot = curSheetAsRoot; settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot; @@ -446,6 +457,9 @@ bool DIALOG_EXPORT_NETLIST::TransferDataFromWindow() if( currPage->m_SaveAllCurrents->GetValue() ) netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS; + if( currPage->m_SaveAllDissipations->GetValue() ) + netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS; + if( currPage->m_CurSheetAsRoot->GetValue() ) netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_CUR_SHEET_AS_ROOT; diff --git a/eeschema/dialogs/dialog_sim_command.h b/eeschema/dialogs/dialog_sim_command.h index d8ac2e3afb..04d2c4529a 100644 --- a/eeschema/dialogs/dialog_sim_command.h +++ b/eeschema/dialogs/dialog_sim_command.h @@ -79,6 +79,7 @@ public: m_fixIncludePaths->SetValue( aOptions & NETLIST_EXPORTER_SPICE::OPTION_ADJUST_INCLUDE_PATHS ); m_saveAllVoltages->SetValue( aOptions & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES ); m_saveAllCurrents->SetValue( aOptions & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS ); + m_saveAllDissipations->SetValue( aOptions & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS ); } bool TransferDataFromWindow() override; diff --git a/eeschema/dialogs/dialog_sim_command_base.cpp b/eeschema/dialogs/dialog_sim_command_base.cpp index 8691c311f8..740b7d8b9c 100644 --- a/eeschema/dialogs/dialog_sim_command_base.cpp +++ b/eeschema/dialogs/dialog_sim_command_base.cpp @@ -438,6 +438,9 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i m_saveAllCurrents = new wxCheckBox( this, wxID_ANY, _("Save all currents"), wxDefaultPosition, wxDefaultSize, 0 ); bSizer88->Add( m_saveAllCurrents, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + m_saveAllDissipations = new wxCheckBox( this, wxID_ANY, _("Save all power dissipations"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer88->Add( m_saveAllDissipations, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + m_compatibilityMode = new wxBoxSizer( wxHORIZONTAL ); wxStaticText* compatibilityLabel; @@ -452,7 +455,7 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i m_compatibilityMode->Add( m_compatibilityModeChoice, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer88->Add( m_compatibilityMode, 1, wxEXPAND|wxBOTTOM, 5 ); + bSizer88->Add( m_compatibilityMode, 1, wxEXPAND|wxTOP|wxBOTTOM, 5 ); bSizer1->Add( bSizer88, 0, wxEXPAND|wxTOP|wxLEFT, 10 ); diff --git a/eeschema/dialogs/dialog_sim_command_base.fbp b/eeschema/dialogs/dialog_sim_command_base.fbp index 41a40e3d30..0191fd3c40 100644 --- a/eeschema/dialogs/dialog_sim_command_base.fbp +++ b/eeschema/dialogs/dialog_sim_command_base.fbp @@ -5053,7 +5053,71 @@ 5 - wxEXPAND|wxBOTTOM + wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Save all power dissipations + + 0 + + + 0 + + 1 + m_saveAllDissipations + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxEXPAND|wxTOP|wxBOTTOM 1 diff --git a/eeschema/dialogs/dialog_sim_command_base.h b/eeschema/dialogs/dialog_sim_command_base.h index 36ef021f52..ba4344c231 100644 --- a/eeschema/dialogs/dialog_sim_command_base.h +++ b/eeschema/dialogs/dialog_sim_command_base.h @@ -119,6 +119,7 @@ class DIALOG_SIM_COMMAND_BASE : public DIALOG_SHIM wxCheckBox* m_fixIncludePaths; wxCheckBox* m_saveAllVoltages; wxCheckBox* m_saveAllCurrents; + wxCheckBox* m_saveAllDissipations; wxBoxSizer* m_compatibilityMode; wxChoice* m_compatibilityModeChoice; wxStdDialogButtonSizer* m_sdbSizer; diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp index cec3a775bf..49145effb9 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp @@ -609,6 +609,18 @@ void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter, if( aNetlistOptions & OPTION_SAVE_ALL_CURRENTS ) aFormatter.Print( 0, ".probe alli\n" ); + if( aNetlistOptions & OPTION_SAVE_ALL_DISSIPATIONS ) + { + for( const SPICE_ITEM& item : m_items ) + { + if( item.model->GetPinCount() >= 2 ) + { + aFormatter.Print( 0, ".probe p(%s)\n", + item.model->SpiceGenerator().ItemName( item ).c_str() ); + } + } + } + for( const wxString& directive : m_directives ) { bool simCommand = false; diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.h b/eeschema/netlist_exporters/netlist_exporter_spice.h index ca8685dfeb..84aed20abd 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.h +++ b/eeschema/netlist_exporters/netlist_exporter_spice.h @@ -51,16 +51,18 @@ class NETLIST_EXPORTER_SPICE : public NETLIST_EXPORTER_BASE public: enum OPTIONS { - OPTION_ADJUST_INCLUDE_PATHS = 0x0010, - OPTION_ADJUST_PASSIVE_VALS = 0x0020, - OPTION_SAVE_ALL_VOLTAGES = 0x0040, - OPTION_SAVE_ALL_CURRENTS = 0x0080, - OPTION_CUR_SHEET_AS_ROOT = 0x0100, - OPTION_SIM_COMMAND = 0x0200, + OPTION_ADJUST_INCLUDE_PATHS = 0x0010, + OPTION_ADJUST_PASSIVE_VALS = 0x0020, + OPTION_SAVE_ALL_VOLTAGES = 0x0040, + OPTION_SAVE_ALL_CURRENTS = 0x0080, + OPTION_SAVE_ALL_DISSIPATIONS = 0x0100, + OPTION_CUR_SHEET_AS_ROOT = 0x0200, + OPTION_SIM_COMMAND = 0x0400, OPTION_DEFAULT_FLAGS = OPTION_ADJUST_INCLUDE_PATHS | OPTION_ADJUST_PASSIVE_VALS | OPTION_SAVE_ALL_VOLTAGES | OPTION_SAVE_ALL_CURRENTS + | OPTION_SAVE_ALL_DISSIPATIONS }; NETLIST_EXPORTER_SPICE( SCHEMATIC_IFACE* aSchematic, wxWindow* aDialogParent = nullptr ); diff --git a/eeschema/schematic_settings.cpp b/eeschema/schematic_settings.cpp index c54055208a..36674758af 100644 --- a/eeschema/schematic_settings.cpp +++ b/eeschema/schematic_settings.cpp @@ -59,6 +59,7 @@ SCHEMATIC_SETTINGS::SCHEMATIC_SETTINGS( JSON_SETTINGS* aParent, const std::strin m_SpiceCurSheetAsRoot( false ), m_SpiceSaveAllVoltages( false ), m_SpiceSaveAllCurrents( false ), + m_SpiceSaveAllDissipations( false ), m_SpiceModelCurSheetAsRoot( true ), m_NgspiceSimulatorSettings( nullptr ) { @@ -204,6 +205,9 @@ SCHEMATIC_SETTINGS::SCHEMATIC_SETTINGS( JSON_SETTINGS* aParent, const std::strin m_params.emplace_back( new PARAM( "spice_save_all_currents", &m_SpiceSaveAllCurrents, false ) ); + m_params.emplace_back( new PARAM( "spice_save_all_dissipations", + &m_SpiceSaveAllDissipations, false ) ); + m_params.emplace_back( new PARAM( "spice_model_current_sheet_as_root", &m_SpiceModelCurSheetAsRoot, true ) ); diff --git a/eeschema/schematic_settings.h b/eeschema/schematic_settings.h index acdd4b0f35..8e9cd6600d 100644 --- a/eeschema/schematic_settings.h +++ b/eeschema/schematic_settings.h @@ -77,6 +77,7 @@ public: bool m_SpiceCurSheetAsRoot; bool m_SpiceSaveAllVoltages; bool m_SpiceSaveAllCurrents; + bool m_SpiceSaveAllDissipations; wxString m_SpiceCommandString; // A command string to run external spice bool m_SpiceModelCurSheetAsRoot; diff --git a/eeschema/sim/sim_plot_frame.cpp b/eeschema/sim/sim_plot_frame.cpp index cd532629ae..5caa35d1f7 100644 --- a/eeschema/sim/sim_plot_frame.cpp +++ b/eeschema/sim/sim_plot_frame.cpp @@ -369,7 +369,7 @@ void SIM_PLOT_FRAME::ShowChangedLanguage() m_cursorsGrid->SetColLabelValue( COL_CURSOR_NAME, _( "Cursor" ) ); m_cursorsGrid->SetColLabelValue( COL_CURSOR_SIGNAL, _( "Signal" ) ); m_cursorsGrid->SetColLabelValue( COL_CURSOR_X, _( "Time" ) ); - m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, _( "Voltage / Current" ) ); + m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, _( "Value" ) ); wxCommandEvent dummy; onCursorUpdate( dummy ); @@ -645,16 +645,19 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand ) unconnected.Replace( '(', '_' ); // Convert to SPICE markup m_signals.clear(); - auto simType = m_circuitModel->GetSimType(); + int options = m_circuitModel->GetSimOptions(); + SIM_TYPE simType = m_circuitModel->GetSimType(); - // Add voltages - for( const std::string& net : m_circuitModel->GetNets() ) + if( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES ) { - // netnames are escaped (can contain "{slash}" for '/') Unscape them: - wxString netname = UnescapeString( net ); - - if( netname != "GND" && netname != "0" && !netname.StartsWith( unconnected ) ) + for( const std::string& net : m_circuitModel->GetNets() ) { + // netnames are escaped (can contain "{slash}" for '/') Unscape them: + wxString netname = UnescapeString( net ); + + if( netname == "GND" || netname == "0" || netname.StartsWith( unconnected ) ) + continue; + if( simType == ST_AC ) { m_signals.push_back( wxString::Format( _( "V(%s) (gain)" ), netname ) ); @@ -667,17 +670,39 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand ) } } - // Add currents - if( simType == ST_TRANSIENT || simType == ST_DC ) + if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS ) + && ( simType == ST_TRANSIENT || simType == ST_DC ) ) { for( const SPICE_ITEM& item : m_circuitModel->GetItems() ) { - // Add all possible currents for the primitive. + // Add all possible currents for the device. for( const std::string& name : item.model->SpiceGenerator().CurrentNames( item ) ) m_signals.push_back( name ); } } + if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS ) + && ( simType == ST_TRANSIENT || simType == ST_DC ) ) + { + for( const SPICE_ITEM& item : m_circuitModel->GetItems() ) + { + if( item.model->GetPinCount() >= 2 ) + { + wxString name = item.model->SpiceGenerator().ItemName( item ); + m_signals.push_back( wxString::Format( wxS( "P(%s)" ), name ) ); + } + } + } + + // Add .PROBE directives + for( const wxString& directive : m_circuitModel->GetDirectives() ) + { + wxString directiveParams; + + if( directive.Upper().StartsWith( wxS( ".PROBE" ), &directiveParams ) ) + m_signals.push_back( directiveParams.Trim( false ) ); + } + rebuildSignalsGrid( m_filter->GetValue() ); applyTuners(); @@ -767,6 +792,8 @@ void SIM_PLOT_FRAME::onSignalsGridCellChanged( wxGridEvent& aEvent ) traceType = SPT_VOLTAGE; else if( firstChar == 'I' || firstChar == 'i' ) traceType = SPT_CURRENT; + else if( firstChar == 'P' || firstChar == 'p' ) + traceType = SPT_POWER; if( signalName.EndsWith( gainSuffix ) ) { @@ -1059,12 +1086,16 @@ bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType, SIM_TYPE simType = m_circuitModel->GetSimType(); wxString traceTitle = aName; + wxString vectorName = aName; if( aType & SPT_AC_MAG ) traceTitle += _( " (gain)" ); else if( aType & SPT_AC_PHASE ) traceTitle += _( " (phase)" ); + if( aType & SPT_POWER ) + vectorName = vectorName.AfterFirst( '(' ).BeforeLast( ')' ) + wxS( ":power" ); + if( !SIM_PANEL_BASE::IsPlottable( simType ) ) { // There is no plot to be shown @@ -1092,9 +1123,9 @@ bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType, wxT( "Cannot set both AC_PHASE and AC_MAG bits" ) ); if( aType & SPT_AC_MAG ) - data_y = m_simulator->GetMagPlot( (const char*) aName.c_str() ); + data_y = m_simulator->GetMagPlot( (const char*) vectorName.c_str() ); else if( aType & SPT_AC_PHASE ) - data_y = m_simulator->GetPhasePlot( (const char*) aName.c_str() ); + data_y = m_simulator->GetPhasePlot( (const char*) vectorName.c_str() ); else wxFAIL_MSG( wxT( "Plot type missing AC_PHASE or AC_MAG bit" ) ); @@ -1103,7 +1134,7 @@ bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType, case ST_NOISE: case ST_DC: case ST_TRANSIENT: - data_y = m_simulator->GetMagPlot( (const char*) aName.c_str() ); + data_y = m_simulator->GetMagPlot( (const char*) vectorName.c_str() ); break; default: @@ -1332,6 +1363,10 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath ) simOptions &= ~NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES; simOptions &= ~NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS; } + else if( version >= 3 ) + { + simOptions &= ~NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS; + } while( tokenizer.HasMoreTokens() ) { @@ -1343,6 +1378,8 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath ) simOptions |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES; else if( line.StartsWith( wxT( ".probe alli" ) ) ) simOptions |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS; + else if( line.StartsWith( wxT( ".probe allp" ) ) ) + simOptions |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS; else simCommand += line + wxT( "\n" ); } @@ -1378,6 +1415,33 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath ) return false; } + if( version <= 2 ) + { + long legacyTraceType = traceType; + traceType = 0; + + if( legacyTraceType & LEGACY_SPT_VOLTAGE ) + traceType |= SPT_VOLTAGE; + + if( legacyTraceType & LEGACY_SPT_CURRENT ) + traceType |= SPT_CURRENT; + + if( legacyTraceType & LEGACY_SPT_AC_PHASE ) + traceType |= SPT_AC_PHASE; + + if( legacyTraceType & LEGACY_SPT_AC_MAG ) + traceType |= SPT_AC_MAG; + + if( legacyTraceType & LEGACY_SPT_TIME ) + traceType |= SPT_TIME; + + if( legacyTraceType & LEGACY_SPT_LIN_FREQUENCY ) + traceType |= SPT_LIN_FREQUENCY; + + if( legacyTraceType & LEGACY_SPT_SWEEP ) + traceType |= SPT_SWEEP; + } + name = file.GetNextLine(); if( name.IsEmpty() ) @@ -1437,7 +1501,7 @@ bool SIM_PLOT_FRAME::SaveWorkbook( const wxString& aPath ) file.Create(); } - file.AddLine( wxT( "version 2" ) ); + file.AddLine( wxT( "version 3" ) ); file.AddLine( wxString::Format( wxT( "%llu" ), m_workbook->GetPageCount() ) ); @@ -1465,6 +1529,9 @@ bool SIM_PLOT_FRAME::SaveWorkbook( const wxString& aPath ) if( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS ) command += wxT( "\n.probe alli" ); + if( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS ) + command += wxT( "\n.probe allp" ); + file.AddLine( EscapeString( command, CTX_LINE ) ); const SIM_PLOT_PANEL* plotPanel = dynamic_cast( basePanel ); @@ -1700,33 +1767,36 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) if( !plotPanel ) return; - // Set up the labels - m_cursorsGrid->SetColLabelValue( COL_CURSOR_X, plotPanel->GetLabelX() ); - - wxString labelY1 = plotPanel->GetLabelY1(); - wxString labelY2 = plotPanel->GetLabelY2(); - - if( labelY2.IsEmpty() ) - m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, labelY1 ); - else - m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, labelY1 + wxT( " / " ) + labelY2 ); - // Update cursor values - wxString unitsX = plotPanel->GetUnitsX(); CURSOR* cursor1 = nullptr; - wxString unitsY1; + wxString cursor1Name; + wxString cursor1Units; CURSOR* cursor2 = nullptr; - wxString unitsY2; + wxString cursor2Name; + wxString cursor2Units; auto getUnitsY = [&]( TRACE* aTrace ) -> wxString { if( ( aTrace->GetType() & SPT_AC_PHASE ) || ( aTrace->GetType() & SPT_CURRENT ) ) return plotPanel->GetUnitsY2(); + else if( aTrace->GetType() & SPT_POWER ) + return plotPanel->GetUnitsY3(); else return plotPanel->GetUnitsY1(); }; + auto getNameY = + [&]( TRACE* aTrace ) -> wxString + { + if( ( aTrace->GetType() & SPT_AC_PHASE ) || ( aTrace->GetType() & SPT_CURRENT ) ) + return plotPanel->GetLabelY2(); + else if( aTrace->GetType() & SPT_POWER ) + return plotPanel->GetLabelY3(); + else + return plotPanel->GetLabelY1(); + }; + auto updateRangeUnits = []( wxString* aRange, const wxString& aUnits ) { @@ -1750,13 +1820,14 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) if( CURSOR* cursor = trace->GetCursor( 1 ) ) { cursor1 = cursor; - unitsY1 = getUnitsY( trace ); + cursor1Name = getNameY( trace ); + cursor1Units = getUnitsY( trace ); wxRealPoint coords = cursor->GetCoords(); int row = m_cursorsGrid->GetNumberRows(); - updateRangeUnits( &m_cursorRange[0][0], unitsX ); - updateRangeUnits( &m_cursorRange[0][1], unitsY1 ); + updateRangeUnits( &m_cursorRange[0][0], plotPanel->GetUnitsX() ); + updateRangeUnits( &m_cursorRange[0][1], cursor1Units ); m_cursorsGrid->AppendRows( 1 ); m_cursorsGrid->SetCellValue( row, COL_CURSOR_NAME, wxS( "1" ) ); @@ -1772,13 +1843,14 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) if( CURSOR* cursor = trace->GetCursor( 2 ) ) { cursor2 = cursor; - unitsY2 = getUnitsY( trace ); + cursor2Name = getNameY( trace ); + cursor2Units = getUnitsY( trace ); wxRealPoint coords = cursor->GetCoords(); int row = m_cursorsGrid->GetNumberRows(); - updateRangeUnits( &m_cursorRange[1][0], unitsX ); - updateRangeUnits( &m_cursorRange[1][1], unitsY2 ); + updateRangeUnits( &m_cursorRange[1][0], plotPanel->GetUnitsX() ); + updateRangeUnits( &m_cursorRange[1][1], cursor2Units ); m_cursorsGrid->AppendRows( 1 ); m_cursorsGrid->SetCellValue( row, COL_CURSOR_NAME, wxS( "2" ) ); @@ -1789,13 +1861,13 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) } } - if( cursor1 && cursor2 && unitsY1 == unitsY2 ) + if( cursor1 && cursor2 && cursor1Units == cursor2Units ) { wxRealPoint coords = cursor2->GetCoords() - cursor1->GetCoords(); wxString signal; - updateRangeUnits( &m_cursorRange[2][0], unitsX ); - updateRangeUnits( &m_cursorRange[2][1], unitsY1 ); + updateRangeUnits( &m_cursorRange[2][0], plotPanel->GetUnitsX() ); + updateRangeUnits( &m_cursorRange[2][1], cursor1Units ); if( cursor1->GetName() == cursor2->GetName() ) signal = wxString::Format( wxS( "%s[2 - 1]" ), cursor2->GetName() ); @@ -1808,6 +1880,21 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) m_cursorsGrid->SetCellValue( 2, COL_CURSOR_X, formatValue( coords.x, 2, 0 ) ); m_cursorsGrid->SetCellValue( 2, COL_CURSOR_Y, formatValue( coords.y, 2, 1 ) ); } + + // Set up the labels + m_cursorsGrid->SetColLabelValue( COL_CURSOR_X, plotPanel->GetLabelX() ); + + wxString valColName = _( "Value" ); + + if( !cursor1Name.IsEmpty() && cursor2Name.IsEmpty() ) + valColName = cursor1Name; + else if( !cursor2Name.IsEmpty() && cursor1Name.IsEmpty() ) + valColName = cursor2Name; + else if( cursor1Name == cursor2Name ) + valColName = cursor1Name; + + m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, valColName ); + } diff --git a/eeschema/sim/sim_plot_frame_base.cpp b/eeschema/sim/sim_plot_frame_base.cpp index 28df5b8b22..e65b6e8ded 100644 --- a/eeschema/sim/sim_plot_frame_base.cpp +++ b/eeschema/sim/sim_plot_frame_base.cpp @@ -114,8 +114,8 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const m_signalsGrid->SetMargins( 0, 0 ); // Columns - m_signalsGrid->SetColSize( 0, 204 ); - m_signalsGrid->SetColSize( 1, 45 ); + m_signalsGrid->SetColSize( 0, 212 ); + m_signalsGrid->SetColSize( 1, 40 ); m_signalsGrid->SetColSize( 2, 45 ); m_signalsGrid->SetColSize( 3, 55 ); m_signalsGrid->SetColSize( 4, 55 ); @@ -171,16 +171,16 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const m_cursorsGrid->SetMargins( 0, 0 ); // Columns - m_cursorsGrid->SetColSize( 0, 44 ); - m_cursorsGrid->SetColSize( 1, 152 ); - m_cursorsGrid->SetColSize( 2, 103 ); - m_cursorsGrid->SetColSize( 3, 106 ); + m_cursorsGrid->SetColSize( 0, 45 ); + m_cursorsGrid->SetColSize( 1, 162 ); + m_cursorsGrid->SetColSize( 2, 100 ); + m_cursorsGrid->SetColSize( 3, 100 ); m_cursorsGrid->EnableDragColMove( false ); m_cursorsGrid->EnableDragColSize( true ); m_cursorsGrid->SetColLabelValue( 0, _("Cursor") ); m_cursorsGrid->SetColLabelValue( 1, _("Signal") ); m_cursorsGrid->SetColLabelValue( 2, _("Time") ); - m_cursorsGrid->SetColLabelValue( 3, _("Voltage / Current") ); + m_cursorsGrid->SetColLabelValue( 3, _("Value") ); m_cursorsGrid->SetColLabelSize( -1 ); m_cursorsGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); diff --git a/eeschema/sim/sim_plot_frame_base.fbp b/eeschema/sim/sim_plot_frame_base.fbp index a5659487b1..68ec6860fd 100644 --- a/eeschema/sim/sim_plot_frame_base.fbp +++ b/eeschema/sim/sim_plot_frame_base.fbp @@ -843,7 +843,7 @@ "Signal" "Plot" "Color" "Cursor 1" "Cursor 2" wxALIGN_CENTER 5 - 204,45,45,55,55 + 212,40,45,55,55 1 0 @@ -1107,10 +1107,10 @@ 1 wxALIGN_CENTER -1 - "Cursor" "Signal" "Time" "Voltage / Current" + "Cursor" "Signal" "Time" "Value" wxALIGN_CENTER 4 - 44,152,103,106 + 45,162,100,100 1 0 diff --git a/eeschema/sim/sim_plot_panel.cpp b/eeschema/sim/sim_plot_panel.cpp index 6c790a7d01..67fec6f8f2 100644 --- a/eeschema/sim/sim_plot_panel.cpp +++ b/eeschema/sim/sim_plot_panel.cpp @@ -130,7 +130,7 @@ class LIN_SCALE : public parent { public: LIN_SCALE( const wxString& name, const wxString& unit, int flags ) : - parent( name, flags ), + parent( name, flags, false ), m_unit( unit ) {}; @@ -174,7 +174,7 @@ class LOG_SCALE : public parent { public: LOG_SCALE( const wxString& name, const wxString& unit, int flags ) : - parent( name, flags ), + parent( name, flags, false ), m_unit( unit ) {}; @@ -377,12 +377,13 @@ void CURSOR::UpdateReference() SIM_PLOT_PANEL::SIM_PLOT_PANEL( const wxString& aCommand, int aOptions, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, - const wxString& name ) - : SIM_PANEL_BASE( aCommand, aOptions, parent, id, pos, size, style, name ), - m_axis_x( nullptr ), - m_axis_y1( nullptr ), - m_axis_y2( nullptr ), - m_dotted_cp( false ) + const wxString& name ) : + SIM_PANEL_BASE( aCommand, aOptions, parent, id, pos, size, style, name ), + m_axis_x( nullptr ), + m_axis_y1( nullptr ), + m_axis_y2( nullptr ), + m_axis_y3( nullptr ), + m_dotted_cp( false ) { m_sizer = new wxBoxSizer( wxVERTICAL ); m_plotWin = new mpWindow( this, wxID_ANY, pos, size, style ); @@ -449,22 +450,36 @@ wxString SIM_PLOT_PANEL::GetUnitsY2() const } -void SIM_PLOT_PANEL::updateAxes() +wxString SIM_PLOT_PANEL::GetUnitsY3() const { - bool skipAddToView = false; + LIN_SCALE* linScale = dynamic_cast*>( m_axis_y3 ); - if( m_axis_x ) - skipAddToView = true; + if( linScale ) + return linScale->GetUnits(); + else + return wxEmptyString; +} + +void SIM_PLOT_PANEL::updateAxes( SIM_TRACE_TYPE aNewTraceType ) +{ switch( GetType() ) { case ST_AC: if( !m_axis_x ) { m_axis_x = new LOG_SCALE( wxEmptyString, wxT( "Hz" ), mpALIGN_BOTTOM ); + m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); + m_plotWin->AddLayer( m_axis_x ); + m_axis_y1 = new LIN_SCALE( wxEmptyString, wxT( "dBV" ), mpALIGN_LEFT ); + m_axis_y1->SetNameAlign( mpALIGN_LEFT ); + m_plotWin->AddLayer( m_axis_y1 ); + m_axis_y2 = new LIN_SCALE( wxEmptyString, wxT( "°" ), mpALIGN_RIGHT ); + m_axis_y2->SetNameAlign( mpALIGN_RIGHT ); m_axis_y2->SetMasterScale( m_axis_y1 ); + m_plotWin->AddLayer( m_axis_y2 ); } m_axis_x->SetName( _( "Frequency" ) ); @@ -480,7 +495,12 @@ void SIM_PLOT_PANEL::updateAxes() if( !m_axis_x ) { m_axis_x = new LOG_SCALE( wxEmptyString, wxT( "Hz" ), mpALIGN_BOTTOM ); - m_axis_y1 = new mpScaleY( wxEmptyString, mpALIGN_LEFT ); + m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); + m_plotWin->AddLayer( m_axis_x ); + + m_axis_y1 = new mpScaleY( wxEmptyString, mpALIGN_LEFT, false ); + m_axis_y1->SetNameAlign( mpALIGN_LEFT ); + m_plotWin->AddLayer( m_axis_y1 ); } m_axis_x->SetName( _( "Frequency" ) ); @@ -491,45 +511,42 @@ void SIM_PLOT_PANEL::updateAxes() if( !m_axis_x ) { m_axis_x = new LIN_SCALE( wxEmptyString, wxT( "s" ), mpALIGN_BOTTOM ); + m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); + m_plotWin->AddLayer( m_axis_x ); + m_axis_y1 = new LIN_SCALE(wxEmptyString, wxT( "V" ), mpALIGN_LEFT ); + m_axis_y1->SetNameAlign( mpALIGN_LEFT ); + m_plotWin->AddLayer( m_axis_y1 ); + m_axis_y2 = new LIN_SCALE( wxEmptyString, wxT( "A" ), mpALIGN_RIGHT ); + m_axis_y2->SetNameAlign( mpALIGN_RIGHT ); m_axis_y2->SetMasterScale( m_axis_y1 ); + m_plotWin->AddLayer( m_axis_y2 ); } m_axis_x->SetName( _( "Time" ) ); m_axis_y1->SetName( _( "Voltage" ) ); m_axis_y2->SetName( _( "Current" ) ); + + if( aNewTraceType == SPT_POWER && !m_axis_y3 ) + { + m_plotWin->SetMargins( 35, 140, 35, 70 ); + + m_axis_y3 = new LIN_SCALE( wxEmptyString, wxT( "W" ), mpALIGN_FAR_RIGHT ); + m_axis_y3->SetNameAlign( mpALIGN_FAR_RIGHT ); + m_axis_y3->SetMasterScale( m_axis_y1 ); + m_plotWin->AddLayer( m_axis_y3 ); + } + + if( m_axis_y3 ) + m_axis_y3->SetName( _( "Power" ) ); + break; default: // suppress warnings break; } - - if( skipAddToView ) - return; - - if( m_axis_x ) - { - m_axis_x->SetTicks( false ); - m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); - - m_plotWin->AddLayer( m_axis_x ); - } - - if( m_axis_y1 ) - { - m_axis_y1->SetTicks( false ); - m_axis_y1->SetNameAlign( mpALIGN_LEFT ); - m_plotWin->AddLayer( m_axis_y1 ); - } - - if( m_axis_y2 ) - { - m_axis_y2->SetTicks( false ); - m_axis_y2->SetNameAlign( mpALIGN_RIGHT ); - m_plotWin->AddLayer( m_axis_y2 ); - } } void SIM_PLOT_PANEL::prepareDCAxes() @@ -558,38 +575,62 @@ void SIM_PLOT_PANEL::prepareDCAxes() default: case 'v': if( !m_axis_x ) + { m_axis_x = new LIN_SCALE( wxEmptyString, wxT( "V" ), mpALIGN_BOTTOM ); + m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); + m_plotWin->AddLayer( m_axis_x ); + } m_axis_x->SetName( _( "Voltage (swept)" ) ); break; case 'i': if( !m_axis_x ) + { m_axis_x = new LIN_SCALE( wxEmptyString, wxT( "A" ), mpALIGN_BOTTOM ); + m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); + m_plotWin->AddLayer( m_axis_x ); + } m_axis_x->SetName( _( "Current (swept)" ) ); break; case 'r': if( !m_axis_x ) + { m_axis_x = new LIN_SCALE( wxEmptyString, wxT( "Ω" ), mpALIGN_BOTTOM ); + m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); + m_plotWin->AddLayer( m_axis_x ); + } m_axis_x->SetName( _( "Resistance (swept)" ) ); break; case 't': if( !m_axis_x ) + { m_axis_x = new LIN_SCALE( wxEmptyString, wxT( "°C" ), mpALIGN_BOTTOM ); + m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); + m_plotWin->AddLayer( m_axis_x ); + } m_axis_x->SetName( _( "Temperature (swept)" ) ); break; } if( !m_axis_y1 ) + { m_axis_y1 = new LIN_SCALE( wxEmptyString, wxT( "V" ), mpALIGN_LEFT ); + m_axis_y1->SetNameAlign( mpALIGN_LEFT ); + m_plotWin->AddLayer( m_axis_y1 ); + } if( !m_axis_y2 ) + { m_axis_y2 = new LIN_SCALE( wxEmptyString, wxT( "A" ), mpALIGN_RIGHT ); + m_axis_y2->SetNameAlign( mpALIGN_RIGHT ); + m_plotWin->AddLayer( m_axis_y2 ); + } m_axis_y1->SetName( _( "Voltage (measured)" ) ); m_axis_y2->SetName( _( "Current" ) ); @@ -640,7 +681,7 @@ bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, in { TRACE* trace = nullptr; - updateAxes(); + updateAxes( aType ); // Find previous entry, if there is one auto prev = m_traces.find( aTitle ); @@ -652,9 +693,9 @@ bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, in { bool hasVoltageTraces = false; - for( const auto& tr : m_traces ) + for( const auto& [ name, candidate ] : m_traces ) { - if( !( tr.second->GetType() & SPT_CURRENT ) ) + if( candidate->GetType() & SPT_VOLTAGE ) { hasVoltageTraces = true; break; @@ -662,9 +703,13 @@ bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, in } if( !hasVoltageTraces ) - m_axis_y2->SetMasterScale( nullptr ); - else - m_axis_y2->SetMasterScale( m_axis_y1 ); + { + if( m_axis_y2 ) + m_axis_y2->SetMasterScale( nullptr ); + + if( m_axis_y3 ) + m_axis_y3->SetMasterScale( nullptr ); + } } // New entry @@ -704,6 +749,8 @@ bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, in if( ( aType & SPT_AC_PHASE ) || ( aType & SPT_CURRENT ) ) trace->SetScale( m_axis_x, m_axis_y2 ); + else if( aType & SPT_POWER ) + trace->SetScale( m_axis_x, m_axis_y3 ); else trace->SetScale( m_axis_x, m_axis_y1 ); @@ -782,6 +829,9 @@ void SIM_PLOT_PANEL::ResetScales() if( m_axis_y2 ) m_axis_y2->ResetDataRange(); + if( m_axis_y3 ) + m_axis_y3->ResetDataRange(); + for( auto& [ name, trace ] : m_traces ) trace->UpdateScales(); } diff --git a/eeschema/sim/sim_plot_panel.h b/eeschema/sim/sim_plot_panel.h index 3ecaabc67d..09af037d3e 100644 --- a/eeschema/sim/sim_plot_panel.h +++ b/eeschema/sim/sim_plot_panel.h @@ -219,9 +219,15 @@ public: return m_axis_y2 ? m_axis_y2->GetName() : wxS( "" ); } + wxString GetLabelY3() const + { + return m_axis_y3 ? m_axis_y3->GetName() : wxS( "" ); + } + wxString GetUnitsX() const; wxString GetUnitsY1() const; wxString GetUnitsY2() const; + wxString GetUnitsY3() const; bool TraceShown( const wxString& aName ) const { @@ -245,6 +251,7 @@ public: m_axis_x->SetTicks( !aEnable ); m_axis_y1->SetTicks( !aEnable ); m_axis_y2->SetTicks( !aEnable ); + m_axis_y3->SetTicks( !aEnable ); m_plotWin->UpdateAll(); } @@ -317,7 +324,7 @@ private: void prepareDCAxes(); ///> Create/Ensure axes are available for plotting - void updateAxes(); + void updateAxes( SIM_TRACE_TYPE aNewTraceType = SIM_TRACE_TYPE::SPT_UNKNOWN ); private: SIM_PLOT_COLORS m_colors; @@ -332,6 +339,7 @@ private: mpScaleXBase* m_axis_x; mpScaleY* m_axis_y1; mpScaleY* m_axis_y2; + mpScaleY* m_axis_y3; mpInfoLegend* m_legend; bool m_dotted_cp; diff --git a/eeschema/sim/sim_types.h b/eeschema/sim/sim_types.h index 239e66c8c5..703292b102 100644 --- a/eeschema/sim/sim_types.h +++ b/eeschema/sim/sim_types.h @@ -43,6 +43,21 @@ enum SIM_TYPE }; ///< Possible plot types +enum LEGACY_SIM_TRACE_TYPE +{ + // Y axis + LEGACY_SPT_VOLTAGE = 0x01, + LEGACY_SPT_CURRENT = 0x02, + LEGACY_SPT_AC_PHASE = 0x04, + LEGACY_SPT_AC_MAG = 0x08, + + // X axis + LEGACY_SPT_TIME = 0x10, + LEGACY_SPT_LIN_FREQUENCY = 0x20, + LEGACY_SPT_SWEEP = 0x40 +}; + + enum SIM_TRACE_TYPE { // Y axis @@ -50,12 +65,13 @@ enum SIM_TRACE_TYPE SPT_CURRENT = 0x02, SPT_AC_PHASE = 0x04, SPT_AC_MAG = 0x08, + SPT_POWER = 0x10, // X axis - SPT_TIME = 0x10, - SPT_LIN_FREQUENCY = 0x20, - SPT_LOG_FREQUENCY = 0x20, - SPT_SWEEP = 0x40, + SPT_TIME = 0x0100, + SPT_LIN_FREQUENCY = 0x0200, + SPT_LOG_FREQUENCY = 0x0400, + SPT_SWEEP = 0x0800, SPT_UNKNOWN = 0x00 }; diff --git a/include/widgets/mathplot.h b/include/widgets/mathplot.h index 516a87270a..ee7512a8c7 100644 --- a/include/widgets/mathplot.h +++ b/include/widgets/mathplot.h @@ -487,6 +487,8 @@ protected: #define mpALIGN_BORDER_BOTTOM 0x04 /** Aligns X axis to top border. For mpScaleX */ #define mpALIGN_BORDER_TOP 0x05 +/** Aligns label to the right of mpALIGN_RIGHT */ +#define mpALIGN_FAR_RIGHT 0x06 /** Set label for X axis in normal mode */ #define mpX_NORMAL 0x00 /** Set label for X axis in time mode: the value is represented as minutes:seconds.milliseconds if time is less than 2 minutes, hours:minutes:seconds otherwise. */