KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_setup_tuning_profile_info.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24
26
28#include <bitmaps.h>
29#include <confirm.h>
30#include <grid_tricks.h>
32#include <pcb_edit_frame.h>
36#include <widgets/wx_grid.h>
37
39 PANEL_SETUP_TUNING_PROFILES* parentPanel ) :
41 m_parentPanel( parentPanel ),
44{
45 Freeze();
46 initPanel();
47 Thaw();
48}
49
50
52{
53 if( EDA_UNIT_UTILS::IsImperialUnit( m_parentPanel->m_unitsProvider->GetUserUnits() ) )
55 else
57
58 m_viaPropagationUnits.SetValue( 0 );
59
62
65
66 m_targetImpedance->SetValue( "0" );
67
68 UNITS_PROVIDER* unitsProvider = m_parentPanel->m_unitsProvider.get();
69
70 m_trackPropagationGrid->SetUnitsProvider( unitsProvider );
71 m_viaOverrides->SetUnitsProvider( unitsProvider );
72
73 // Configure the track grid
74 m_trackPropagationGrid->BeginBatch();
75 m_trackPropagationGrid->SetUseNativeColLabels();
76
77 m_trackPropagationGrid->EnsureColLabelsVisible();
79 m_trackPropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
80
81 std::vector<int> trackColIds;
82 m_trackPropagationGrid->SetAutoEvalColUnits( TRACK_GRID_DELAY,
84 trackColIds.push_back( TRACK_GRID_DELAY );
86 unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::DISTANCE ) );
87 trackColIds.push_back( TRACK_GRID_TRACK_WIDTH );
88 m_trackPropagationGrid->SetAutoEvalColUnits( TRACK_GRID_TRACK_GAP,
89 unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::DISTANCE ) );
90 trackColIds.push_back( TRACK_GRID_TRACK_GAP );
91 m_trackPropagationGrid->SetAutoEvalCols( trackColIds );
92
93 // Add the calculation editors
94 wxGridCellAttr* attr = new wxGridCellAttr;
95 attr->SetEditor( new GRID_CELL_RUN_FUNCTION_EDITOR(
96 m_parentPanel->m_dlg,
97 [this]( int row, int col )
98 {
99 calculateTrackParametersForCell( row, col );
100 },
101 false ) );
103
104 attr = new wxGridCellAttr;
105 attr->SetEditor( new GRID_CELL_RUN_FUNCTION_EDITOR(
106 m_parentPanel->m_dlg,
107 [this]( int row, int col )
108 {
109 calculateTrackParametersForCell( row, col );
110 },
111 false ) );
112 m_trackPropagationGrid->SetColAttr( TRACK_GRID_TRACK_GAP, attr );
113
114 attr = new wxGridCellAttr;
115 attr->SetEditor( new GRID_CELL_RUN_FUNCTION_EDITOR(
116 m_parentPanel->m_dlg,
117 [this]( int row, int col )
118 {
119 calculateTrackParametersForCell( row, col );
120 },
121 false ) );
122 m_trackPropagationGrid->SetColAttr( TRACK_GRID_DELAY, attr );
123
124 m_trackPropagationGrid->EndBatch();
125
126 // Configure the via grid
127 m_viaOverrides->BeginBatch();
128 m_viaOverrides->SetUseNativeColLabels();
129
130 m_viaOverrides->EnsureColLabelsVisible();
131 m_viaOverrides->PushEventHandler( new GRID_TRICKS( m_viaOverrides ) );
132 m_viaOverrides->SetSelectionMode( wxGrid::wxGridSelectRows );
133
134 std::vector<int> viaColIds;
135 m_viaOverrides->SetAutoEvalColUnits( VIA_GRID_DELAY, unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::TIME ) );
136 viaColIds.push_back( VIA_GRID_DELAY );
137 m_viaOverrides->SetAutoEvalCols( viaColIds );
138 m_viaOverrides->EndBatch();
139
141
142 // Hide the trace gap as we start in single mode
144
146}
147
148
150{
151 BOARD* board = m_parentPanel->m_board;
152
153 m_name->SetValue( aProfile.m_ProfileName );
154 m_type->SetSelection( static_cast<int>( aProfile.m_Type ) );
155 onChangeProfileType( aProfile.m_Type );
156 m_targetImpedance->SetValue( wxString::FromDouble( aProfile.m_TargetImpedance ) );
158 m_enableDelayTuning->SetValue( aProfile.m_EnableTimeDomainTuning );
159 m_viaPropagationUnits.SetValue( aProfile.m_ViaPropagationDelay );
160
161 for( const auto& entry : aProfile.m_TrackPropagationEntries )
162 {
163 const int row = m_trackPropagationGrid->GetNumberRows();
164 m_trackPropagationGrid->AppendRows();
165
167 board->GetLayerName( entry.GetSignalLayer() ) );
168
169 if( entry.GetTopReferenceLayer() != UNDEFINED_LAYER )
170 {
172 board->GetLayerName( entry.GetTopReferenceLayer() ) );
173 }
174
175 if( entry.GetBottomReferenceLayer() != UNDEFINED_LAYER )
176 {
178 board->GetLayerName( entry.GetBottomReferenceLayer() ) );
179 }
180
181 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_TRACK_WIDTH, entry.GetWidth() );
182 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_TRACK_GAP, entry.GetDiffPairGap() );
183 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_DELAY, entry.GetDelay( true ) );
184 }
185
186 for( const auto& entry : aProfile.m_ViaOverrides )
187 {
188 const int row = m_viaOverrides->GetNumberRows();
189 m_viaOverrides->AppendRows();
190
191 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, board->GetLayerName( entry.m_SignalLayerFrom ) );
192 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, board->GetLayerName( entry.m_SignalLayerTo ) );
193 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, board->GetLayerName( entry.m_ViaLayerFrom ) );
194 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, board->GetLayerName( entry.m_ViaLayerTo ) );
195 m_viaOverrides->SetUnitValue( row, VIA_GRID_DELAY, entry.m_Delay );
196 }
197
199}
200
201
203{
204 TUNING_PROFILE profile;
205 profile.m_ProfileName = m_name->GetValue();
206 profile.m_Type = static_cast<TUNING_PROFILE::PROFILE_TYPE>( m_type->GetSelection() );
208 profile.m_EnableTimeDomainTuning = m_enableDelayTuning->GetValue();
209 profile.m_ViaPropagationDelay = m_viaPropagationUnits.GetValue();
210
211 double targetImpedance;
212
213 if( m_targetImpedance->GetValue().ToDouble( &targetImpedance ) )
214 profile.m_TargetImpedance = targetImpedance;
215 else
216 profile.m_TargetImpedance = 0.0;
217
218 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); row++ )
219 {
221
222 wxString signalLayerName = m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_SIGNAL_LAYER );
223 entry.SetSignalLayer( m_parentPanel->m_layerNamesToIDs[signalLayerName] );
224
225 if( wxString topReferenceLayerName = m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_TOP_REFERENCE );
226 m_parentPanel->m_layerNamesToIDs.contains( topReferenceLayerName ) )
227 {
228 entry.SetTopReferenceLayer( m_parentPanel->m_layerNamesToIDs[topReferenceLayerName] );
229 }
230 else
231 {
233 }
234
235 if( wxString bottomReferenceLayerName =
237 m_parentPanel->m_layerNamesToIDs.contains( bottomReferenceLayerName ) )
238 {
239 entry.SetBottomReferenceLayer( m_parentPanel->m_layerNamesToIDs[bottomReferenceLayerName] );
240 }
241 else
242 {
244 }
245
246 entry.SetWidth( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_TRACK_WIDTH ) );
247 entry.SetDiffPairGap( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_TRACK_GAP ) );
248 entry.SetDelay( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_DELAY ) );
250
251 profile.m_TrackPropagationEntries.push_back( entry );
252 profile.m_TrackPropagationEntriesMap[entry.GetSignalLayer()] = entry;
253 }
254
255 for( int row = 0; row < m_viaOverrides->GetNumberRows(); row++ )
256 {
257 const wxString signalLayerFrom = m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM );
258 const wxString signalLayerTo = m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO );
259 const wxString viaLayerFrom = m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM );
260 const wxString viaLayerTo = m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_TO );
261 PCB_LAYER_ID signalLayerIdFrom = m_parentPanel->m_layerNamesToIDs[signalLayerFrom];
262 PCB_LAYER_ID signalLayerIdTo = m_parentPanel->m_layerNamesToIDs[signalLayerTo];
263 PCB_LAYER_ID viaLayerIdFrom = m_parentPanel->m_layerNamesToIDs[viaLayerFrom];
264 PCB_LAYER_ID viaLayerIdTo = m_parentPanel->m_layerNamesToIDs[viaLayerTo];
265
266 // Order layers in stackup order (from F_Cu first)
267 if( IsCopperLayerLowerThan( signalLayerIdFrom, signalLayerIdTo ) )
268 std::swap( signalLayerIdFrom, signalLayerIdTo );
269
270 if( IsCopperLayerLowerThan( viaLayerIdFrom, viaLayerIdTo ) )
271 std::swap( viaLayerIdFrom, viaLayerIdTo );
272
273 const DELAY_PROFILE_VIA_OVERRIDE_ENTRY entry{ signalLayerIdFrom, signalLayerIdTo, viaLayerIdFrom, viaLayerIdTo,
274 m_viaOverrides->GetUnitValue( row, VIA_GRID_DELAY ) };
275 profile.m_ViaOverrides.push_back( entry );
276 }
277
278 return profile;
279}
280
281
283{
284 m_trackPropagationGrid->PopEventHandler( true );
285 m_viaOverrides->PopEventHandler( true );
286}
287
288
290{
291 wxArrayString layerNames, layerNamesWithNone;
292 layerNamesWithNone.push_back( "<None>" );
293 std::ranges::for_each( m_parentPanel->m_layerNames,
294 [&layerNames, &layerNamesWithNone]( const wxString& aLayerName )
295 {
296 layerNames.push_back( aLayerName );
297 layerNamesWithNone.push_back( aLayerName );
298 } );
299
300
301 // Save the current data - track grid
302 std::vector<wxString> currentSignalLayer;
303 std::vector<wxString> currentTopReferenceLayer;
304 std::vector<wxString> currentBottomReferenceLayer;
305
306 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); ++row )
307 {
308 currentSignalLayer.emplace_back( m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_SIGNAL_LAYER ) );
309 currentTopReferenceLayer.emplace_back( m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_TOP_REFERENCE ) );
310 currentBottomReferenceLayer.emplace_back(
312 }
313
314 // Save the current data - via grid
315 std::vector<wxString> currentSignalLayersFrom;
316 std::vector<wxString> currentSignalLayersTo;
317 std::vector<wxString> currentViaLayersFrom;
318 std::vector<wxString> currentViaLayersTo;
319
320 for( int row = 0; row < m_viaOverrides->GetNumberRows(); ++row )
321 {
322 currentSignalLayersFrom.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM ) );
323 currentSignalLayersTo.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO ) );
324 currentViaLayersFrom.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM ) );
325 currentViaLayersTo.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_TO ) );
326 }
327
328 // Reset the via layers lists
329 wxGridCellAttr* attr = new wxGridCellAttr;
330 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
332
333 attr = new wxGridCellAttr;
334 attr->SetEditor( new wxGridCellChoiceEditor( layerNamesWithNone, false ) );
336
337 attr = new wxGridCellAttr;
338 attr->SetEditor( new wxGridCellChoiceEditor( layerNamesWithNone, false ) );
340
341 attr = new wxGridCellAttr;
342 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
343 m_viaOverrides->SetColAttr( VIA_GRID_SIGNAL_LAYER_FROM, attr );
344
345 attr = new wxGridCellAttr;
346 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
347 m_viaOverrides->SetColAttr( VIA_GRID_SIGNAL_LAYER_TO, attr );
348
349 attr = new wxGridCellAttr;
350 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
351 m_viaOverrides->SetColAttr( VIA_GRID_VIA_LAYER_FROM, attr );
352
353 attr = new wxGridCellAttr;
354 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
355 m_viaOverrides->SetColAttr( VIA_GRID_VIA_LAYER_TO, attr );
356
357 // Restore the data, changing or resetting layer names if required
358 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); ++row )
359 {
360 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentSignalLayer[row] ) )
361 {
362 PCB_LAYER_ID lastSignalId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayer[row]];
363
364 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalId ) )
366 m_parentPanel->m_board->GetLayerName( lastSignalId ) );
367 else
369 m_parentPanel->m_layerNames.front() );
370 }
371 else
372 {
373 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_SIGNAL_LAYER, m_parentPanel->m_layerNames.front() );
374 }
375
376 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentTopReferenceLayer[row] ) )
377 {
378 const PCB_LAYER_ID lastTopReferenceId = m_parentPanel->m_prevLayerNamesToIDs[currentTopReferenceLayer[row]];
379
380 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastTopReferenceId ) )
382 m_parentPanel->m_board->GetLayerName( lastTopReferenceId ) );
383 else
384 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_TOP_REFERENCE, layerNamesWithNone[0] );
385 }
386 else
387 {
388 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_TOP_REFERENCE, layerNamesWithNone[0] );
389 }
390
391 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentBottomReferenceLayer[row] ) )
392 {
393 const PCB_LAYER_ID lastBottomReferenceId =
394 m_parentPanel->m_prevLayerNamesToIDs[currentBottomReferenceLayer[row]];
395
396 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastBottomReferenceId ) )
398 m_parentPanel->m_board->GetLayerName( lastBottomReferenceId ) );
399 else
400 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, layerNamesWithNone[0] );
401 }
402 else
403 {
404 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, layerNamesWithNone[0] );
405 }
406 }
407
408 for( int row = 0; row < m_viaOverrides->GetNumberRows(); ++row )
409 {
410 const PCB_LAYER_ID lastSignalFromId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayersFrom[row]];
411
412 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalFromId ) )
413 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM,
414 m_parentPanel->m_board->GetLayerName( lastSignalFromId ) );
415 else
416 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_parentPanel->m_layerNames.front() );
417
418 const PCB_LAYER_ID lastSignalToId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayersTo[row]];
419
420 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalToId ) )
421 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO,
422 m_parentPanel->m_board->GetLayerName( lastSignalToId ) );
423 else
424 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_parentPanel->m_layerNames.back() );
425
426 const PCB_LAYER_ID lastViaFromId = m_parentPanel->m_prevLayerNamesToIDs[currentViaLayersFrom[row]];
427
428 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastViaFromId ) )
429 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM,
430 m_parentPanel->m_board->GetLayerName( lastViaFromId ) );
431 else
432 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_parentPanel->m_layerNames.front() );
433
434 const PCB_LAYER_ID lastViaToId = m_parentPanel->m_prevLayerNamesToIDs[currentViaLayersTo[row]];
435
436 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastViaToId ) )
437 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO,
438 m_parentPanel->m_board->GetLayerName( lastViaToId ) );
439 else
440 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_parentPanel->m_layerNames.back() );
441 }
442}
443
444
446{
447 const int minValueWidth = m_trackPropagationGrid->GetTextExtent( wxT( "000.0000 ps/mm" ) ).x;
448
449 for( int i = 0; i < m_trackPropagationGrid->GetNumberCols(); ++i )
450 {
451 const int titleSize = m_trackPropagationGrid->GetTextExtent( m_trackPropagationGrid->GetColLabelValue( i ) ).x;
452
454 m_trackPropagationGrid->SetColSize( i, titleSize + 30 );
455 else
456 m_trackPropagationGrid->SetColSize( i, std::max( titleSize, minValueWidth ) );
457 }
458
459 for( int i = 0; i < m_viaOverrides->GetNumberCols(); ++i )
460 {
461 const int titleSize = GetTextExtent( m_viaOverrides->GetColLabelValue( i ) ).x;
462 if( i == VIA_GRID_DELAY )
463 m_viaOverrides->SetColSize( i, std::max( titleSize, minValueWidth ) );
464 else
465 m_viaOverrides->SetColSize( i, titleSize + 30 );
466 }
467
468 const int impedanceWidth = m_targetImpedance->GetTextExtent( wxT( "0000.00" ) ).x;
469 m_targetImpedance->SetSize( impedanceWidth, m_targetImpedance->GetSize().GetHeight() );
470
471 Layout();
472}
473
474
476{
477 const wxString newName = event.GetString();
478 m_parentPanel->UpdateProfileName( this, newName );
479}
480
481
489
490
492{
493 m_trackPropagationGrid->CommitPendingChanges();
494 m_viaOverrides->CommitPendingChanges();
495
498 else
500}
501
502
504{
505 const int numRows = m_trackPropagationGrid->GetNumberRows();
506 m_trackPropagationGrid->InsertRows( m_trackPropagationGrid->GetNumberRows() );
507
508 auto setFrontRowLayers = [&]( const int row )
509 {
510 auto nameItr = m_parentPanel->m_layerNames.begin();
511
512 if( nameItr == m_parentPanel->m_layerNames.end() )
513 return;
514
515 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_SIGNAL_LAYER, *nameItr );
516
517 ++nameItr;
518
519 if( nameItr == m_parentPanel->m_layerNames.end() )
520 return;
521
522 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, *nameItr );
523 };
524
525 auto setRowLayers = [&]()
526 {
527 if( numRows == 0 )
528 {
529 setFrontRowLayers( 0 );
530 return;
531 }
532
533 const wxString lastSignalLayerName =
534 m_trackPropagationGrid->GetCellValue( numRows - 1, TRACK_GRID_SIGNAL_LAYER );
535 auto nameItr = std::find( m_parentPanel->m_layerNames.begin(), m_parentPanel->m_layerNames.end(),
536 lastSignalLayerName );
537
538 if( nameItr == m_parentPanel->m_layerNames.end() )
539 return;
540
541 if( nameItr == m_parentPanel->m_layerNames.end() - 1 )
542 {
543 setFrontRowLayers( numRows );
544 return;
545 }
546
547 ++nameItr;
548
549 if( nameItr == m_parentPanel->m_layerNames.end() )
550 return;
551
552 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_SIGNAL_LAYER, *nameItr );
553 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_TOP_REFERENCE, *( nameItr - 1 ) );
554
555 ++nameItr;
556
557 if( nameItr != m_parentPanel->m_layerNames.end() )
558 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_BOTTOM_REFERENCE, *nameItr );
559 };
560
561 setRowLayers();
562
563 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_TRACK_WIDTH, 0 );
564 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_TRACK_GAP, 0 );
565 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_DELAY, 0 );
567}
568
569
571{
572 wxArrayInt selRows = m_trackPropagationGrid->GetSelectedRows();
573
574 if( selRows.size() == 1 )
575 m_trackPropagationGrid->DeleteRows( selRows[0] );
576}
577
578
580{
581 const int numRows = m_viaOverrides->GetNumberRows();
582 m_viaOverrides->InsertRows( numRows );
583 m_viaOverrides->SetUnitValue( numRows, VIA_GRID_DELAY, 0 );
584 m_viaOverrides->SetCellValue( numRows, VIA_GRID_SIGNAL_LAYER_FROM, m_parentPanel->m_layerNames.front() );
585 m_viaOverrides->SetCellValue( numRows, VIA_GRID_SIGNAL_LAYER_TO, m_parentPanel->m_layerNames.back() );
586 m_viaOverrides->SetCellValue( numRows, VIA_GRID_VIA_LAYER_FROM, m_parentPanel->m_layerNames.front() );
587 m_viaOverrides->SetCellValue( numRows, VIA_GRID_VIA_LAYER_TO, m_parentPanel->m_layerNames.back() );
589}
590
591
593{
594 wxArrayInt selRows = m_viaOverrides->GetSelectedRows();
595
596 if( selRows.size() == 1 )
597 m_viaOverrides->DeleteRows( selRows[0] );
598}
599
600
602{
603 return m_name->GetValue();
604}
605
606
607double PANEL_SETUP_TUNING_PROFILE_INFO::calculateSkinDepth( const double aFreq, const double aMurc,
608 const double aSigma )
609{
610 return 1.0 / sqrt( M_PI * aFreq * aMurc * TRANSLINE_CALCULATIONS::MU0 * aSigma );
611}
612
613
614int PANEL_SETUP_TUNING_PROFILE_INFO::getStackupLayerId( const std::vector<BOARD_STACKUP_ITEM*>& aLayerList,
615 PCB_LAYER_ID aPcbLayerId )
616{
617 bool layerFound = false;
618 int layerStackupId = 0;
619
620 while( layerStackupId < static_cast<int>( aLayerList.size() ) && !layerFound )
621 {
622 if( aLayerList.at( layerStackupId )->GetBrdLayerId() != aPcbLayerId )
623 ++layerStackupId;
624 else
625 layerFound = true;
626 }
627
628 if( !layerFound )
629 return -1;
630
631 return layerStackupId;
632}
633
634
636{
637 const wxString zStr = m_targetImpedance->GetValue();
638
639 double z;
640 if( !zStr.ToDouble( &z ) )
641 z = -1;
642
643 return z;
644}
645
646
648 const std::vector<BOARD_STACKUP_ITEM*>& aStackupLayerList, const std::vector<int>& dielectricLayerStackupIds,
649 const EDA_IU_SCALE& aIuScale )
650{
651 double e_r = 0.0;
652 double lossTangent = 0.0;
653 double totalHeight = 0.0;
654
655 for( int i : dielectricLayerStackupIds )
656 {
657 const BOARD_STACKUP_ITEM* layer = aStackupLayerList.at( i );
658 totalHeight += aIuScale.IUTomm( layer->GetThickness() ) / 1000.0;
659 }
660
661 for( int i : dielectricLayerStackupIds )
662 {
663 const BOARD_STACKUP_ITEM* layer = aStackupLayerList.at( i );
664 e_r += layer->GetEpsilonR() * aIuScale.IUTomm( layer->GetThickness() ) / ( 1000.0 * totalHeight );
665 lossTangent += layer->GetLossTangent() * aIuScale.IUTomm( layer->GetThickness() ) / ( 1000.0 * totalHeight );
666 }
667
668 return { e_r, lossTangent };
669}
670
671
672void PANEL_SETUP_TUNING_PROFILE_INFO::getDielectricDetails( const std::vector<BOARD_STACKUP_ITEM*>& aStackupLayerList,
673 const int aSignalLayerId, const int aReferenceLayerId,
674 std::vector<int>& aDielectricLayerStackupIds,
675 double& aDielectricLayerHeight )
676{
677 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
678 aDielectricLayerHeight = 0.0;
679
680 for( int i = std::min( aSignalLayerId, aReferenceLayerId ) + 1; i < std::max( aSignalLayerId, aReferenceLayerId );
681 ++i )
682 {
683 const BOARD_STACKUP_ITEM* layer = aStackupLayerList.at( i );
684
685 if( layer->GetType() != BS_ITEM_TYPE_DIELECTRIC )
686 continue;
687
688 if( !layer->HasEpsilonRValue() )
689 continue;
690
691 aDielectricLayerStackupIds.push_back( i );
692 aDielectricLayerHeight += iuScale.IUTomm( aStackupLayerList.at( i )->GetThickness() ) / 1000.0;
693 }
694}
695
696
698{
699 // Determine if this is a stripline or microstrip geometry
700 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
701
702 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
703 return;
704
705 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs.at( signalLayerName );
706 const TUNING_PROFILE::PROFILE_TYPE profileType = m_type->GetSelection() == 0
709 const bool isMicrostrip = IsFrontLayer( signalLayer ) || IsBackLayer( signalLayer );
710 CalculationType calculationType;
711
712 switch( aCol )
713 {
714 case TRACK_GRID_TRACK_WIDTH: calculationType = CalculationType::WIDTH; break;
715 case TRACK_GRID_TRACK_GAP: calculationType = CalculationType::GAP; break;
716 case TRACK_GRID_DELAY: calculationType = CalculationType::DELAY; break;
717 default: calculationType = CalculationType::WIDTH; break;
718 }
719
720 if( profileType == TUNING_PROFILE::PROFILE_TYPE::DIFFERENTIAL ) // Differential tracks mode
721 {
722 int calculatedWidth = 0;
723 int calculatedGap = 0;
724 int calculatedDelay = 0;
725
726 std::tuple<int, int, int> result;
727
728 if( isMicrostrip )
729 result = calculateDifferentialMicrostrip( aRow, calculationType );
730 else
731 result = calculateDifferentialStripline( aRow, calculationType );
732
733 calculatedWidth = std::get<0>( result );
734 calculatedGap = std::get<1>( result );
735 calculatedDelay = std::get<2>( result );
736
737 const bool widthOk = calculatedWidth > 0;
738 const bool gapOk = calculatedGap > 0;
739 const bool delayOk = calculatedDelay > 0;
740
741 if( !widthOk )
742 {
743 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track width" ) );
744 return;
745 }
746 else if( !gapOk )
747 {
748 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute differential pair gap" ) );
749 return;
750 }
751 else if( !delayOk )
752 {
753 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track propagation delay" ) );
754 return;
755 }
756
757 if( calculationType == CalculationType::WIDTH )
758 {
759 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH, calculatedWidth );
760 }
761 else if( calculationType == CalculationType::GAP )
762 {
763 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_GAP, calculatedGap );
764 }
765
766 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_DELAY, calculatedDelay );
767 }
768 else // Single track mode
769 {
770 int calculatedWidth = 0;
771 int calculatedDelay = 0;
772
773 std::pair<int, int> result;
774
775 if( isMicrostrip )
776 result = calculateSingleMicrostrip( aRow, calculationType );
777 else
778 result = calculateSingleStripline( aRow, calculationType );
779
780 calculatedWidth = result.first;
781 calculatedDelay = result.second;
782
783 const bool widthOk = calculatedWidth > 0;
784 const bool delayOk = calculatedDelay > 0;
785
786 if( !widthOk )
787 {
788 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track width" ) );
789 return;
790 }
791 else if( !delayOk )
792 {
793 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track propagation delay" ) );
794 return;
795 }
796
797 if( calculationType == CalculationType::WIDTH )
798 {
799 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH, calculatedWidth );
800 }
801
802 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_DELAY, calculatedDelay );
803 }
804}
805
806
808{
809 if( m_name->GetValue() == wxEmptyString )
810 {
811 m_parentPanel->m_tuningProfiles->SetSelection( aPageIndex );
812
813 const wxString msg = _( "Tuning profile must have a name" );
815 return false;
816 }
817
818 std::set<wxString> layerNames;
819
820 for( int i = 0; i < m_trackPropagationGrid->GetNumberRows(); ++i )
821 {
822 const wxString& layerName = m_trackPropagationGrid->GetCellValue( i, TRACK_GRID_SIGNAL_LAYER );
823
824 if( layerNames.contains( layerName ) )
825 {
826 m_parentPanel->m_tuningProfiles->SetSelection( aPageIndex );
827
828 const wxString msg = _( "Duplicated signal layer configuration in tuning profile" );
831 return false;
832 }
833
834 layerNames.insert( layerName );
835 }
836
837 return true;
838}
839
840
841/*****************************************************************************************************************
842 * SIMULATION / ANALYSIS PLUMBING
843 ****************************************************************************************************************/
844
846 CalculationType aCalculationType )
847{
848 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
849
850 // Get the target impedance
851 const double targetZ = getTargetImpedance();
852
853 if( targetZ <= 0 )
854 return { 0, 0 };
855
856 // Get the signal layer information from the stackup
857 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
858 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
859
860 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
861
862 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
863 return { 0, 0 };
864
865 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
866
867 // Microstrip can only be on an outer copper layer
868 if( signalLayer != F_Cu && signalLayer != B_Cu )
869 return { 0, 0 };
870
871 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
872
873 if( signalLayerStackupId == -1 )
874 return { 0, 0 };
875
876 const double signalLayerThickness =
877 iuScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
878
879 // Get reference layer
880 wxString referenceLayerName;
881
882 if( signalLayer == F_Cu )
883 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
884 else
885 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
886
887 if( !m_parentPanel->m_layerNamesToIDs.contains( referenceLayerName ) )
888 return { 0, 0 };
889
890 const PCB_LAYER_ID referenceLayer = m_parentPanel->m_layerNamesToIDs[referenceLayerName];
891 const int referenceLayerStackupId = getStackupLayerId( stackupLayerList, referenceLayer );
892
893 if( signalLayerStackupId == referenceLayerStackupId )
894 return { 0, 0 };
895
896 // Get the dielectric layers between signal and reference layers
897 std::vector<int> dielectricLayerStackupIds;
898 double dielectricLayerHeight = 0;
899 getDielectricDetails( stackupLayerList, signalLayerStackupId, referenceLayerStackupId, dielectricLayerStackupIds,
900 dielectricLayerHeight );
901
902 if( dielectricLayerHeight <= 0.0 )
903 return { 0, 0 };
904
905 // Calculate geometric average of the dielectric materials
906 const auto [e_r, tan_d] =
907 calculateAverageDielectricConstants( stackupLayerList, dielectricLayerStackupIds, iuScale );
908
909 if( aCalculationType == CalculationType::WIDTH )
910 {
912 }
913 else if( aCalculationType == CalculationType::DELAY )
914 {
915 const int widthInt = m_trackPropagationGrid->GetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
916
917 const double width = iuScale.IUTomm( widthInt ) / 1000.0;
919 }
920
921 // Run the synthesis or analysis
922 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, 1.0 / RHO );
926 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::H_T, 1e+20 );
927 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::H, dielectricLayerHeight );
928 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::T, signalLayerThickness );
929 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0, targetZ );
930 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
932 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, tan_d );
937
938 if( aCalculationType == CalculationType::WIDTH )
940 else
941 m_microstripCalc.Analyse();
942
943 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
944 [this, aCalculationType]() -> decltype( m_microstripCalc.GetSynthesisResults() )
945 {
946 if( aCalculationType == CalculationType::WIDTH )
947 return m_microstripCalc.GetSynthesisResults();
948
949 return m_microstripCalc.GetAnalysisResults();
950 }();
951
953 return { 0, 0 };
954
956 return { 0, 0 };
957
958 int width = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
959 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
960 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
962
963 return { width, propDelay };
964}
965
966
968 CalculationType aCalculationType )
969{
970 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
971
972 // Get the target impedance
973 const double targetZ = getTargetImpedance();
974
975 if( targetZ <= 0 )
976 return { 0, 0 };
977
978 // Get the signal layer information from the stackup
979 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
980 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
981
982 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
983
984 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
985 return { 0, 0 };
986
987 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
988 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
989
990 if( signalLayerStackupId == -1 )
991 return { 0, 0 };
992
993 const double signalLayerThickness =
994 iuScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
995
996 // Get top reference layer
997 const wxString topReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
998
999 if( !m_parentPanel->m_layerNamesToIDs.contains( topReferenceLayerName ) )
1000 return { 0, 0 };
1001
1002 const PCB_LAYER_ID topReferenceLayer = m_parentPanel->m_layerNamesToIDs[topReferenceLayerName];
1003 const int topReferenceLayerStackupId = getStackupLayerId( stackupLayerList, topReferenceLayer );
1004
1005 if( !IsCopperLayerLowerThan( signalLayer, topReferenceLayer ) )
1006 return { 0, 0 };
1007
1008 // Get bottom reference layer
1009 wxString bottomReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
1010
1011 if( !m_parentPanel->m_layerNamesToIDs.contains( bottomReferenceLayerName ) )
1012 return { 0, 0 };
1013
1014 const PCB_LAYER_ID bottomReferenceLayer = m_parentPanel->m_layerNamesToIDs[bottomReferenceLayerName];
1015 const int bottomReferenceLayerStackupId = getStackupLayerId( stackupLayerList, bottomReferenceLayer );
1016
1017 if( !IsCopperLayerLowerThan( bottomReferenceLayer, signalLayer ) )
1018 return { 0, 0 };
1019
1020 // Get the dielectric layers between signal and reference layers
1021 std::vector<int> topDielectricLayerStackupIds, bottomDielectricLayerStackupIds;
1022 double topDielectricLayerHeight = 0.0;
1023 double bottomDielectricLayerHeight = 0.0;
1024
1025 getDielectricDetails( stackupLayerList, signalLayerStackupId, topReferenceLayerStackupId,
1026 topDielectricLayerStackupIds, topDielectricLayerHeight );
1027 getDielectricDetails( stackupLayerList, signalLayerStackupId, bottomReferenceLayerStackupId,
1028 bottomDielectricLayerStackupIds, bottomDielectricLayerHeight );
1029
1030 if( topDielectricLayerHeight <= 0.0 || bottomDielectricLayerHeight <= 0.0 )
1031 return { 0, 0 };
1032
1033 // Calculate geometric average of the dielectric materials
1034 std::vector<int> allDielectricLayerStackupIds( topDielectricLayerStackupIds );
1035 allDielectricLayerStackupIds.insert( allDielectricLayerStackupIds.end(), bottomDielectricLayerStackupIds.begin(),
1036 bottomDielectricLayerStackupIds.end() );
1037 const auto [e_r, tan_d] =
1038 calculateAverageDielectricConstants( stackupLayerList, allDielectricLayerStackupIds, iuScale );
1039
1040 if( aCalculationType == CalculationType::WIDTH )
1041 {
1043 }
1044 else if( aCalculationType == CalculationType::DELAY )
1045 {
1046 const int widthInt = m_trackPropagationGrid->GetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1047
1048 const double width = iuScale.IUTomm( widthInt ) / 1000.0;
1050 }
1051
1052 // Run the synthesis
1053 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, calculateSkinDepth( 1.0, 1.0, 1.0 / RHO ) );
1055 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, signalLayerThickness );
1056 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::STRIPLINE_A, topDielectricLayerHeight );
1058 topDielectricLayerHeight + signalLayerThickness + bottomDielectricLayerHeight );
1059 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0, targetZ );
1061 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1062 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, tan_d );
1063 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, 1.0 );
1064 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, 1.0 / RHO );
1066
1067 if( aCalculationType == CalculationType::WIDTH )
1069 else
1070 m_striplineCalc.Analyse();
1071
1072 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1073 [this, aCalculationType]() -> decltype( m_striplineCalc.GetSynthesisResults() )
1074 {
1075 if( aCalculationType == CalculationType::WIDTH )
1076 return m_striplineCalc.GetSynthesisResults();
1077
1078 return m_striplineCalc.GetAnalysisResults();
1079 }();
1080
1082 return { 0, 0 };
1083
1085 return { 0, 0 };
1086
1087 int width = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1088 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1089 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1091
1092 return { width, propDelay };
1093}
1094
1095
1096std::tuple<int, int, int>
1098{
1099 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1100
1101 // Get the target impedance
1102 const double targetZ = getTargetImpedance();
1103
1104 if( targetZ <= 0 )
1105 return { 0, 0, 0 };
1106
1107 // Get the signal layer information from the stackup
1108 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
1109 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
1110
1111 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
1112
1113 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
1114 return { 0, 0, 0 };
1115
1116 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
1117
1118 // Microstrip can only be on an outer copper layer
1119 if( signalLayer != F_Cu && signalLayer != B_Cu )
1120 return { 0, 0, 0 };
1121
1122 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
1123
1124 if( signalLayerStackupId == -1 )
1125 return { 0, 0, 0 };
1126
1127 const double signalLayerThickness =
1128 iuScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
1129
1130 // Get reference layer
1131 wxString referenceLayerName;
1132
1133 if( signalLayer == F_Cu )
1134 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
1135 else
1136 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
1137
1138 if( !m_parentPanel->m_layerNamesToIDs.contains( referenceLayerName ) )
1139 return { 0, 0, 0 };
1140
1141 const PCB_LAYER_ID referenceLayer = m_parentPanel->m_layerNamesToIDs[referenceLayerName];
1142 const int referenceLayerStackupId = getStackupLayerId( stackupLayerList, referenceLayer );
1143
1144 if( signalLayerStackupId == referenceLayerStackupId )
1145 return { 0, 0, 0 };
1146
1147 // Get the dielectric layers between signal and reference layers
1148 std::vector<int> dielectricLayerStackupIds;
1149 double dielectricLayerHeight = 0;
1150 getDielectricDetails( stackupLayerList, signalLayerStackupId, referenceLayerStackupId, dielectricLayerStackupIds,
1151 dielectricLayerHeight );
1152
1153 if( dielectricLayerHeight <= 0.0 )
1154 return { 0, 0, 0 };
1155
1156 // Calculate geometric average of the dielectric materials
1157 const auto [e_r, tan_d] =
1158 calculateAverageDielectricConstants( stackupLayerList, dielectricLayerStackupIds, iuScale );
1159
1160 // Get tuning parameters
1161 double width = 0.0;
1162 double gap = 0.0;
1163
1164 const std::optional<int> widthOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1165 const std::optional<int> gapOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_GAP );
1166
1167 if( aCalculationType == CalculationType::WIDTH )
1168 {
1169 if( !gapOpt )
1170 return { 0, 0, 0 };
1171
1172 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1173 }
1174 else if( aCalculationType == CalculationType::GAP )
1175 {
1176 if( !widthOpt )
1177 return { 0, 0, 0 };
1178
1179 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1180 }
1181 else if( aCalculationType == CalculationType::DELAY )
1182 {
1183 if( !widthOpt || !gapOpt )
1184 return { 0, 0, 0 };
1185
1186 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1187 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1188 }
1189
1190 // Run the synthesis
1191 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, targetZ / 2.0 );
1192 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, targetZ / 2.0 );
1198 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::H, dielectricLayerHeight );
1199 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::T, signalLayerThickness );
1201 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1208
1209 switch( aCalculationType )
1210 {
1213 case CalculationType::DELAY: m_coupledMicrostripCalc.Analyse(); break;
1214 }
1215
1216 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1217 [this, aCalculationType]() -> decltype( m_microstripCalc.GetSynthesisResults() )
1218 {
1219 if( aCalculationType == CalculationType::WIDTH || aCalculationType == CalculationType::GAP )
1220 return m_coupledMicrostripCalc.GetSynthesisResults();
1221
1222 return m_coupledMicrostripCalc.GetAnalysisResults();
1223 }();
1224
1226 return { 0, 0, 0 };
1227
1228 if( results[TRANSLINE_PARAMETERS::PHYS_S].second != TRANSLINE_STATUS::OK )
1229 return { 0, 0, 0 };
1230
1232 return { 0, 0, 0 };
1233
1234 int calcWidth = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1235 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1236 int calcGap = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1237 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_S].first * 1000.0 ) );
1238 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1240
1241 return { calcWidth, calcGap, propDelay };
1242}
1243
1244
1245std::tuple<int, int, int>
1247{
1248 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1249
1250 // Get the target impedance
1251 const double targetZ = getTargetImpedance();
1252
1253 if( targetZ <= 0 )
1254 return { 0, 0, 0 };
1255
1256 // Get the signal layer information from the stackup
1257 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
1258 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
1259
1260 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
1261
1262 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
1263 return { 0, 0, 0 };
1264
1265 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
1266 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
1267
1268 if( signalLayerStackupId == -1 )
1269 return { 0, 0, 0 };
1270
1271 const double signalLayerThickness =
1272 iuScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
1273
1274 // Get top reference layer
1275 const wxString topReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
1276
1277 if( !m_parentPanel->m_layerNamesToIDs.contains( topReferenceLayerName ) )
1278 return { 0, 0, 0 };
1279
1280 const PCB_LAYER_ID topReferenceLayer = m_parentPanel->m_layerNamesToIDs[topReferenceLayerName];
1281 const int topReferenceLayerStackupId = getStackupLayerId( stackupLayerList, topReferenceLayer );
1282
1283 if( !IsCopperLayerLowerThan( signalLayer, topReferenceLayer ) )
1284 return { 0, 0, 0 };
1285
1286 // Get bottom reference layer
1287 wxString bottomReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
1288
1289 if( !m_parentPanel->m_layerNamesToIDs.contains( bottomReferenceLayerName ) )
1290 return { 0, 0, 0 };
1291
1292 const PCB_LAYER_ID bottomReferenceLayer = m_parentPanel->m_layerNamesToIDs[bottomReferenceLayerName];
1293 const int bottomReferenceLayerStackupId = getStackupLayerId( stackupLayerList, bottomReferenceLayer );
1294
1295 if( !IsCopperLayerLowerThan( bottomReferenceLayer, signalLayer ) )
1296 return { 0, 0, 0 };
1297
1298 // Get the dielectric layers between signal and reference layers
1299 std::vector<int> topDielectricLayerStackupIds, bottomDielectricLayerStackupIds;
1300 double topDielectricLayerHeight = 0.0;
1301 double bottomDielectricLayerHeight = 0.0;
1302
1303 getDielectricDetails( stackupLayerList, signalLayerStackupId, topReferenceLayerStackupId,
1304 topDielectricLayerStackupIds, topDielectricLayerHeight );
1305 getDielectricDetails( stackupLayerList, signalLayerStackupId, bottomReferenceLayerStackupId,
1306 bottomDielectricLayerStackupIds, bottomDielectricLayerHeight );
1307
1308 if( topDielectricLayerHeight <= 0.0 || bottomDielectricLayerHeight <= 0.0 )
1309 return { 0, 0, 0 };
1310
1311 // Calculate geometric average of the dielectric materials
1312 std::vector<int> allDielectricLayerStackupIds( topDielectricLayerStackupIds );
1313 allDielectricLayerStackupIds.insert( allDielectricLayerStackupIds.end(), bottomDielectricLayerStackupIds.begin(),
1314 bottomDielectricLayerStackupIds.end() );
1315 const auto [e_r, tan_d] =
1316 calculateAverageDielectricConstants( stackupLayerList, allDielectricLayerStackupIds, iuScale );
1317
1318 // Get tuning parameters
1319 double width = 0.0;
1320 double gap = 0.0;
1321
1322 const std::optional<int> widthOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1323 const std::optional<int> gapOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_GAP );
1324
1325 if( aCalculationType == CalculationType::WIDTH )
1326 {
1327 if( !gapOpt )
1328 return { 0, 0, 0 };
1329
1330 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1331 }
1332 else if( aCalculationType == CalculationType::GAP )
1333 {
1334 if( !widthOpt )
1335 return { 0, 0, 0 };
1336
1337 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1338 }
1339 else if( aCalculationType == CalculationType::DELAY )
1340 {
1341 if( !widthOpt || !gapOpt )
1342 return { 0, 0, 0 };
1343
1344 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1345 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1346 }
1347
1348 // Run the synthesis
1349 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, targetZ / 2.0 );
1350 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, targetZ / 2.0 );
1354 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, signalLayerThickness );
1355 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::H, topDielectricLayerHeight + signalLayerThickness
1356 + bottomDielectricLayerHeight );
1360 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1364
1365 switch( aCalculationType )
1366 {
1369 case CalculationType::DELAY: m_coupledStriplineCalc.Analyse(); break;
1370 }
1371
1372 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1373 [this, aCalculationType]() -> decltype( m_coupledStriplineCalc.GetSynthesisResults() )
1374 {
1375 if( aCalculationType == CalculationType::WIDTH || aCalculationType == CalculationType::GAP )
1376 return m_coupledStriplineCalc.GetSynthesisResults();
1377
1378 return m_coupledStriplineCalc.GetAnalysisResults();
1379 }();
1380
1382 return { 0, 0, 0 };
1383
1384 if( results[TRANSLINE_PARAMETERS::PHYS_S].second != TRANSLINE_STATUS::OK )
1385 return { 0, 0, 0 };
1386
1388 return { 0, 0, 0 };
1389
1390 int calcWidth = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1391 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1392 int calcGap = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1393 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_S].first * 1000.0 ) );
1394 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1396
1397 return { calcWidth, calcGap, propDelay };
1398}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
@ BS_ITEM_TYPE_DIELECTRIC
Manage one layer needed to make a physical board.
double GetEpsilonR(int aDielectricSubLayer=0) const
bool HasEpsilonRValue() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:692
Represents a single line in a time domain profile track propagation setup.
void SetWidth(const int aWidth)
void SetEnableTimeDomainTuning(bool aEnable)
void SetDiffPairGap(const int aDiffPairGap)
void SetTopReferenceLayer(const PCB_LAYER_ID aLayer)
void SetSignalLayer(const PCB_LAYER_ID aLayer)
void SetDelay(const int aDelay)
void SetBottomReferenceLayer(const PCB_LAYER_ID aLayer)
PCB_LAYER_ID GetSignalLayer() const
A cell editor which runs a provided function when the grid cell button is clicked.
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
static PAGED_DIALOG * GetDialog(wxWindow *aWindow)
void SetError(const wxString &aMessage, const wxString &aPageName, int aCtrlId, int aRow=-1, int aCol=-1)
PANEL_SETUP_TUNING_PROFILE_INFO_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(719, 506), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
std::tuple< int, int, int > calculateDifferentialStripline(int aRow, CalculationType aCalculationType)
Calculates the track width, pair gap, or delay for the given propagation grid row.
void OnAddViaOverride(wxCommandEvent &event) override
Adds a via override row.
void getDielectricDetails(const std::vector< BOARD_STACKUP_ITEM * > &aStackupLayerList, int aSignalLayerId, int aReferenceLayerId, std::vector< int > &aDielectricLayerStackupIds, double &aDielectricLayerHeight)
Gets the dielectric layers and heights for dielectrics between the two given copper layer IDs.
MICROSTRIP m_microstripCalc
Calculator for single microstrip parameters.
COUPLED_STRIPLINE m_coupledStriplineCalc
Calculator for coupled (differential) stripline parameters.
void initPanel()
Initialises all controls on the panel.
void calculateTrackParametersForCell(int aRow, int aCol)
Calculates the required track parameters for the given track parameters grid row and col.
double getTargetImpedance() const
Gets the target impedance for the profile.
STRIPLINE m_striplineCalc
Calculator for single stripline parameters.
static double calculateSkinDepth(double aFreq, double aMurc, double aSigma)
Calculate the effective skin depth for the given parameters.
bool ValidateProfile(size_t aPageIndex)
Validate this panel's data.
void UpdateLayerNames()
Updates the displayed layer names in all grids.
std::pair< int, int > calculateSingleMicrostrip(const int aRow, CalculationType aCalculationType)
Calculates the track width or delay for the given propagation grid row.
std::tuple< int, int, int > calculateDifferentialMicrostrip(int aRow, CalculationType aCalculationType)
Calculates the track width, pair gap, or delay for the given propagation grid row.
static int getStackupLayerId(const std::vector< BOARD_STACKUP_ITEM * > &aLayerList, PCB_LAYER_ID aPcbLayerId)
Gets the index in to the layer list for the given layer.
UNIT_BINDER m_viaPropagationUnits
Units for global via propagation unit delay.
PANEL_SETUP_TUNING_PROFILE_INFO(wxWindow *aParentWindow, PANEL_SETUP_TUNING_PROFILES *parentPanel)
void LoadProfile(const TUNING_PROFILE &aProfile)
Loads the given profile in to the panel.
TUNING_PROFILE GetProfile() const
Saves the panel to the given profile.
PANEL_SETUP_TUNING_PROFILES * m_parentPanel
The parent setup panel.
void OnChangeProfileType(wxCommandEvent &event) override
Changes between Single and Differential profiles.
void OnRemoveTrackRow(wxCommandEvent &event) override
Removes a row from the track propagation grid.
wxString GetProfileName() const
Gets the name of this profile.
std::pair< int, int > calculateSingleStripline(const int aRow, CalculationType aCalculationType)
Calculates the track width or delay for the given propagation grid row.
static std::pair< double, double > calculateAverageDielectricConstants(const std::vector< BOARD_STACKUP_ITEM * > &aStackupLayerList, const std::vector< int > &dielectricLayerStackupIds, const EDA_IU_SCALE &aIuScale)
Calculates the geometric average of the dielectric material properties.
COUPLED_MICROSTRIP m_coupledMicrostripCalc
Calculator for coupled (differential) microstrip parameters.
void onChangeProfileType(TUNING_PROFILE::PROFILE_TYPE aType) const
Sets the panel display for the given tuning type.
void OnRemoveViaOverride(wxCommandEvent &event) override
Removes a via override row.
void OnAddTrackRow(wxCommandEvent &event) override
Adds a row to the track propagation grid.
void setColumnWidths()
Set up the widths of all grid columns.
void OnProfileNameChanged(wxCommandEvent &event) override
Updates the parent notebook control.
EDA_UNITS GetUnitsFromType(EDA_DATA_TYPE aType) const
Gets the units to use in the conversion based on the underlying user units.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
This file is part of the common library.
#define _(s)
@ PS_PER_INCH
Definition eda_units.h:59
bool IsCopperLayerLowerThan(PCB_LAYER_ID aLayerA, PCB_LAYER_ID aLayerB)
Return true if copper aLayerA is placed lower than aLayerB, false otherwise.
Definition layer_ids.h:823
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:779
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:802
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ B_Cu
Definition layer_ids.h:65
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:64
KICOMMON_API double FromUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Return in internal units the value aValue given in a real unit such as "in", "mm",...
KICOMMON_API bool IsImperialUnit(EDA_UNITS aUnit)
Definition eda_units.cpp:47
Represents a single line in the time domain configuration via overrides configuration grid.
constexpr double IUTomm(int iu) const
Definition base_units.h:90
Represents a single line in the tuning profile configuration grid.
bool m_GenerateNetClassDRCRules
std::map< PCB_LAYER_ID, DELAY_PROFILE_TRACK_PROPAGATION_ENTRY > m_TrackPropagationEntriesMap
std::vector< DELAY_PROFILE_VIA_OVERRIDE_ENTRY > m_ViaOverrides
PROFILE_TYPE m_Type
std::vector< DELAY_PROFILE_TRACK_PROPAGATION_ENTRY > m_TrackPropagationEntries
wxString result
Test unit parsing edge cases and error handling.
#define M_PI