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
59
60 int x = 0, y = 0;
61 m_name->GetTextExtent( "XXXXXXXXXXXXXXXXXXXXX", &x, &y );
62 m_name->SetMinSize( wxSize( x, -1 ) );
63 m_targetImpedance->GetTextExtent( "XXXXXXXXX", &x, &y );
64 m_targetImpedance->SetMinSize( wxSize( x, -1 ) );
65
66 m_viaPropagationUnits.SetValue( 0 );
67
70
73
74 m_targetImpedance->SetValue( "0" );
75
76 UNITS_PROVIDER* unitsProvider = m_parentPanel->m_unitsProvider.get();
77
78 m_trackPropagationGrid->SetUnitsProvider( unitsProvider );
79 m_viaOverrides->SetUnitsProvider( unitsProvider );
80
81 // Configure the track grid
82 m_trackPropagationGrid->BeginBatch();
83 m_trackPropagationGrid->SetUseNativeColLabels();
84
85 m_trackPropagationGrid->EnsureColLabelsVisible();
87 m_trackPropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
88
89 std::vector<int> trackColIds;
90 m_trackPropagationGrid->SetAutoEvalColUnits( TRACK_GRID_DELAY,
92 trackColIds.push_back( TRACK_GRID_DELAY );
94 unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::DISTANCE ) );
95 trackColIds.push_back( TRACK_GRID_TRACK_WIDTH );
96 m_trackPropagationGrid->SetAutoEvalColUnits( TRACK_GRID_TRACK_GAP,
97 unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::DISTANCE ) );
98 trackColIds.push_back( TRACK_GRID_TRACK_GAP );
99 m_trackPropagationGrid->SetAutoEvalCols( trackColIds );
100
101 // Add the calculation editors
102 wxGridCellAttr* attr = new wxGridCellAttr;
103 attr->SetEditor( new GRID_CELL_RUN_FUNCTION_EDITOR(
104 m_parentPanel->m_dlg,
105 [this]( int row, int col )
106 {
107 calculateTrackParametersForCell( row, col );
108 },
109 false ) );
111
112 attr = new wxGridCellAttr;
113 attr->SetEditor( new GRID_CELL_RUN_FUNCTION_EDITOR(
114 m_parentPanel->m_dlg,
115 [this]( int row, int col )
116 {
117 calculateTrackParametersForCell( row, col );
118 },
119 false ) );
120 m_trackPropagationGrid->SetColAttr( TRACK_GRID_TRACK_GAP, attr );
121
122 attr = new wxGridCellAttr;
123 attr->SetEditor( new GRID_CELL_RUN_FUNCTION_EDITOR(
124 m_parentPanel->m_dlg,
125 [this]( int row, int col )
126 {
127 calculateTrackParametersForCell( row, col );
128 },
129 false ) );
130 m_trackPropagationGrid->SetColAttr( TRACK_GRID_DELAY, attr );
131
132 m_trackPropagationGrid->EndBatch();
133
134 // Configure the via grid
135 m_viaOverrides->BeginBatch();
136 m_viaOverrides->SetUseNativeColLabels();
137
138 m_viaOverrides->EnsureColLabelsVisible();
139 m_viaOverrides->PushEventHandler( new GRID_TRICKS( m_viaOverrides ) );
140 m_viaOverrides->SetSelectionMode( wxGrid::wxGridSelectRows );
141
142 std::vector<int> viaColIds;
143 m_viaOverrides->SetAutoEvalColUnits( VIA_GRID_DELAY, unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::TIME ) );
144 viaColIds.push_back( VIA_GRID_DELAY );
145 m_viaOverrides->SetAutoEvalCols( viaColIds );
146 m_viaOverrides->EndBatch();
147
149
150 // Hide the trace gap as we start in single mode
152
154 Layout();
155}
156
157
159{
160 BOARD* board = m_parentPanel->m_board;
161
162 m_name->SetValue( aProfile.m_ProfileName );
163 m_type->SetSelection( static_cast<int>( aProfile.m_Type ) );
164 onChangeProfileType( aProfile.m_Type );
165 m_targetImpedance->SetValue( wxString::FromDouble( aProfile.m_TargetImpedance ) );
167 m_enableDelayTuning->SetValue( aProfile.m_EnableTimeDomainTuning );
168 m_viaPropagationUnits.SetValue( aProfile.m_ViaPropagationDelay );
169
170 for( const auto& entry : aProfile.m_TrackPropagationEntries )
171 {
172 const int row = m_trackPropagationGrid->GetNumberRows();
173 m_trackPropagationGrid->AppendRows();
174
176 board->GetLayerName( entry.GetSignalLayer() ) );
177
178 if( entry.GetTopReferenceLayer() != UNDEFINED_LAYER )
179 {
181 board->GetLayerName( entry.GetTopReferenceLayer() ) );
182 }
183
184 if( entry.GetBottomReferenceLayer() != UNDEFINED_LAYER )
185 {
187 board->GetLayerName( entry.GetBottomReferenceLayer() ) );
188 }
189
190 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_TRACK_WIDTH, entry.GetWidth() );
191 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_TRACK_GAP, entry.GetDiffPairGap() );
192 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_DELAY, entry.GetDelay( true ) );
193 }
194
195 for( const auto& entry : aProfile.m_ViaOverrides )
196 {
197 const int row = m_viaOverrides->GetNumberRows();
198 m_viaOverrides->AppendRows();
199
200 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, board->GetLayerName( entry.m_SignalLayerFrom ) );
201 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, board->GetLayerName( entry.m_SignalLayerTo ) );
202 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, board->GetLayerName( entry.m_ViaLayerFrom ) );
203 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, board->GetLayerName( entry.m_ViaLayerTo ) );
204 m_viaOverrides->SetUnitValue( row, VIA_GRID_DELAY, entry.m_Delay );
205 }
206
208}
209
210
212{
213 TUNING_PROFILE profile;
214 profile.m_ProfileName = m_name->GetValue();
215 profile.m_Type = static_cast<TUNING_PROFILE::PROFILE_TYPE>( m_type->GetSelection() );
217 profile.m_EnableTimeDomainTuning = m_enableDelayTuning->GetValue();
218 profile.m_ViaPropagationDelay = m_viaPropagationUnits.GetIntValue();
219
220 double targetImpedance;
221
222 if( m_targetImpedance->GetValue().ToDouble( &targetImpedance ) )
223 profile.m_TargetImpedance = targetImpedance;
224 else
225 profile.m_TargetImpedance = 0.0;
226
227 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); row++ )
228 {
230
231 wxString signalLayerName = m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_SIGNAL_LAYER );
232 entry.SetSignalLayer( m_parentPanel->m_layerNamesToIDs[signalLayerName] );
233
234 if( wxString topReferenceLayerName = m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_TOP_REFERENCE );
235 m_parentPanel->m_layerNamesToIDs.contains( topReferenceLayerName ) )
236 {
237 entry.SetTopReferenceLayer( m_parentPanel->m_layerNamesToIDs[topReferenceLayerName] );
238 }
239 else
240 {
242 }
243
244 if( wxString bottomReferenceLayerName =
246 m_parentPanel->m_layerNamesToIDs.contains( bottomReferenceLayerName ) )
247 {
248 entry.SetBottomReferenceLayer( m_parentPanel->m_layerNamesToIDs[bottomReferenceLayerName] );
249 }
250 else
251 {
253 }
254
255 entry.SetWidth( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_TRACK_WIDTH ) );
256 entry.SetDiffPairGap( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_TRACK_GAP ) );
257 entry.SetDelay( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_DELAY ) );
259
260 profile.m_TrackPropagationEntries.push_back( entry );
261 profile.m_TrackPropagationEntriesMap[entry.GetSignalLayer()] = entry;
262 }
263
264 for( int row = 0; row < m_viaOverrides->GetNumberRows(); row++ )
265 {
266 const wxString signalLayerFrom = m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM );
267 const wxString signalLayerTo = m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO );
268 const wxString viaLayerFrom = m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM );
269 const wxString viaLayerTo = m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_TO );
270 PCB_LAYER_ID signalLayerIdFrom = m_parentPanel->m_layerNamesToIDs[signalLayerFrom];
271 PCB_LAYER_ID signalLayerIdTo = m_parentPanel->m_layerNamesToIDs[signalLayerTo];
272 PCB_LAYER_ID viaLayerIdFrom = m_parentPanel->m_layerNamesToIDs[viaLayerFrom];
273 PCB_LAYER_ID viaLayerIdTo = m_parentPanel->m_layerNamesToIDs[viaLayerTo];
274
275 // Order layers in stackup order (from F_Cu first)
276 if( IsCopperLayerLowerThan( signalLayerIdFrom, signalLayerIdTo ) )
277 std::swap( signalLayerIdFrom, signalLayerIdTo );
278
279 if( IsCopperLayerLowerThan( viaLayerIdFrom, viaLayerIdTo ) )
280 std::swap( viaLayerIdFrom, viaLayerIdTo );
281
282 const DELAY_PROFILE_VIA_OVERRIDE_ENTRY entry{ signalLayerIdFrom, signalLayerIdTo, viaLayerIdFrom, viaLayerIdTo,
283 m_viaOverrides->GetUnitValue( row, VIA_GRID_DELAY ) };
284 profile.m_ViaOverrides.push_back( entry );
285 }
286
287 return profile;
288}
289
290
292{
293 m_trackPropagationGrid->PopEventHandler( true );
294 m_viaOverrides->PopEventHandler( true );
295}
296
297
299{
300 wxArrayString layerNames, layerNamesWithNone;
301 layerNamesWithNone.push_back( "<None>" );
302 std::ranges::for_each( m_parentPanel->m_layerNames,
303 [&layerNames, &layerNamesWithNone]( const wxString& aLayerName )
304 {
305 layerNames.push_back( aLayerName );
306 layerNamesWithNone.push_back( aLayerName );
307 } );
308
309
310 // Save the current data - track grid
311 std::vector<wxString> currentSignalLayer;
312 std::vector<wxString> currentTopReferenceLayer;
313 std::vector<wxString> currentBottomReferenceLayer;
314
315 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); ++row )
316 {
317 currentSignalLayer.emplace_back( m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_SIGNAL_LAYER ) );
318 currentTopReferenceLayer.emplace_back( m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_TOP_REFERENCE ) );
319 currentBottomReferenceLayer.emplace_back(
321 }
322
323 // Save the current data - via grid
324 std::vector<wxString> currentSignalLayersFrom;
325 std::vector<wxString> currentSignalLayersTo;
326 std::vector<wxString> currentViaLayersFrom;
327 std::vector<wxString> currentViaLayersTo;
328
329 for( int row = 0; row < m_viaOverrides->GetNumberRows(); ++row )
330 {
331 currentSignalLayersFrom.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM ) );
332 currentSignalLayersTo.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO ) );
333 currentViaLayersFrom.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM ) );
334 currentViaLayersTo.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_TO ) );
335 }
336
337 // Reset the via layers lists
338 wxGridCellAttr* attr = new wxGridCellAttr;
339 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
341
342 attr = new wxGridCellAttr;
343 attr->SetEditor( new wxGridCellChoiceEditor( layerNamesWithNone, false ) );
345
346 attr = new wxGridCellAttr;
347 attr->SetEditor( new wxGridCellChoiceEditor( layerNamesWithNone, false ) );
349
350 attr = new wxGridCellAttr;
351 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
352 m_viaOverrides->SetColAttr( VIA_GRID_SIGNAL_LAYER_FROM, attr );
353
354 attr = new wxGridCellAttr;
355 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
356 m_viaOverrides->SetColAttr( VIA_GRID_SIGNAL_LAYER_TO, attr );
357
358 attr = new wxGridCellAttr;
359 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
360 m_viaOverrides->SetColAttr( VIA_GRID_VIA_LAYER_FROM, attr );
361
362 attr = new wxGridCellAttr;
363 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
364 m_viaOverrides->SetColAttr( VIA_GRID_VIA_LAYER_TO, attr );
365
366 // Restore the data, changing or resetting layer names if required
367 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); ++row )
368 {
369 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentSignalLayer[row] ) )
370 {
371 PCB_LAYER_ID lastSignalId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayer[row]];
372
373 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalId ) )
375 m_parentPanel->m_board->GetLayerName( lastSignalId ) );
376 else
378 m_parentPanel->m_layerNames.front() );
379 }
380 else
381 {
382 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_SIGNAL_LAYER, m_parentPanel->m_layerNames.front() );
383 }
384
385 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentTopReferenceLayer[row] ) )
386 {
387 const PCB_LAYER_ID lastTopReferenceId = m_parentPanel->m_prevLayerNamesToIDs[currentTopReferenceLayer[row]];
388
389 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastTopReferenceId ) )
391 m_parentPanel->m_board->GetLayerName( lastTopReferenceId ) );
392 else
393 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_TOP_REFERENCE, layerNamesWithNone[0] );
394 }
395 else
396 {
397 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_TOP_REFERENCE, layerNamesWithNone[0] );
398 }
399
400 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentBottomReferenceLayer[row] ) )
401 {
402 const PCB_LAYER_ID lastBottomReferenceId =
403 m_parentPanel->m_prevLayerNamesToIDs[currentBottomReferenceLayer[row]];
404
405 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastBottomReferenceId ) )
407 m_parentPanel->m_board->GetLayerName( lastBottomReferenceId ) );
408 else
409 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, layerNamesWithNone[0] );
410 }
411 else
412 {
413 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, layerNamesWithNone[0] );
414 }
415 }
416
417 for( int row = 0; row < m_viaOverrides->GetNumberRows(); ++row )
418 {
419 const PCB_LAYER_ID lastSignalFromId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayersFrom[row]];
420
421 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalFromId ) )
422 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM,
423 m_parentPanel->m_board->GetLayerName( lastSignalFromId ) );
424 else
425 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_parentPanel->m_layerNames.front() );
426
427 const PCB_LAYER_ID lastSignalToId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayersTo[row]];
428
429 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalToId ) )
430 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO,
431 m_parentPanel->m_board->GetLayerName( lastSignalToId ) );
432 else
433 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_parentPanel->m_layerNames.back() );
434
435 const PCB_LAYER_ID lastViaFromId = m_parentPanel->m_prevLayerNamesToIDs[currentViaLayersFrom[row]];
436
437 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastViaFromId ) )
438 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM,
439 m_parentPanel->m_board->GetLayerName( lastViaFromId ) );
440 else
441 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_parentPanel->m_layerNames.front() );
442
443 const PCB_LAYER_ID lastViaToId = m_parentPanel->m_prevLayerNamesToIDs[currentViaLayersTo[row]];
444
445 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastViaToId ) )
446 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO,
447 m_parentPanel->m_board->GetLayerName( lastViaToId ) );
448 else
449 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_parentPanel->m_layerNames.back() );
450 }
451}
452
453
455{
456 const int minValueWidth = m_trackPropagationGrid->GetTextExtent( wxT( "000.0000 ps/mm" ) ).x;
457
458 for( int i = 0; i < m_trackPropagationGrid->GetNumberCols(); ++i )
459 {
460 const int titleSize = m_trackPropagationGrid->GetTextExtent( m_trackPropagationGrid->GetColLabelValue( i ) ).x;
461
463 m_trackPropagationGrid->SetColSize( i, titleSize + 30 );
464 else
465 m_trackPropagationGrid->SetColSize( i, std::max( titleSize, minValueWidth ) );
466 }
467
468 for( int i = 0; i < m_viaOverrides->GetNumberCols(); ++i )
469 {
470 const int titleSize = GetTextExtent( m_viaOverrides->GetColLabelValue( i ) ).x;
471 if( i == VIA_GRID_DELAY )
472 m_viaOverrides->SetColSize( i, std::max( titleSize, minValueWidth ) );
473 else
474 m_viaOverrides->SetColSize( i, titleSize + 30 );
475 }
476
477 const int impedanceWidth = m_targetImpedance->GetTextExtent( wxT( "0000.00" ) ).x;
478 m_targetImpedance->SetSize( impedanceWidth, m_targetImpedance->GetSize().GetHeight() );
479
480 Layout();
481}
482
483
485{
486 const wxString newName = event.GetString();
487 m_parentPanel->UpdateProfileName( this, newName );
488}
489
490
498
499
501{
502 m_trackPropagationGrid->CommitPendingChanges();
503 m_viaOverrides->CommitPendingChanges();
504
507 else
509}
510
511
513{
514 const int numRows = m_trackPropagationGrid->GetNumberRows();
515 m_trackPropagationGrid->InsertRows( m_trackPropagationGrid->GetNumberRows() );
516
517 auto setFrontRowLayers = [&]( const int row )
518 {
519 auto nameItr = m_parentPanel->m_layerNames.begin();
520
521 if( nameItr == m_parentPanel->m_layerNames.end() )
522 return;
523
524 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_SIGNAL_LAYER, *nameItr );
525
526 ++nameItr;
527
528 if( nameItr == m_parentPanel->m_layerNames.end() )
529 return;
530
531 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, *nameItr );
532 };
533
534 auto setRowLayers = [&]()
535 {
536 if( numRows == 0 )
537 {
538 setFrontRowLayers( 0 );
539 return;
540 }
541
542 const wxString lastSignalLayerName =
543 m_trackPropagationGrid->GetCellValue( numRows - 1, TRACK_GRID_SIGNAL_LAYER );
544 auto nameItr = std::find( m_parentPanel->m_layerNames.begin(), m_parentPanel->m_layerNames.end(),
545 lastSignalLayerName );
546
547 if( nameItr == m_parentPanel->m_layerNames.end() )
548 return;
549
550 if( nameItr == m_parentPanel->m_layerNames.end() - 1 )
551 {
552 setFrontRowLayers( numRows );
553 return;
554 }
555
556 ++nameItr;
557
558 if( nameItr == m_parentPanel->m_layerNames.end() )
559 return;
560
561 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_SIGNAL_LAYER, *nameItr );
562 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_TOP_REFERENCE, *( nameItr - 1 ) );
563
564 ++nameItr;
565
566 if( nameItr != m_parentPanel->m_layerNames.end() )
567 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_BOTTOM_REFERENCE, *nameItr );
568 };
569
570 setRowLayers();
571
572 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_TRACK_WIDTH, 0 );
573 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_TRACK_GAP, 0 );
574 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_DELAY, 0 );
576}
577
578
580{
581 wxArrayInt selRows = m_trackPropagationGrid->GetSelectedRows();
582
583 if( selRows.size() == 1 )
584 m_trackPropagationGrid->DeleteRows( selRows[0] );
585}
586
587
589{
590 const int numRows = m_viaOverrides->GetNumberRows();
591 m_viaOverrides->InsertRows( numRows );
592 m_viaOverrides->SetUnitValue( numRows, VIA_GRID_DELAY, 0 );
593 m_viaOverrides->SetCellValue( numRows, VIA_GRID_SIGNAL_LAYER_FROM, m_parentPanel->m_layerNames.front() );
594 m_viaOverrides->SetCellValue( numRows, VIA_GRID_SIGNAL_LAYER_TO, m_parentPanel->m_layerNames.back() );
595 m_viaOverrides->SetCellValue( numRows, VIA_GRID_VIA_LAYER_FROM, m_parentPanel->m_layerNames.front() );
596 m_viaOverrides->SetCellValue( numRows, VIA_GRID_VIA_LAYER_TO, m_parentPanel->m_layerNames.back() );
598}
599
600
602{
603 wxArrayInt selRows = m_viaOverrides->GetSelectedRows();
604
605 if( selRows.size() == 1 )
606 m_viaOverrides->DeleteRows( selRows[0] );
607}
608
609
611{
612 return m_name->GetValue();
613}
614
615
616double PANEL_SETUP_TUNING_PROFILE_INFO::calculateSkinDepth( const double aFreq, const double aMurc,
617 const double aSigma )
618{
619 return 1.0 / sqrt( M_PI * aFreq * aMurc * TRANSLINE_CALCULATIONS::MU0 * aSigma );
620}
621
622
623int PANEL_SETUP_TUNING_PROFILE_INFO::getStackupLayerId( const std::vector<BOARD_STACKUP_ITEM*>& aLayerList,
624 PCB_LAYER_ID aPcbLayerId )
625{
626 bool layerFound = false;
627 int layerStackupId = 0;
628
629 while( layerStackupId < static_cast<int>( aLayerList.size() ) && !layerFound )
630 {
631 if( aLayerList.at( layerStackupId )->GetBrdLayerId() != aPcbLayerId )
632 ++layerStackupId;
633 else
634 layerFound = true;
635 }
636
637 if( !layerFound )
638 return -1;
639
640 return layerStackupId;
641}
642
643
645{
646 const wxString zStr = m_targetImpedance->GetValue();
647
648 double z;
649 if( !zStr.ToDouble( &z ) )
650 z = -1;
651
652 return z;
653}
654
655
657 const std::vector<BOARD_STACKUP_ITEM*>& aStackupLayerList, const std::vector<int>& dielectricLayerStackupIds,
658 const EDA_IU_SCALE& aIuScale )
659{
660 double totalHeight = 0.0;
661 double e_r = 0.0;
662 double lossTangent = 0.0;
663
664 for( int i : dielectricLayerStackupIds )
665 {
666 const BOARD_STACKUP_ITEM* layer = aStackupLayerList.at( i );
667
668 for( int subLayerIdx = 0; subLayerIdx < layer->GetSublayersCount(); ++subLayerIdx )
669 {
670 totalHeight += aIuScale.IUTomm( layer->GetThickness( subLayerIdx ) );
671 e_r += layer->GetEpsilonR( subLayerIdx ) * aIuScale.IUTomm( layer->GetThickness( subLayerIdx ) );
672 lossTangent += layer->GetLossTangent( subLayerIdx ) * aIuScale.IUTomm( layer->GetThickness( subLayerIdx ) );
673 }
674 }
675
676 e_r = e_r / totalHeight;
677 lossTangent = lossTangent / totalHeight;
678 totalHeight /= 1000.0; // Convert from mm to m
679
680 return { totalHeight, e_r, lossTangent };
681}
682
683
684void PANEL_SETUP_TUNING_PROFILE_INFO::getDielectricLayers( const std::vector<BOARD_STACKUP_ITEM*>& aStackupLayerList,
685 const int aSignalLayerId, const int aReferenceLayerId,
686 std::vector<int>& aDielectricLayerStackupIds )
687{
688 for( int i = std::min( aSignalLayerId, aReferenceLayerId ) + 1; i < std::max( aSignalLayerId, aReferenceLayerId );
689 ++i )
690 {
691 const BOARD_STACKUP_ITEM* layer = aStackupLayerList.at( i );
692
693 if( layer->GetType() != BS_ITEM_TYPE_DIELECTRIC )
694 continue;
695
696 if( !layer->HasEpsilonRValue() )
697 continue;
698
699 aDielectricLayerStackupIds.push_back( i );
700 }
701}
702
703
705{
706 // Determine if this is a stripline or microstrip geometry
707 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
708
709 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
710 return;
711
712 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs.at( signalLayerName );
713 const TUNING_PROFILE::PROFILE_TYPE profileType = m_type->GetSelection() == 0
716 const bool isMicrostrip = IsFrontLayer( signalLayer ) || IsBackLayer( signalLayer );
717 CalculationType calculationType;
718
719 switch( aCol )
720 {
721 case TRACK_GRID_TRACK_WIDTH: calculationType = CalculationType::WIDTH; break;
722 case TRACK_GRID_TRACK_GAP: calculationType = CalculationType::GAP; break;
723 case TRACK_GRID_DELAY: calculationType = CalculationType::DELAY; break;
724 default: calculationType = CalculationType::WIDTH; break;
725 }
726
727 if( profileType == TUNING_PROFILE::PROFILE_TYPE::DIFFERENTIAL ) // Differential tracks mode
728 {
729 int calculatedWidth = 0;
730 int calculatedGap = 0;
731 int calculatedDelay = 0;
732
734
735 if( isMicrostrip )
736 result = calculateDifferentialMicrostrip( aRow, calculationType );
737 else
738 result = calculateDifferentialStripline( aRow, calculationType );
739
740 if( !result.OK )
741 {
742 DisplayErrorMessage( m_parentPanel->m_dlg, wxString::Format( _( "Error: %s" ), result.ErrorMsg ) );
743 return;
744 }
745
746 calculatedWidth = result.Width;
747 calculatedGap = result.DiffPairGap;
748 calculatedDelay = result.Delay;
749
750 const bool widthOk = calculatedWidth > 0;
751 const bool gapOk = calculatedGap > 0;
752 const bool delayOk = calculatedDelay > 0;
753
754 if( !widthOk )
755 {
756 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track width" ) );
757 return;
758 }
759 else if( !gapOk )
760 {
761 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute differential pair gap" ) );
762 return;
763 }
764 else if( !delayOk )
765 {
766 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track propagation delay" ) );
767 return;
768 }
769
770 if( calculationType == CalculationType::WIDTH )
771 {
772 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH, calculatedWidth );
773 }
774 else if( calculationType == CalculationType::GAP )
775 {
776 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_GAP, calculatedGap );
777 }
778
779 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_DELAY, calculatedDelay );
780 }
781 else // Single track mode
782 {
783 int calculatedWidth = 0;
784 int calculatedDelay = 0;
785
787
788 if( isMicrostrip )
789 result = calculateSingleMicrostrip( aRow, calculationType );
790 else
791 result = calculateSingleStripline( aRow, calculationType );
792
793 if( !result.OK )
794 {
795 DisplayErrorMessage( m_parentPanel->m_dlg, wxString::Format( _( "Error: %s" ), result.ErrorMsg ) );
796 return;
797 }
798
799 calculatedWidth = result.Width;
800 calculatedDelay = result.Delay;
801
802 const bool widthOk = calculatedWidth > 0;
803 const bool delayOk = calculatedDelay > 0;
804
805 if( !widthOk )
806 {
807 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track width" ) );
808 return;
809 }
810 else if( !delayOk )
811 {
812 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track propagation delay" ) );
813 return;
814 }
815
816 if( calculationType == CalculationType::WIDTH )
817 {
818 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH, calculatedWidth );
819 }
820
821 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_DELAY, calculatedDelay );
822 }
823}
824
825
827{
828 if( m_name->GetValue() == wxEmptyString )
829 {
830 m_parentPanel->m_tuningProfiles->SetSelection( aPageIndex );
831
832 const wxString msg = _( "Tuning profile must have a name" );
834 return false;
835 }
836
837 std::set<wxString> layerNames;
838
839 for( int i = 0; i < m_trackPropagationGrid->GetNumberRows(); ++i )
840 {
841 const wxString& layerName = m_trackPropagationGrid->GetCellValue( i, TRACK_GRID_SIGNAL_LAYER );
842
843 if( layerNames.contains( layerName ) )
844 {
845 m_parentPanel->m_tuningProfiles->SetSelection( aPageIndex );
846
847 const wxString msg = _( "Duplicated signal layer configuration in tuning profile" );
850 return false;
851 }
852
853 layerNames.insert( layerName );
854 }
855
856 return true;
857}
858
859
860/*****************************************************************************************************************
861 * SIMULATION / ANALYSIS PLUMBING
862 ****************************************************************************************************************/
863
867{
868 // Get the signal layer information from the stackup
869 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
870 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
871
872 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
873
874 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
875 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
876
877 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
878
879 // Microstrip can only be on an outer copper layer
880 if( signalLayer != F_Cu && signalLayer != B_Cu )
881 return { {}, CALCULATION_RESULT{ _( "Internal error: Microstrip can only be on an outer copper layer" ) } };
882
883 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
884
885 if( signalLayerStackupId == -1 )
886 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
887
888 const double signalLayerThickness =
889 aScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
890
891 if( signalLayerThickness <= 0 )
892 return { {}, CALCULATION_RESULT{ _( "Signal layer thickness must be greater than 0" ) } };
893
894 // Get reference layer
895 wxString referenceLayerName;
896
897 if( signalLayer == F_Cu )
898 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
899 else
900 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
901
902 if( !m_parentPanel->m_layerNamesToIDs.contains( referenceLayerName ) )
903 return { {}, CALCULATION_RESULT{ _( "Reference layer not found in stackup" ) } };
904
905 const PCB_LAYER_ID referenceLayer = m_parentPanel->m_layerNamesToIDs[referenceLayerName];
906 const int referenceLayerStackupId = getStackupLayerId( stackupLayerList, referenceLayer );
907
908 if( signalLayerStackupId == referenceLayerStackupId )
909 return { {}, CALCULATION_RESULT{ _( "Reference layer must be different to signal layer" ) } };
910
911 // Get the dielectric layers between signal and reference layers
912 std::vector<int> dielectricLayerStackupIds;
913 getDielectricLayers( stackupLayerList, signalLayerStackupId, referenceLayerStackupId, dielectricLayerStackupIds );
914
915 // Calculate geometric average of the dielectric materials
916 const DIELECTRIC_INFO dielectricInfo =
917 calculateAverageDielectricConstants( stackupLayerList, dielectricLayerStackupIds, aScale );
918
919 if( dielectricInfo.Height <= 0.0 )
920 return { {}, CALCULATION_RESULT{ _( "Dielectric height must be greater than 0" ) } };
921
922 CALCULATION_BOARD_PARAMETERS boardParameters{ dielectricInfo.E_r, dielectricInfo.Height, 0.0, signalLayerThickness,
923 dielectricInfo.Loss_Tangent };
925 result.OK = true;
926
927 return { boardParameters, result };
928}
929
930
934{
935 // Get the signal layer information from the stackup
936 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
937 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
938
939 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
940
941 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
942 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
943
944 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
945 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
946
947 if( signalLayerStackupId == -1 )
948 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
949
950 const double signalLayerThickness =
951 aScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
952
953 if( signalLayerThickness <= 0 )
954 return { {}, CALCULATION_RESULT{ _( "Signal layer thickness must be greater than 0" ) } };
955
956 // Get top reference layer
957 const wxString topReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
958
959 if( !m_parentPanel->m_layerNamesToIDs.contains( topReferenceLayerName ) )
960 return { {}, CALCULATION_RESULT{ _( "Top reference layer not found in stackup" ) } };
961
962 const PCB_LAYER_ID topReferenceLayer = m_parentPanel->m_layerNamesToIDs[topReferenceLayerName];
963 const int topReferenceLayerStackupId = getStackupLayerId( stackupLayerList, topReferenceLayer );
964
965 if( !IsCopperLayerLowerThan( signalLayer, topReferenceLayer ) )
966 return { {}, CALCULATION_RESULT{ _( "Top reference layer must be above signal layer in board stackup" ) } };
967
968 // Get bottom reference layer
969 wxString bottomReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
970
971 if( !m_parentPanel->m_layerNamesToIDs.contains( bottomReferenceLayerName ) )
972 return { {}, CALCULATION_RESULT{ _( "Bottom reference layer not found in stackup" ) } };
973
974 const PCB_LAYER_ID bottomReferenceLayer = m_parentPanel->m_layerNamesToIDs[bottomReferenceLayerName];
975 const int bottomReferenceLayerStackupId = getStackupLayerId( stackupLayerList, bottomReferenceLayer );
976
977 if( !IsCopperLayerLowerThan( bottomReferenceLayer, signalLayer ) )
978 return { {}, CALCULATION_RESULT{ _( "Bottom reference layer must be below signal layer in board stackup" ) } };
979
980 // Get the dielectric layers between signal and reference layers
981 std::vector<int> topDielectricLayerStackupIds, bottomDielectricLayerStackupIds;
982
983 getDielectricLayers( stackupLayerList, signalLayerStackupId, topReferenceLayerStackupId,
984 topDielectricLayerStackupIds );
985 getDielectricLayers( stackupLayerList, signalLayerStackupId, bottomReferenceLayerStackupId,
986 bottomDielectricLayerStackupIds );
987
988 // Calculate geometric average of the dielectric materials
989 std::vector<int> allDielectricLayerStackupIds( topDielectricLayerStackupIds );
990 allDielectricLayerStackupIds.insert( allDielectricLayerStackupIds.end(), bottomDielectricLayerStackupIds.begin(),
991 bottomDielectricLayerStackupIds.end() );
992
993 const DIELECTRIC_INFO topDielectricInfo =
994 calculateAverageDielectricConstants( stackupLayerList, topDielectricLayerStackupIds, aScale );
995 const DIELECTRIC_INFO bottomDielectricInfo =
996 calculateAverageDielectricConstants( stackupLayerList, bottomDielectricLayerStackupIds, aScale );
997 const DIELECTRIC_INFO allDielectricInfo =
998 calculateAverageDielectricConstants( stackupLayerList, allDielectricLayerStackupIds, aScale );
999
1000 if( topDielectricInfo.Height <= 0.0 && bottomDielectricInfo.Height <= 0.0 )
1001 return { {}, CALCULATION_RESULT{ _( "Dielectric heights must be greater than 0" ) } };
1002
1003 CALCULATION_BOARD_PARAMETERS boardParameters{ allDielectricInfo.E_r, topDielectricInfo.Height,
1004 bottomDielectricInfo.Height, signalLayerThickness,
1005 allDielectricInfo.Loss_Tangent };
1007 result.OK = true;
1008
1009 return { boardParameters, result };
1010}
1011
1012
1015{
1016 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1017
1018 // Get the target impedance
1019 const double targetZ = getTargetImpedance();
1020
1021 if( targetZ <= 0 )
1022 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1023
1024 // Get board parameters
1025 auto [boardParameters, result] = getMicrostripBoardParameters( aRow, iuScale );
1026
1027 if( !result.OK )
1028 return result;
1029
1030 // Set calculation parameters
1031 if( aCalculationType == CalculationType::WIDTH )
1032 {
1034 }
1035 else if( aCalculationType == CalculationType::DELAY )
1036 {
1037 const int widthInt = m_trackPropagationGrid->GetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1038
1039 const double width = iuScale.IUTomm( widthInt ) / 1000.0;
1041 }
1042
1043 // Run the synthesis or analysis
1044 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, 1.0 / RHO );
1046 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, calculateSkinDepth( 1.0, 1.0, 1.0 / RHO ) );
1047 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1048 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::H_T, 1e+20 );
1049 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness );
1050 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1051 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0, targetZ );
1052 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1054 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, boardParameters.LossTangent );
1059
1060 if( aCalculationType == CalculationType::WIDTH )
1062 else
1063 m_microstripCalc.Analyse();
1064
1065 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1066 [this, aCalculationType]() -> decltype( m_microstripCalc.GetSynthesisResults() )
1067 {
1068 if( aCalculationType == CalculationType::WIDTH )
1069 return m_microstripCalc.GetSynthesisResults();
1070
1071 return m_microstripCalc.GetAnalysisResults();
1072 }();
1073
1075 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1076
1078 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1079
1080 int width = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1081 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1082 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1084
1085 return CALCULATION_RESULT{ width, propDelay };
1086}
1087
1088
1091{
1092 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1093
1094 // Get the target impedance
1095 const double targetZ = getTargetImpedance();
1096
1097 if( targetZ <= 0 )
1098 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1099
1100 // Get board parameters
1101 auto [boardParameters, result] = getStriplineBoardParameters( aRow, iuScale );
1102
1103 if( !result.OK )
1104 return result;
1105
1106 // Set calculation parameters
1107 if( aCalculationType == CalculationType::WIDTH )
1108 {
1110 }
1111 else if( aCalculationType == CalculationType::DELAY )
1112 {
1113 const int widthInt = m_trackPropagationGrid->GetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1114
1115 const double width = iuScale.IUTomm( widthInt ) / 1000.0;
1117 }
1118
1119 // Run the synthesis
1120 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, calculateSkinDepth( 1.0, 1.0, 1.0 / RHO ) );
1121 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1122 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1123 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::STRIPLINE_A, boardParameters.TopDielectricLayerThickness );
1124 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness
1125 + boardParameters.SignalLayerThickness
1126 + boardParameters.BottomDielectricLayerThickness );
1127 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0, targetZ );
1129 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1130 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, boardParameters.LossTangent );
1131 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, 1.0 );
1132 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, 1.0 / RHO );
1134
1135 if( aCalculationType == CalculationType::WIDTH )
1137 else
1138 m_striplineCalc.Analyse();
1139
1140 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1141 [this, aCalculationType]() -> decltype( m_striplineCalc.GetSynthesisResults() )
1142 {
1143 if( aCalculationType == CalculationType::WIDTH )
1144 return m_striplineCalc.GetSynthesisResults();
1145
1146 return m_striplineCalc.GetAnalysisResults();
1147 }();
1148
1150 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1151
1153 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1154
1155 int width = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1156 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1157 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1159
1160 return CALCULATION_RESULT{ width, propDelay };
1161}
1162
1163
1166{
1167 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1168
1169 // Get the target impedance
1170 const double targetZ = getTargetImpedance();
1171
1172 if( targetZ <= 0 )
1173 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1174
1175 // Get board parameters
1176 auto [boardParameters, result] = getMicrostripBoardParameters( aRow, iuScale );
1177
1178 if( !result.OK )
1179 return result;
1180
1181 // Set calculation parameters
1182 double width = 0.0;
1183 double gap = 0.0;
1184
1185 const std::optional<int> widthOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1186 const std::optional<int> gapOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_GAP );
1187
1188 if( aCalculationType == CalculationType::WIDTH )
1189 {
1190 if( !gapOpt || *gapOpt <= 0 )
1191 return CALCULATION_RESULT{ _( "Diff pair gap must be greater than 0 to calculate width" ) };
1192
1193 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1194 }
1195 else if( aCalculationType == CalculationType::GAP )
1196 {
1197 if( !widthOpt || *widthOpt <= 0 )
1198 return CALCULATION_RESULT{ _( "Width must be greater than 0 to calculate diff pair gap" ) };
1199
1200 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1201 }
1202 else if( aCalculationType == CalculationType::DELAY )
1203 {
1204 if( !widthOpt || !gapOpt || *widthOpt <= 0 || *gapOpt <= 0 )
1205 return CALCULATION_RESULT{ _( "Width and diff pair gap must be greater than 0 to calculate delay" ) };
1206
1207 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1208 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1209 }
1210
1211 // Run the synthesis
1212 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, targetZ / 2.0 );
1213 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, targetZ / 2.0 );
1217 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1219 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness );
1220 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1222 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1227 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, boardParameters.LossTangent );
1229
1230 switch( aCalculationType )
1231 {
1234 case CalculationType::DELAY: m_coupledMicrostripCalc.Analyse(); break;
1235 }
1236
1237 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1238 [this, aCalculationType]() -> decltype( m_microstripCalc.GetSynthesisResults() )
1239 {
1240 if( aCalculationType == CalculationType::WIDTH || aCalculationType == CalculationType::GAP )
1241 return m_coupledMicrostripCalc.GetSynthesisResults();
1242
1243 return m_coupledMicrostripCalc.GetAnalysisResults();
1244 }();
1245
1247 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1248
1249 if( results[TRANSLINE_PARAMETERS::PHYS_S].second != TRANSLINE_STATUS::OK )
1250 return CALCULATION_RESULT{ _( "Diff pair gap calculation failed" ) };
1251
1253 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1254
1255 int calcWidth = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1256 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1257 int calcGap = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1258 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_S].first * 1000.0 ) );
1259 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1261
1262 return CALCULATION_RESULT{ calcWidth, calcGap, propDelay };
1263}
1264
1265
1268{
1269 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1270
1271 // Get the target impedance
1272 const double targetZ = getTargetImpedance();
1273
1274 if( targetZ <= 0 )
1275 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1276
1277 // Get board parameters
1278 auto [boardParameters, result] = getStriplineBoardParameters( aRow, iuScale );
1279
1280 if( !result.OK )
1281 return result;
1282
1283 // Set calculation parameters
1284 double width = 0.0;
1285 double gap = 0.0;
1286
1287 const std::optional<int> widthOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1288 const std::optional<int> gapOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_GAP );
1289
1290 if( aCalculationType == CalculationType::WIDTH )
1291 {
1292 if( !gapOpt || *gapOpt <= 0 )
1293 return CALCULATION_RESULT{ _( "Diff pair gap must be greater than 0 to calculate width" ) };
1294
1295 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1296 }
1297 else if( aCalculationType == CalculationType::GAP )
1298 {
1299 if( !widthOpt || *widthOpt <= 0 )
1300 return CALCULATION_RESULT{ _( "Width must be greater than 0 to calculate diff pair gap" ) };
1301
1302 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1303 }
1304 else if( aCalculationType == CalculationType::DELAY )
1305 {
1306 if( !widthOpt || !gapOpt || *widthOpt <= 0 || *gapOpt <= 0 )
1307 return CALCULATION_RESULT{ _( "Width and diff pair gap must be greater than 0 to calculate delay" ) };
1308
1309 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1310 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1311 }
1312
1313 // Run the synthesis
1314 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, targetZ / 2.0 );
1315 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, targetZ / 2.0 );
1319 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1320 m_coupledStriplineCalc.SetParameter(
1321 TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness + boardParameters.SignalLayerThickness
1322 + boardParameters.BottomDielectricLayerThickness );
1323 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1326 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1330
1331 switch( aCalculationType )
1332 {
1335 case CalculationType::DELAY: m_coupledStriplineCalc.Analyse(); break;
1336 }
1337
1338 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1339 [this, aCalculationType]() -> decltype( m_coupledStriplineCalc.GetSynthesisResults() )
1340 {
1341 if( aCalculationType == CalculationType::WIDTH || aCalculationType == CalculationType::GAP )
1342 return m_coupledStriplineCalc.GetSynthesisResults();
1343
1344 return m_coupledStriplineCalc.GetAnalysisResults();
1345 }();
1346
1348 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1349
1350 if( results[TRANSLINE_PARAMETERS::PHYS_S].second != TRANSLINE_STATUS::OK )
1351 return CALCULATION_RESULT{ _( "Diff pair gap calculation failed" ) };
1352
1354 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1355
1356 int calcWidth = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1357 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1358 int calcGap = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1359 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_S].first * 1000.0 ) );
1360 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1362
1363 return CALCULATION_RESULT{ calcWidth, calcGap, propDelay };
1364}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
@ BS_ITEM_TYPE_DIELECTRIC
Manage one layer needed to make a physical board.
int GetSublayersCount() const
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:695
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)
void OnAddViaOverride(wxCommandEvent &event) override
Adds a via override row.
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.
CALCULATION_RESULT calculateSingleStripline(const int aRow, CalculationType aCalculationType)
Calculates the track width or delay for the given propagation grid row.
double getTargetImpedance() const
Gets the target impedance for the profile.
CALCULATION_RESULT calculateSingleMicrostrip(const int aRow, CalculationType aCalculationType)
Calculates the track width or delay for the given propagation grid row.
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.
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.
CALCULATION_RESULT calculateDifferentialMicrostrip(int aRow, CalculationType aCalculationType)
Calculates the track width, pair gap, or delay for the given propagation grid row.
std::pair< CALCULATION_BOARD_PARAMETERS, CALCULATION_RESULT > getMicrostripBoardParameters(int aRow, const EDA_IU_SCALE &aScale)
Gets the board parameters for microstrip calculations @parameter aRow The grid row to calculate board...
PANEL_SETUP_TUNING_PROFILE_INFO(wxWindow *aParentWindow, PANEL_SETUP_TUNING_PROFILES *parentPanel)
static DIELECTRIC_INFO 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.
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.
std::pair< CALCULATION_BOARD_PARAMETERS, CALCULATION_RESULT > getStriplineBoardParameters(int aRow, const EDA_IU_SCALE &aScale)
Gets the board parameters for stripline calculations @parameter aRow The grid row to calculate board ...
void getDielectricLayers(const std::vector< BOARD_STACKUP_ITEM * > &aStackupLayerList, int aSignalLayerId, int aReferenceLayerId, std::vector< int > &aDielectricLayerStackupIds)
Gets the dielectric layers for dielectrics between the two given copper layer IDs.
void OnRemoveTrackRow(wxCommandEvent &event) override
Removes a row from the track propagation grid.
wxString GetProfileName() const
Gets the name of this profile.
COUPLED_MICROSTRIP m_coupledMicrostripCalc
Calculator for coupled (differential) microstrip parameters.
CALCULATION_RESULT calculateDifferentialStripline(int aRow, CalculationType aCalculationType)
Calculates the track width, pair gap, or delay for the given propagation grid row.
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:202
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:824
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:780
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:803
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