24#include <wx/tokenzr.h>
40 fmt.Printf(
"%%.0%df", nDigits );
50static void getSISuffix(
double x,
const wxString& unit,
int& power, wxString& suffix )
52 const int n_powers = 11;
80 for(
int i = 0; i < n_powers - 1; i++ )
82 double r_cur = pow( 10, powers[i].exponent );
84 if( fabs( x ) >= r_cur && fabs( x ) < r_cur * 1000.0 )
86 power = powers[i].exponent;
88 if( powers[i].suffix )
89 suffix = wxString( powers[i].suffix ) + unit;
101 if( std::isnan( x ) )
104 auto countSignificantDigits =
107 while( k && ( k % 10LL ) == 0LL )
121 int64_t k = (int)( ( x - floor( x ) ) * pow( 10.0, (
double) maxDigits ) );
122 int n = countSignificantDigits( k );
125 n = std::min( n, countSignificantDigits( k + 1 ) );
131template <
typename T_PARENT>
136 T_PARENT(
name, flags, false ),
145 double maxVis = T_PARENT::AbsVisibleMaxValue();
150 int constexpr MAX_DIGITS = 3;
151 int constexpr MAX_DISAMBIGUATION_DIGITS = 6;
152 bool duplicateLabels =
false;
156 double sf = pow( 10.0, power );
163 for(
size_t ii = 0; ii < T_PARENT::m_tickLabels.size(); ++ii )
170 if( ii > 0 && l.
label == T_PARENT::m_tickLabels[ii-1].label )
171 duplicateLabels =
true;
174 while( duplicateLabels && ++digits <= MAX_DISAMBIGUATION_DIGITS );
199 LIN_SCALE::ExtendDataRange( minV, maxV );
229template <
typename T_PARENT>
234 T_PARENT(
name, flags, false ),
245 int constexpr MAX_DIGITS = 3;
250 double sf = pow( 10.0, power );
268 int radius = std::min( plotW, plotH ) / 2 - 15;
273 aView.
center = wxPoint( mL + plotW / 2, mT + plotH / 2 );
277 aView.
plotRect = wxRect( mL, mT, plotW, plotH );
287 wxRealPoint pan = tab ? tab->
GetSmithPan() : wxRealPoint( 0.0, 0.0 );
303 const wxRect& plotRect = view.
plotRect;
304 int mL = plotRect.x, mT = plotRect.y, plotW = plotRect.width, plotH = plotRect.height;
306 aDC.SetClippingRegion( plotRect );
309 auto segmentsFor = [&](
double aR ) ->
int
315 auto drawClippedCircle = [&](
double aCx,
double aCy,
double aR )
317 constexpr double LIMIT = 1.0002;
319 std::vector<wxPoint> run;
320 int segments = segmentsFor( aR );
322 for(
int ii = 0; ii <= segments; ii++ )
324 double angle = 2.0 *
M_PI * ii / segments;
325 double re = aCx + aR * cos( angle );
326 double im = aCy + aR * sin( angle );
328 if( re * re + im * im <= LIMIT )
330 run.push_back( view.
ToScreen( re, im ) );
335 aDC.DrawLines( (
int) run.size(), run.data() );
342 aDC.DrawLines( (
int) run.size(), run.data() );
345 auto formatValue = [](
double aValue ) -> wxString
347 return wxString::Format( wxS(
"%g" ), aValue );
353 static const std::vector<double> baseVals = { 0.2, 0.5, 1.0, 2.0, 5.0 };
354 std::vector<double> gridVals = baseVals;
356 if( view.
zoom >= 2.0 )
357 gridVals.insert( gridVals.end(), { 0.1, 0.3, 0.4, 0.7, 1.5, 3.0, 10.0 } );
359 if( view.
zoom >= 5.0 )
360 gridVals.insert( gridVals.end(), { 0.05, 0.15, 0.6, 0.8, 1.2, 1.7, 2.5, 4.0, 7.0, 20.0 } );
362 wxPen gridPen =
m_pen;
363 gridPen.SetStyle( wxPENSTYLE_DOT );
365 aDC.SetBrush( *wxTRANSPARENT_BRUSH );
367 aDC.SetTextForeground(
m_pen.GetColour() );
368 aDC.SetPen( gridPen );
371 for(
double r : gridVals )
372 drawClippedCircle( r / ( 1.0 + r ), 0.0, 1.0 / ( 1.0 + r ) );
375 for(
double x : gridVals )
377 drawClippedCircle( 1.0, 1.0 / x, 1.0 / x );
378 drawClippedCircle( 1.0, -1.0 / x, 1.0 / x );
387 constexpr double LABEL_LIMIT = 1.0002;
389 auto anchorPos = [&](
double aRe,
double aIm, wxPoint& aOut ) ->
bool
391 if( aRe * aRe + aIm * aIm > LABEL_LIMIT )
394 wxPoint p = view.
ToScreen( aRe, aIm );
396 if( !plotRect.Contains( p ) )
404 auto edgePos = [&](
double aCx,
double aCy,
double aR, wxPoint& aOut ) ->
bool
406 int bestMargin = std::numeric_limits<int>::max();
408 int segments = segmentsFor( aR );
410 for(
int ii = 0; ii <= segments; ii++ )
412 double angle = 2.0 *
M_PI * ii / segments;
413 double re = aCx + aR * cos( angle );
414 double im = aCy + aR * sin( angle );
416 if( re * re + im * im > LABEL_LIMIT )
419 wxPoint p = view.
ToScreen( re, im );
421 if( !plotRect.Contains( p ) )
424 int margin = std::min( { p.x - mL, mL + plotW - p.x, p.y - mT, mT + plotH - p.y } );
426 if( margin < bestMargin )
437 auto clampToPlot = [&](
const wxPoint& aPos,
const wxSize& aExt ) -> wxPoint
439 return wxPoint( std::clamp( aPos.x, mL + 1, mL + plotW - aExt.x - 1 ),
440 std::clamp( aPos.y, mT + 1, mT + plotH - aExt.y - 1 ) );
443 auto drawEdgeLabel = [&](
const wxString& aLabel,
const wxPoint& aAt )
445 wxSize ext = aDC.GetTextExtent( aLabel );
447 aDC.DrawText( aLabel, clampToPlot( wxPoint( aAt.x - ext.x / 2, aAt.y + 3 ), ext ) );
451 auto drawRimLabel = [&](
const wxString& aLabel,
const wxPoint& aAt,
double aRe,
double aIm )
453 wxSize ext = aDC.GetTextExtent( aLabel );
458 pos.x -=
KiROUND( ext.x * ( 1.0 - aRe ) / 2.0 );
459 pos.y -=
KiROUND( ext.y * ( 1.0 + aIm ) / 2.0 );
461 aDC.DrawText( aLabel, clampToPlot( pos, ext ) );
467 if( anchorPos( -1.0, 0.0, at ) )
468 drawRimLabel( wxS(
"0" ), at, -1.0, 0.0 );
469 else if( edgePos( 0.0, 0.0, 1.0, at ) )
470 drawEdgeLabel( wxS(
"0" ), at );
472 for(
double r : gridVals )
474 if( anchorPos( ( r - 1.0 ) / ( r + 1.0 ), 0.0, at ) || edgePos( r / ( 1.0 + r ), 0.0, 1.0 / ( 1.0 + r ), at ) )
476 drawEdgeLabel( formatValue( r * labelScale ), at );
480 for(
double x : gridVals )
482 double d = x * x + 1.0;
483 double re = ( x * x - 1.0 ) / d;
484 double im = 2.0 * x / d;
485 wxString posLabel = wxS(
"j" ) + formatValue( x * labelScale );
486 wxString negLabel = wxS(
"-j" ) + formatValue( x * labelScale );
488 if( anchorPos( re, im, at ) )
489 drawRimLabel( posLabel, at, re, im );
490 else if( edgePos( 1.0, 1.0 / x, 1.0 / x, at ) )
491 drawEdgeLabel( posLabel, at );
493 if( anchorPos( re, -im, at ) )
494 drawRimLabel( negLabel, at, re, -im );
495 else if( edgePos( 1.0, -1.0 / x, 1.0 / x, at ) )
496 drawEdgeLabel( negLabel, at );
501 wxString note =
_(
"normalized" );
502 wxSize ext = aDC.GetTextExtent( note );
504 aDC.DrawText( note, mL + 4, mT + plotH - ext.y - 4 );
507 aDC.DestroyClippingRegion();
521 const std::vector<double>& xs =
GetDataX();
522 const std::vector<double>& ys =
GetDataY();
523 size_t count = std::min( xs.size(), ys.size() );
529 aDC.SetClippingRegion( view.
plotRect );
533 if(
GetSweepCount() <= 1 || chunk == std::numeric_limits<size_t>::max() || chunk == 0 )
536 std::vector<wxPoint> pts;
542 aDC.DrawLines( (
int) pts.size(), pts.data() );
544 else if( pts.size() == 1 )
546 aDC.SetBrush( wxBrush(
m_pen.GetColour() ) );
547 aDC.DrawCircle( pts[0], 2 );
553 for(
size_t start = 0; start < count; start += chunk )
555 size_t end = std::min( count, start + chunk );
557 for(
size_t ii = start; ii <
end; ii++ )
560 if( !std::isfinite( xs[ii] ) || !std::isfinite( ys[ii] ) )
566 pts.emplace_back( view.
ToScreen( xs[ii], ys[ii] ) );
572 aDC.DestroyClippingRegion();
578 const std::vector<double>& re =
m_trace->GetDataX();
579 const std::vector<double>& im =
m_trace->GetDataY();
580 const std::vector<double>& freqs =
static_cast<SMITH_TRACE*
>(
m_trace )->GetFrequencies();
582 size_t count = std::min( re.size(), im.size() );
587 m_index = std::clamp( aIndex, 0, (
int) count - 1 );
599 const std::vector<double>& freqs =
static_cast<SMITH_TRACE*
>(
m_trace )->GetFrequencies();
600 const std::vector<double>& re =
m_trace->GetDataX();
601 const std::vector<double>& im =
m_trace->GetDataY();
606 size_t end = freqs.size();
607 size_t chunk =
m_trace->GetSweepSize();
609 if(
m_trace->GetSweepCount() > 1 && chunk > 0 && chunk != std::numeric_limits<size_t>::max() &&
m_index >= 0
610 && (
size_t)
m_index < freqs.size() )
612 begin = ( (size_t)
m_index / chunk ) * chunk;
613 end = std::min( freqs.size(), begin + chunk );
617 double bestDist = std::numeric_limits<double>::max();
619 for(
size_t ii = begin; ii <
end; ii++ )
621 if( !std::isfinite( freqs[ii] ) )
624 if( ii < re.size() && ii < im.size() && ( !std::isfinite( re[ii] ) || !std::isfinite( im[ii] ) ) )
627 double dist = std::fabs( freqs[ii] - aFreq );
629 if( dist < bestDist )
706 const std::vector<double>& re =
m_trace->GetDataX();
707 const std::vector<double>& im =
m_trace->GetDataY();
708 size_t count = std::min( re.size(), im.size() );
727 double bestDist = std::numeric_limits<double>::max();
729 for(
size_t ii = 0; ii < count; ii++ )
731 if( !std::isfinite( re[ii] ) || !std::isfinite( im[ii] ) )
734 wxPoint p = view.
ToScreen( re[ii], im[ii] );
735 double dx = (double) p.x -
m_dim.x;
736 double dy = (double) p.y -
m_dim.y;
737 double dist = dx * dx + dy * dy;
739 if( dist < bestDist )
762 wxQueueEvent( aWindow.GetParent(),
new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
774 m_dim.SetX( marker.x );
775 m_dim.SetY( marker.y );
784 wxColour fg = aWindow.GetForegroundColour();
787 pen.SetColour( cursorColor.
ToColour() );
788 pen.SetStyle( wxPENSTYLE_SOLID );
790 aDC.SetBrush( *wxTRANSPARENT_BRUSH );
792 aDC.DrawCircle( marker, 4 );
793 aDC.DrawLine( marker.x - 8, marker.y, marker.x - 4, marker.y );
794 aDC.DrawLine( marker.x + 4, marker.y, marker.x + 8, marker.y );
795 aDC.DrawLine( marker.x, marker.y - 8, marker.x, marker.y - 4 );
796 aDC.DrawLine( marker.x, marker.y + 4, marker.x, marker.y + 8 );
803 auto formatSI = [](
double aValue,
const wxString& aUnit ) -> wxString
805 if( std::isnan( aValue ) )
813 double sf = pow( 10.0, power );
815 return formatFloat( aValue / sf, 3 ) + wxS(
" " ) + suffix;
818 std::vector<wxString> lines;
820 lines.push_back(
getID() + wxS(
": f = " ) + formatSI( freq, wxS(
"Hz" ) ) );
824 lines.push_back( wxS(
"Z = inf" ) );
828 lines.push_back( wxString::Format( wxS(
"Z = %s %s j%s" ), formatSI( zr, wxS(
"Ω" ) ),
829 zi < 0 ? wxS(
"-" ) : wxS(
"+" ),
830 formatSI( std::fabs( zi ), wxS(
"Ω" ) ) ) );
833 if( std::isfinite( freq ) && freq > 0.0 && zi != 0.0 )
845 if( std::isfinite( rl ) )
846 lines.push_back( wxString::Format( wxS(
"RL = %s dB" ),
formatFloat( rl, 1 ) ) );
848 lines.push_back( wxS(
"RL = inf" ) );
850 if( std::isfinite( vswr ) )
851 lines.push_back( wxString::Format( wxS(
"VSWR = %s" ),
formatFloat( vswr, 2 ) ) );
853 lines.push_back( wxS(
"VSWR = inf" ) );
859 int lineH = aDC.GetTextExtent( wxS(
"M" ) ).y;
861 for(
const wxString& line : lines )
862 boxW = std::max( boxW, aDC.GetTextExtent( line ).x );
865 boxH = (int) lines.size() * lineH + 6;
867 wxPoint boxPos( marker.x + ( marker.x < aWindow.
GetScrX() / 2 ? 12 : -12 - boxW ),
868 marker.y + ( marker.y < aWindow.
GetScrY() / 2 ? 12 : -12 - boxH ) );
870 boxPos.x = std::clamp( boxPos.x, 0, std::max( 0, aWindow.
GetScrX() - boxW ) );
871 boxPos.y = std::clamp( boxPos.y, 0, std::max( 0, aWindow.
GetScrY() - boxH ) );
873 wxBrush labelBrush( aWindow.GetBackgroundColour() );
875 aDC.SetBrush( labelBrush );
876 aDC.DrawRectangle( wxRect( boxPos, wxSize( boxW, boxH ) ) );
877 aDC.SetTextForeground( cursorColor.
ToColour() );
879 for(
size_t ii = 0; ii < lines.size(); ii++ )
880 aDC.DrawText( lines[ii], boxPos.x + 4, boxPos.y + 3 + (
int) ii * lineH );
908 &&
m_trace->GetSweepSize() != std::numeric_limits<size_t>::max() )
912 double plotY =
m_window->p2y( newY );
929 int sweepCount =
m_trace->GetSweepCount();
930 size_t sweepSize =
m_trace->GetSweepSize();
932 if( sweepCount <= 1 )
935 if( sweepSize == std::numeric_limits<size_t>::max() || sweepSize == 0 )
956 const std::vector<double>& dataX =
m_trace->GetDataX();
957 const std::vector<double>& dataY =
m_trace->GetDataY();
959 if( dataX.size() <= 1 )
967 size_t endIdx = dataX.size();
968 int sweepCount =
m_trace->GetSweepCount();
969 size_t sweepSize =
m_trace->GetSweepSize();
971 if( snapToNearest &&
m_trace->IsMultiRun() && sweepCount > 1
972 && sweepSize != std::numeric_limits<size_t>::max() && sweepSize > 0
973 && std::isfinite( snapTargetY ) )
975 double bestDistance = std::numeric_limits<double>::infinity();
979 for(
int sweepIdx = 0; sweepIdx < sweepCount; ++sweepIdx )
981 size_t candidateStart =
static_cast<size_t>( sweepIdx ) * sweepSize;
982 size_t candidateEnd = std::min( dataX.size(), candidateStart + sweepSize );
984 if( candidateStart >= candidateEnd )
987 auto candidateBegin = dataX.begin() + candidateStart;
988 auto candidateEndIt = dataX.begin() + candidateEnd;
989 auto candidateMaxIt = std::upper_bound( candidateBegin, candidateEndIt,
m_coords.x );
990 int candidateMaxIdx = candidateMaxIt - dataX.begin();
991 int candidateMinIdx = candidateMaxIdx - 1;
993 if( candidateMinIdx < (
int) candidateStart
994 || candidateMaxIdx >= (
int) candidateEnd
995 || candidateMaxIdx >= (
int) dataX.size() )
1000 double leftX = dataX[candidateMinIdx];
1001 double rightX = dataX[candidateMaxIdx];
1003 if( leftX == rightX )
1006 double leftY = dataY[candidateMinIdx];
1007 double rightY = dataY[candidateMaxIdx];
1008 double value = leftY + ( rightY - leftY ) / ( rightX - leftX ) * (
m_coords.x - leftX );
1009 double distance = std::fabs( value - snapTargetY );
1014 bestSweep = sweepIdx;
1023 if(
m_trace->IsMultiRun() && sweepCount > 1
1024 && sweepSize != std::numeric_limits<size_t>::max() && sweepSize > 0 )
1026 size_t available =
static_cast<size_t>( sweepCount ) * sweepSize;
1028 if( available <= dataX.size() )
1033 startIdx =
static_cast<size_t>(
m_sweepIndex ) * sweepSize;
1034 endIdx = std::min( dataX.size(), startIdx + sweepSize );
1046 if( startIdx >= endIdx )
1052 auto beginIt = dataX.begin() + startIdx;
1053 auto endIt = dataX.begin() + endIdx;
1056 auto maxXIt = std::upper_bound( beginIt, endIt,
m_coords.x );
1057 int maxIdx = maxXIt - dataX.begin();
1058 int minIdx = maxIdx - 1;
1061 if( minIdx < (
int) startIdx || maxIdx >= (
int) endIdx || maxIdx >= (
int) dataX.size() )
1070 const double leftX = dataX[minIdx];
1071 const double rightX = dataX[maxIdx];
1072 const double leftY = dataY[minIdx];
1073 const double rightY = dataY[maxIdx];
1076 m_coords.y = leftY + ( rightY - leftY ) / ( rightX - leftX ) * (
m_coords.x - leftX );
1085 return wxString::Format(
_(
"%d" ),
id );
1088 return wxEmptyString;
1106 wxQueueEvent( aWindow.GetParent(),
new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
1124 const bool hasY = std::isfinite(
m_coords.y );
1136 wxColour fg = aWindow.GetForegroundColour();
1140 if( cursorColor.
Distance( textColor ) < 0.66 )
1143 pen.SetColour( cursorColor.
ToColour() );
1144 pen.SetStyle(
m_continuous ? wxPENSTYLE_SOLID : wxPENSTYLE_LONG_DASH );
1147 if( hasY && topPx < cursorPos.y && cursorPos.y < bottomPx )
1148 aDC.DrawLine( leftPx, cursorPos.y, rightPx, cursorPos.y );
1150 if( leftPx < cursorPos.x && cursorPos.x < rightPx )
1152 aDC.DrawLine( cursorPos.x, topPx, cursorPos.x, bottomPx );
1154 wxString
id =
getID();
1155 wxSize size = aDC.GetTextExtent( wxS(
"M" ) );
1156 wxRect textRect( wxPoint( cursorPos.x + 1 - size.x / 2, topPx - 4 - size.y ), size );
1167 size.y = ( size.y / 2 ) * 2;
1168 poly[0] = { cursorPos.x - 1 - size.y / 2, topPx - size.y };
1169 poly[1] = { cursorPos.x + 1 + size.y / 2, topPx - size.y };
1170 poly[2] = { cursorPos.x, topPx };
1172 brush.SetStyle( wxBRUSHSTYLE_SOLID );
1173 brush.SetColour(
m_trace->GetTraceColour() );
1174 aDC.SetBrush( brush );
1175 aDC.DrawPolygon( 3, poly );
1177 aDC.SetTextForeground( textColor.
ToColour() );
1178 aDC.DrawLabel(
id, textRect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL );
1181 &&
m_trace->GetSweepSize() != std::numeric_limits<size_t>::max() )
1184 const std::vector<wxString>& labels =
m_trace->GetMultiRunLabels();
1192 runLabel = wxString::Format(
_(
"Run %d" ),
m_sweepIndex + 1 );
1195 wxSize runSize = aDC.GetTextExtent( runLabel );
1196 int runX = textRect.GetRight() + 6;
1197 wxRect runRect( wxPoint( runX, textRect.y ), runSize );
1199 runRect.Inflate( 3, 1 );
1201 wxBrush labelBrush( aWindow.GetBackgroundColour() );
1202 wxPen labelPen( cursorColor.
ToColour() );
1204 aDC.SetPen( labelPen );
1205 aDC.SetBrush( labelBrush );
1206 aDC.DrawRectangle( runRect );
1207 aDC.SetTextForeground( cursorColor.
ToColour() );
1208 aDC.DrawLabel( runLabel, runRect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL );
1220 bool nearX = std::isfinite(
m_coords.x )
1222 bool nearY = std::isfinite(
m_coords.y )
1225 return nearX || nearY;
1245 SIM_TAB( aSimCommand, parent ),
1257 m_sizer =
new wxBoxSizer( wxVERTICAL );
1261 m_plotWin->SetMargins( 30, 70, 45, 70 );
1304 m_axis_y1->SetAxisMinMax( aLock, aMin, aMax );
1311 m_axis_y2->SetAxisMinMax( aLock, aMin, aMax );
1318 m_axis_y3->SetAxisMinMax( aLock, aMin, aMax );
1332 return wxEmptyString;
1343 return wxEmptyString;
1354 return wxEmptyString;
1365 return wxEmptyString;
1445 m_axis_y1->SetName(
_(
"Noise (V/√Hz)" ) );
1448 m_axis_y2->SetName(
_(
"Noise (A/√Hz)" ) );
1506 m_plotWin->SetMargins( 30, 160, 45, 70 );
1516 m_plotWin->SetMargins( 30, 70, 45, 70 );
1544 if( sim_cmd.StartsWith(
".dc", &rem ) )
1552 ch = rem.GetChar( 0 );
1571 m_axis_x->SetName(
_(
"Voltage (swept)" ) );
1582 m_axis_x->SetName(
_(
"Current (swept)" ) );
1593 m_axis_x->SetName(
_(
"Resistance (swept)" ) );
1604 m_axis_x->SetName(
_(
"Temperature (swept)" ) );
1622 m_axis_y1->SetName(
_(
"Voltage (measured)" ) );
1638 m_plotWin->SetMargins( 30, 160, 45, 70 );
1680 wxPenStyle penStyle;
1683 penStyle = wxPENSTYLE_SOLID;
1685 penStyle =
m_dotted_cp ? wxPENSTYLE_DOT : wxPENSTYLE_SOLID;
1687 penStyle =
m_dotted_cp ? wxPENSTYLE_DOT : wxPENSTYLE_SOLID;
1689 penStyle = wxPENSTYLE_SOLID;
1706 bool hasVoltageTraces =
false;
1708 for(
const auto& [
id, candidate ] :
m_traces )
1712 hasVoltageTraces =
true;
1717 if( !hasVoltageTraces )
1748 int aSweepCount,
size_t aSweepSize,
bool aIsMultiRun,
1749 const std::vector<wxString>& aMultiRunLabels )
1757 if( aX.size() > 0 && aX[0] == 0 )
1759 aX.erase( aX.begin() );
1760 aY.erase( aY.begin() );
1768 for(
double& pt : aY )
1769 pt = pt * 180.0 /
M_PI;
1773 for(
double& pt : aY )
1788 trace->
SetScale(
nullptr,
nullptr );
1816 bool hasY1Traces =
false;
1817 bool hasY2Traces =
false;
1818 bool hasY3Traces =
false;
1843 bool visibilityChanged =
false;
1848 visibilityChanged =
true;
1854 visibilityChanged =
true;
1860 visibilityChanged =
true;
1866 visibilityChanged =
true;
1869 if( visibilityChanged )
1878 if( trace == aTrace )
1891 m_plotWin->DelLayer( aTrace,
true,
true );
1988 double newZoom = std::clamp(
m_smithZoom * aFactor, 1.0, 50.0 );
1990 if( newZoom <= 1.0 )
2028 if( aEvent.GetWheelAxis() != wxMOUSE_WHEEL_VERTICAL || aEvent.GetWheelRotation() == 0 )
2032 SmithZoomAt( aEvent.GetPosition(), aEvent.GetWheelRotation() > 0 ? 1.2 : 1.0 / 1.2 );
2044 double factor = aEvent.GetMagnification() + 1.0;
2065 wxPoint pos = aEvent.GetPosition();
2091 wxPoint pos = aEvent.GetPosition();
2101 if( aEvent.MiddleIsDown() )
2129 wxPoint pos = aEvent.GetPosition();
2161 wxMenu* menu =
m_plotWin->GetPopupMenu();
2166 m_plotWin->PopupMenu( menu, aEvent.GetPosition() );
2178 switch( aEvent.GetId() )
2201 default: aEvent.Skip();
2219 if( !freqs.empty() )
2220 cursor->SetCoordX( freqs[freqs.size() * ( aCursorId == 1 ? 2 : 3 ) / 5] );
2233 cursor->SetName( aSignalName );
2238 wxQueueEvent(
this,
new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
2246 aTrace->
SetCursor( aCursorId,
nullptr );
2250 wxQueueEvent(
this,
new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
2263 wxStringTokenizer tokenizer(
GetSimCommand(),
" \t\r\n", wxTOKEN_STRTOK );
2264 wxString cmd = tokenizer.GetNextToken().Lower();
2266 wxASSERT( cmd == wxS(
".tran" ) );
2272 if( tokenizer.HasMoreTokens() )
2275 if( tokenizer.HasMoreTokens() )
2278 if( tokenizer.HasMoreTokens() )
2295 trace->UpdateScales();
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
The SIMULATOR_FRAME holds the main user-interface for running simulations.
void Move(wxPoint aDelta) override
Moves the layer rectangle of given pixel deltas.
static constexpr int DRAG_MARGIN
bool Inside(const wxPoint &aPoint) const override
Checks whether a point is inside the info box rectangle.
void doSetCoordX(double aValue)
bool OnDoubleClick(const wxPoint &aPoint, mpWindow &aWindow) override
virtual void SetCoordX(double aValue)
void UpdateReference() override
Updates the rectangle reference point.
void Plot(wxDC &aDC, mpWindow &aWindow) override
Plot method.
A color representation with 4 components: red, green, blue, alpha.
COLOR4D & Invert()
Makes the color inverted, alpha remains the same.
wxColour ToColour() const
double Distance(const COLOR4D &other) const
Returns the distance (in RGB space) between two colors.
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
void formatLabels() override
wxString GetUnits() const
LIN_SCALE(const wxString &name, const wxString &unit, int flags)
wxString m_base_axis_label
wxString GetUnits() const
LOG_SCALE(const wxString &name, const wxString &unit, int flags)
void formatLabels() override
bool DeleteTrace(const wxString &aVectorName, int aTraceType)
double GetSmithZoom() const
void UpdateSmithReferenceImpedance()
void onSmithMotion(wxMouseEvent &aEvent)
mpWindow * GetPlotWin() const
void prepareDCAxes(int aNewTraceType)
Create/Ensure axes are available for plotting.
void SetTraceData(TRACE *aTrace, std::vector< double > &aX, std::vector< double > &aY, int aSweepCount, size_t aSweepSize, bool aIsMultiRun=false, const std::vector< wxString > &aMultiRunLabels={})
wxString GetUnitsY2() const
void SetY2Scale(bool aLock, double aMin, double aMax)
void SmithZoomAt(const wxPoint &aPos, double aFactor)
TRACE * GetTrace(const wxString &aVecName, int aType) const
void SetSmithMode(bool aEnable)
void SetY1Scale(bool aLock, double aMin, double aMax)
void onSmithRightDown(wxMouseEvent &aEvent)
void UpdateAxisVisibility()
void SetY3Scale(bool aLock, double aMin, double aMax)
std::map< wxString, TRACE * > m_traces
void UpdateTraceStyle(TRACE *trace)
Update plot colors.
void ResetScales(bool aIncludeX)
Update trace line style.
void onSmithMiddleDown(wxMouseEvent &aEvent)
void onSmithMenuCommand(wxCommandEvent &aEvent)
SIM_PLOT_TAB(const wxString &aSimCommand, wxWindow *parent)
void EnableCursor(TRACE *aTrace, int aCursorId, const wxString &aSignalName)
wxString GetUnitsX() const
void OnLanguageChanged() override
Getter for math plot window.
void EnsureThirdYAxisExists()
wxString getTraceId(const wxString &aVectorName, int aType) const
Construct the plot axes for DC simulation plot.
TRACE * GetOrAddTrace(const wxString &aVectorName, int aType)
void onSmithLeftUp(wxMouseEvent &aEvent)
void SmithPanBy(const wxPoint &aDelta)
Traces and cursors set aside while in Smith mode, restored when leaving it.
wxPoint m_LastLegendPosition
void onSmithDClick(wxMouseEvent &aEvent)
void onSmithRightUp(wxMouseEvent &aEvent)
void onSmithMouseWheel(wxMouseEvent &aEvent)
wxString GetUnitsY1() const
std::map< wxString, wxColour > m_sessionTraceColors
void DisableCursor(TRACE *aTrace, int aCursorId)
Reset scale ranges to fit the current traces.
const wxRealPoint & GetSmithPan() const
void onSmithLeftDown(wxMouseEvent &aEvent)
void ResetSmithView()
Restore a saved view, values are validated and clamped.
bool getSmithView(SMITH_VIEW &aView) const
void updateAxes(int aNewTraceType=SIM_TRACE_TYPE::SPT_UNKNOWN)
void onSmithMagnify(wxMouseEvent &aEvent)
wxString GetUnitsY3() const
SIM_TYPE GetSimType() const
const wxString & GetSimCommand() const
Trace hidden while the tab is in Smith mode, kept so leaving the mode restores it.
void UpdateReference() override
Updates the rectangle reference point.
void Plot(wxDC &aDC, mpWindow &aWindow) override
Plot method.
bool Inside(const wxPoint &aPoint) const override
Checks whether a point is inside the info box rectangle.
void SetCoordX(double aValue) override
void snapToIndex(int aIndex)
void snapToFrequency(double aFreq)
void Move(wxPoint aDelta) override
Moves the layer rectangle of given pixel deltas.
Reflection coefficient locus, Re in X and Im in Y, drawn on the Smith chart.
static bool GetChartView(mpWindow &aWindow, double aZoom, const wxRealPoint &aPan, SMITH_VIEW &aView)
void Plot(wxDC &aDC, mpWindow &aWindow) override
Plot given view of layer to the given device context.
Cursor that snaps along a Smith chart locus, keyed by frequency.
void Plot(wxDC &aDC, mpWindow &aWindow) override
Layer plot handler.
const std::vector< double > & GetFrequencies() const
double GetReferenceImpedance() const
Helper class to recognize Spice formatted values.
void ResetDataRange() override
void ExtendDataRange(double minV, double maxV) override
void SetStartAndEnd(double aStartTime, double aEndTime)
TIME_SCALE(const wxString &name, const wxString &unit, int flags)
Overlay layer drawing the Smith chart grid (constant resistance and reactance circles)
void SetIsMultiRun(bool aIsMultiRun)
void SetTraceColour(const wxColour &aColour)
void SetMultiRunLabels(const std::vector< wxString > &aLabels)
std::map< int, CURSOR * > & GetCursors()
SIM_TRACE_TYPE GetType() const
void SetData(const std::vector< double > &aX, const std::vector< double > &aY) override
Assigns new data set for the trace.
void SetCursor(int aCursorId, CURSOR *aCursor)
const std::vector< double > & GetDataY() const
wxColour GetTraceColour() const
const std::vector< double > & GetDataX() const
CURSOR * GetCursor(int aCursorId)
void SetSweepSize(size_t aSweepSize)
size_t GetSweepSize() const
void SetSweepCount(int aSweepCount)
int GetSweepCount() const override
virtual void SetScale(mpScaleBase *scaleX, mpScaleBase *scaleY)
virtual void UpdateReference()
Updates the rectangle reference point.
virtual void Move(wxPoint delta)
Moves the layer rectangle of given pixel deltas.
Implements the legend to be added to the plot This layer allows you to add a legend to describe the p...
const wxString & GetName() const
Get layer name.
const wxFont & GetFont() const
Get font set for this layer.
const wxPen & GetPen() const
Get pen set for this layer.
void SetPen(const wxPen &pen)
Set layer pen.
Canvas for plotting mpLayer implementations.
int GetMarginLeft() const
int GetScrX() const
Get current view's X dimension in device context units.
int GetScrY() const
Get current view's Y dimension in device context units.
double p2x(wxCoord pixelCoordX)
Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates,...
wxCoord x2p(double x)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
bool DelLayer(mpLayer *layer, bool alsoDeleteObject=false, bool refreshDisplay=true)
Remove a plot layer from the canvas.
wxCoord y2p(double y)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
int GetMarginRight() const
int GetMarginBottom() const
static bool empty(const wxTextEntryBase *aCtrl)
#define mpALIGN_BORDER_RIGHT
Aligns Y axis to right border.
class WXDLLIMPEXP_MATHPLOT mpWindow
#define mpALIGN_RIGHT
Aligns label to the right.
#define mpALIGN_LEFT
Aligns label to the left.
#define mpALIGN_BOTTOM
Aligns label to the bottom.
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
double SeriesCapacitance(double aReactance, double aFreq)
Pan that keeps the gamma point under aPos fixed when the view zooms to aNewZoom.
double SeriesInductance(double aReactance, double aFreq)
double VSWR(double aGammaMag)
wxRealPoint ZoomAboutPoint(const SMITH_VIEW &aView, const wxPoint &aPos, double aNewZoom)
S-parameter vectors are named S_<responsePort>_<drivePort>.
bool GammaToImpedance(double aRe, double aIm, double aZ0, double &aResistance, double &aReactance)
< Impedance of a reflection coefficient, z = z0 ( 1 + gamma ) / ( 1 - gamma ), false at the gamma = 1...
double ReturnLoss(double aGammaMag)
Series equivalent element of a reactance at one frequency, henries for aReactance > 0,...
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
Class is responsible for providing colors for traces on simulation plot.
wxDEFINE_EVENT(EVT_SIM_CURSOR_UPDATE, wxCommandEvent)
static void getSISuffix(double x, const wxString &unit, int &power, wxString &suffix)
static int countDecimalDigits(double x, int maxDigits)
static bool smithView(mpWindow &aWindow, SMITH_VIEW &aView)
static wxString formatFloat(double x, int nDigits)
double MagnitudeToDb(double aMagnitude)
Convert a linear magnitude to decibels.
< Smith chart placement plus pan/zoom, maps a gamma point to a screen pixel and back.
wxRealPoint ToGamma(const wxPoint &aPt) const
wxPoint ToScreen(double aRe, double aIm) const