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 ) );
166 m_enableDelayTuning->SetValue( aProfile.m_EnableTimeDomainTuning );
167 m_viaPropagationUnits.SetValue( aProfile.m_ViaPropagationDelay );
168
169 for( const auto& entry : aProfile.m_TrackPropagationEntries )
170 {
171 const int row = m_trackPropagationGrid->GetNumberRows();
172 m_trackPropagationGrid->AppendRows();
173
175 board->GetLayerName( entry.GetSignalLayer() ) );
176
177 if( entry.GetTopReferenceLayer() != UNDEFINED_LAYER )
178 {
180 board->GetLayerName( entry.GetTopReferenceLayer() ) );
181 }
182
183 if( entry.GetBottomReferenceLayer() != UNDEFINED_LAYER )
184 {
186 board->GetLayerName( entry.GetBottomReferenceLayer() ) );
187 }
188
189 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_TRACK_WIDTH, entry.GetWidth() );
190 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_TRACK_GAP, entry.GetDiffPairGap() );
191 m_trackPropagationGrid->SetUnitValue( row, TRACK_GRID_DELAY, entry.GetDelay( true ) );
192 }
193
194 for( const auto& entry : aProfile.m_ViaOverrides )
195 {
196 const int row = m_viaOverrides->GetNumberRows();
197 m_viaOverrides->AppendRows();
198
199 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, board->GetLayerName( entry.m_SignalLayerFrom ) );
200 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, board->GetLayerName( entry.m_SignalLayerTo ) );
201 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, board->GetLayerName( entry.m_ViaLayerFrom ) );
202 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, board->GetLayerName( entry.m_ViaLayerTo ) );
203 m_viaOverrides->SetUnitValue( row, VIA_GRID_DELAY, entry.m_Delay );
204 }
205
207}
208
209
211{
212 TUNING_PROFILE profile;
213 profile.m_ProfileName = m_name->GetValue();
214 profile.m_Type = static_cast<TUNING_PROFILE::PROFILE_TYPE>( m_type->GetSelection() );
215 profile.m_EnableTimeDomainTuning = m_enableDelayTuning->GetValue();
216 profile.m_ViaPropagationDelay = m_viaPropagationUnits.GetIntValue();
217
218 double targetImpedance;
219
220 if( m_targetImpedance->GetValue().ToDouble( &targetImpedance ) )
221 profile.m_TargetImpedance = targetImpedance;
222 else
223 profile.m_TargetImpedance = 0.0;
224
225 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); row++ )
226 {
228
229 wxString signalLayerName = m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_SIGNAL_LAYER );
230 entry.SetSignalLayer( m_parentPanel->m_layerNamesToIDs[signalLayerName] );
231
232 if( wxString topReferenceLayerName = m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_TOP_REFERENCE );
233 m_parentPanel->m_layerNamesToIDs.contains( topReferenceLayerName ) )
234 {
235 entry.SetTopReferenceLayer( m_parentPanel->m_layerNamesToIDs[topReferenceLayerName] );
236 }
237 else
238 {
240 }
241
242 if( wxString bottomReferenceLayerName =
244 m_parentPanel->m_layerNamesToIDs.contains( bottomReferenceLayerName ) )
245 {
246 entry.SetBottomReferenceLayer( m_parentPanel->m_layerNamesToIDs[bottomReferenceLayerName] );
247 }
248 else
249 {
251 }
252
253 entry.SetWidth( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_TRACK_WIDTH ) );
254 entry.SetDiffPairGap( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_TRACK_GAP ) );
255 entry.SetDelay( m_trackPropagationGrid->GetUnitValue( row, TRACK_GRID_DELAY ) );
257
258 profile.m_TrackPropagationEntries.push_back( entry );
259 profile.m_TrackPropagationEntriesMap[entry.GetSignalLayer()] = entry;
260 }
261
262 for( int row = 0; row < m_viaOverrides->GetNumberRows(); row++ )
263 {
264 const wxString signalLayerFrom = m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM );
265 const wxString signalLayerTo = m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO );
266 const wxString viaLayerFrom = m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM );
267 const wxString viaLayerTo = m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_TO );
268 PCB_LAYER_ID signalLayerIdFrom = m_parentPanel->m_layerNamesToIDs[signalLayerFrom];
269 PCB_LAYER_ID signalLayerIdTo = m_parentPanel->m_layerNamesToIDs[signalLayerTo];
270 PCB_LAYER_ID viaLayerIdFrom = m_parentPanel->m_layerNamesToIDs[viaLayerFrom];
271 PCB_LAYER_ID viaLayerIdTo = m_parentPanel->m_layerNamesToIDs[viaLayerTo];
272
273 // Order layers in stackup order (from F_Cu first)
274 if( IsCopperLayerLowerThan( signalLayerIdFrom, signalLayerIdTo ) )
275 std::swap( signalLayerIdFrom, signalLayerIdTo );
276
277 if( IsCopperLayerLowerThan( viaLayerIdFrom, viaLayerIdTo ) )
278 std::swap( viaLayerIdFrom, viaLayerIdTo );
279
280 const DELAY_PROFILE_VIA_OVERRIDE_ENTRY entry{ signalLayerIdFrom, signalLayerIdTo, viaLayerIdFrom, viaLayerIdTo,
281 m_viaOverrides->GetUnitValue( row, VIA_GRID_DELAY ) };
282 profile.m_ViaOverrides.push_back( entry );
283 }
284
285 return profile;
286}
287
288
290{
291 m_trackPropagationGrid->PopEventHandler( true );
292 m_viaOverrides->PopEventHandler( true );
293}
294
295
297{
298 wxArrayString layerNames, layerNamesWithNone;
299 layerNamesWithNone.push_back( "<None>" );
300 std::ranges::for_each( m_parentPanel->m_layerNames,
301 [&layerNames, &layerNamesWithNone]( const wxString& aLayerName )
302 {
303 layerNames.push_back( aLayerName );
304 layerNamesWithNone.push_back( aLayerName );
305 } );
306
307
308 // Save the current data - track grid
309 std::vector<wxString> currentSignalLayer;
310 std::vector<wxString> currentTopReferenceLayer;
311 std::vector<wxString> currentBottomReferenceLayer;
312
313 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); ++row )
314 {
315 currentSignalLayer.emplace_back( m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_SIGNAL_LAYER ) );
316 currentTopReferenceLayer.emplace_back( m_trackPropagationGrid->GetCellValue( row, TRACK_GRID_TOP_REFERENCE ) );
317 currentBottomReferenceLayer.emplace_back(
319 }
320
321 // Save the current data - via grid
322 std::vector<wxString> currentSignalLayersFrom;
323 std::vector<wxString> currentSignalLayersTo;
324 std::vector<wxString> currentViaLayersFrom;
325 std::vector<wxString> currentViaLayersTo;
326
327 for( int row = 0; row < m_viaOverrides->GetNumberRows(); ++row )
328 {
329 currentSignalLayersFrom.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM ) );
330 currentSignalLayersTo.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO ) );
331 currentViaLayersFrom.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM ) );
332 currentViaLayersTo.emplace_back( m_viaOverrides->GetCellValue( row, VIA_GRID_VIA_LAYER_TO ) );
333 }
334
335 // Reset the via layers lists
336 wxGridCellAttr* attr = new wxGridCellAttr;
337 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
339
340 attr = new wxGridCellAttr;
341 attr->SetEditor( new wxGridCellChoiceEditor( layerNamesWithNone, false ) );
343
344 attr = new wxGridCellAttr;
345 attr->SetEditor( new wxGridCellChoiceEditor( layerNamesWithNone, false ) );
347
348 attr = new wxGridCellAttr;
349 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
350 m_viaOverrides->SetColAttr( VIA_GRID_SIGNAL_LAYER_FROM, attr );
351
352 attr = new wxGridCellAttr;
353 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
354 m_viaOverrides->SetColAttr( VIA_GRID_SIGNAL_LAYER_TO, attr );
355
356 attr = new wxGridCellAttr;
357 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
358 m_viaOverrides->SetColAttr( VIA_GRID_VIA_LAYER_FROM, attr );
359
360 attr = new wxGridCellAttr;
361 attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
362 m_viaOverrides->SetColAttr( VIA_GRID_VIA_LAYER_TO, attr );
363
364 // Restore the data, changing or resetting layer names if required
365 for( int row = 0; row < m_trackPropagationGrid->GetNumberRows(); ++row )
366 {
367 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentSignalLayer[row] ) )
368 {
369 PCB_LAYER_ID lastSignalId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayer[row]];
370
371 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalId ) )
373 m_parentPanel->m_board->GetLayerName( lastSignalId ) );
374 else
376 m_parentPanel->m_layerNames.front() );
377 }
378 else
379 {
380 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_SIGNAL_LAYER, m_parentPanel->m_layerNames.front() );
381 }
382
383 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentTopReferenceLayer[row] ) )
384 {
385 const PCB_LAYER_ID lastTopReferenceId = m_parentPanel->m_prevLayerNamesToIDs[currentTopReferenceLayer[row]];
386
387 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastTopReferenceId ) )
389 m_parentPanel->m_board->GetLayerName( lastTopReferenceId ) );
390 else
391 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_TOP_REFERENCE, layerNamesWithNone[0] );
392 }
393 else
394 {
395 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_TOP_REFERENCE, layerNamesWithNone[0] );
396 }
397
398 if( m_parentPanel->m_prevLayerNamesToIDs.contains( currentBottomReferenceLayer[row] ) )
399 {
400 const PCB_LAYER_ID lastBottomReferenceId =
401 m_parentPanel->m_prevLayerNamesToIDs[currentBottomReferenceLayer[row]];
402
403 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastBottomReferenceId ) )
405 m_parentPanel->m_board->GetLayerName( lastBottomReferenceId ) );
406 else
407 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, layerNamesWithNone[0] );
408 }
409 else
410 {
411 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, layerNamesWithNone[0] );
412 }
413 }
414
415 for( int row = 0; row < m_viaOverrides->GetNumberRows(); ++row )
416 {
417 const PCB_LAYER_ID lastSignalFromId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayersFrom[row]];
418
419 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalFromId ) )
420 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM,
421 m_parentPanel->m_board->GetLayerName( lastSignalFromId ) );
422 else
423 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_parentPanel->m_layerNames.front() );
424
425 const PCB_LAYER_ID lastSignalToId = m_parentPanel->m_prevLayerNamesToIDs[currentSignalLayersTo[row]];
426
427 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastSignalToId ) )
428 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO,
429 m_parentPanel->m_board->GetLayerName( lastSignalToId ) );
430 else
431 m_viaOverrides->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_parentPanel->m_layerNames.back() );
432
433 const PCB_LAYER_ID lastViaFromId = m_parentPanel->m_prevLayerNamesToIDs[currentViaLayersFrom[row]];
434
435 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastViaFromId ) )
436 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM,
437 m_parentPanel->m_board->GetLayerName( lastViaFromId ) );
438 else
439 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_parentPanel->m_layerNames.front() );
440
441 const PCB_LAYER_ID lastViaToId = m_parentPanel->m_prevLayerNamesToIDs[currentViaLayersTo[row]];
442
443 if( m_parentPanel->m_copperLayerIdsToIndex.contains( lastViaToId ) )
444 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO,
445 m_parentPanel->m_board->GetLayerName( lastViaToId ) );
446 else
447 m_viaOverrides->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_parentPanel->m_layerNames.back() );
448 }
449}
450
451
453{
454 const int minValueWidth = m_trackPropagationGrid->GetTextExtent( wxT( "000.0000 ps/mm" ) ).x;
455
456 for( int i = 0; i < m_trackPropagationGrid->GetNumberCols(); ++i )
457 {
458 const int titleSize = m_trackPropagationGrid->GetTextExtent( m_trackPropagationGrid->GetColLabelValue( i ) ).x;
459
461 m_trackPropagationGrid->SetColSize( i, titleSize + 30 );
462 else
463 m_trackPropagationGrid->SetColSize( i, std::max( titleSize, minValueWidth ) );
464 }
465
466 for( int i = 0; i < m_viaOverrides->GetNumberCols(); ++i )
467 {
468 const int titleSize = GetTextExtent( m_viaOverrides->GetColLabelValue( i ) ).x;
469 if( i == VIA_GRID_DELAY )
470 m_viaOverrides->SetColSize( i, std::max( titleSize, minValueWidth ) );
471 else
472 m_viaOverrides->SetColSize( i, titleSize + 30 );
473 }
474
475 const int impedanceWidth = m_targetImpedance->GetTextExtent( wxT( "0000.00" ) ).x;
476 m_targetImpedance->SetSize( impedanceWidth, m_targetImpedance->GetSize().GetHeight() );
477
478 Layout();
479}
480
481
483{
484 const wxString newName = event.GetString();
485 m_parentPanel->UpdateProfileName( this, newName );
486}
487
488
496
497
499{
500 m_trackPropagationGrid->CommitPendingChanges();
501 m_viaOverrides->CommitPendingChanges();
502
505 else
507}
508
509
511{
512 const int numRows = m_trackPropagationGrid->GetNumberRows();
513 m_trackPropagationGrid->InsertRows( m_trackPropagationGrid->GetNumberRows() );
514
515 auto setFrontRowLayers = [&]( const int row )
516 {
517 auto nameItr = m_parentPanel->m_layerNames.begin();
518
519 if( nameItr == m_parentPanel->m_layerNames.end() )
520 return;
521
522 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_SIGNAL_LAYER, *nameItr );
523
524 ++nameItr;
525
526 if( nameItr == m_parentPanel->m_layerNames.end() )
527 return;
528
529 m_trackPropagationGrid->SetCellValue( row, TRACK_GRID_BOTTOM_REFERENCE, *nameItr );
530 };
531
532 auto setRowLayers = [&]()
533 {
534 if( numRows == 0 )
535 {
536 setFrontRowLayers( 0 );
537 return;
538 }
539
540 const wxString lastSignalLayerName =
541 m_trackPropagationGrid->GetCellValue( numRows - 1, TRACK_GRID_SIGNAL_LAYER );
542 auto nameItr = std::find( m_parentPanel->m_layerNames.begin(), m_parentPanel->m_layerNames.end(),
543 lastSignalLayerName );
544
545 if( nameItr == m_parentPanel->m_layerNames.end() )
546 return;
547
548 if( nameItr == m_parentPanel->m_layerNames.end() - 1 )
549 {
550 setFrontRowLayers( numRows );
551 return;
552 }
553
554 ++nameItr;
555
556 if( nameItr == m_parentPanel->m_layerNames.end() )
557 return;
558
559 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_SIGNAL_LAYER, *nameItr );
560 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_TOP_REFERENCE, *( nameItr - 1 ) );
561
562 ++nameItr;
563
564 if( nameItr != m_parentPanel->m_layerNames.end() )
565 m_trackPropagationGrid->SetCellValue( numRows, TRACK_GRID_BOTTOM_REFERENCE, *nameItr );
566 };
567
568 setRowLayers();
569
570 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_TRACK_WIDTH, 0 );
571 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_TRACK_GAP, 0 );
572 m_trackPropagationGrid->SetUnitValue( numRows, TRACK_GRID_DELAY, 0 );
574}
575
576
578{
579 wxArrayInt selRows = m_trackPropagationGrid->GetSelectedRows();
580
581 if( selRows.size() == 1 )
582 m_trackPropagationGrid->DeleteRows( selRows[0] );
583}
584
585
587{
588 const int numRows = m_viaOverrides->GetNumberRows();
589 m_viaOverrides->InsertRows( numRows );
590 m_viaOverrides->SetUnitValue( numRows, VIA_GRID_DELAY, 0 );
591 m_viaOverrides->SetCellValue( numRows, VIA_GRID_SIGNAL_LAYER_FROM, m_parentPanel->m_layerNames.front() );
592 m_viaOverrides->SetCellValue( numRows, VIA_GRID_SIGNAL_LAYER_TO, m_parentPanel->m_layerNames.back() );
593 m_viaOverrides->SetCellValue( numRows, VIA_GRID_VIA_LAYER_FROM, m_parentPanel->m_layerNames.front() );
594 m_viaOverrides->SetCellValue( numRows, VIA_GRID_VIA_LAYER_TO, m_parentPanel->m_layerNames.back() );
596}
597
598
600{
601 wxArrayInt selRows = m_viaOverrides->GetSelectedRows();
602
603 if( selRows.size() == 1 )
604 m_viaOverrides->DeleteRows( selRows[0] );
605}
606
607
609{
610 return m_name->GetValue();
611}
612
613
614double PANEL_SETUP_TUNING_PROFILE_INFO::calculateSkinDepth( const double aFreq, const double aMurc,
615 const double aSigma )
616{
617 return 1.0 / sqrt( M_PI * aFreq * aMurc * TRANSLINE_CALCULATIONS::MU0 * aSigma );
618}
619
620
621int PANEL_SETUP_TUNING_PROFILE_INFO::getStackupLayerId( const std::vector<BOARD_STACKUP_ITEM*>& aLayerList,
622 PCB_LAYER_ID aPcbLayerId )
623{
624 bool layerFound = false;
625 int layerStackupId = 0;
626
627 while( layerStackupId < static_cast<int>( aLayerList.size() ) && !layerFound )
628 {
629 if( aLayerList.at( layerStackupId )->GetBrdLayerId() != aPcbLayerId )
630 ++layerStackupId;
631 else
632 layerFound = true;
633 }
634
635 if( !layerFound )
636 return -1;
637
638 return layerStackupId;
639}
640
641
643{
644 const wxString zStr = m_targetImpedance->GetValue();
645
646 double z;
647 if( !zStr.ToDouble( &z ) )
648 z = -1;
649
650 return z;
651}
652
653
655 const std::vector<BOARD_STACKUP_ITEM*>& aStackupLayerList, const std::vector<int>& dielectricLayerStackupIds,
656 const EDA_IU_SCALE& aIuScale )
657{
658 double totalHeight = 0.0;
659 double e_r = 0.0;
660 double lossTangent = 0.0;
661
662 for( int i : dielectricLayerStackupIds )
663 {
664 const BOARD_STACKUP_ITEM* layer = aStackupLayerList.at( i );
665
666 for( int subLayerIdx = 0; subLayerIdx < layer->GetSublayersCount(); ++subLayerIdx )
667 {
668 totalHeight += aIuScale.IUTomm( layer->GetThickness( subLayerIdx ) );
669 e_r += layer->GetEpsilonR( subLayerIdx ) * aIuScale.IUTomm( layer->GetThickness( subLayerIdx ) );
670 lossTangent += layer->GetLossTangent( subLayerIdx ) * aIuScale.IUTomm( layer->GetThickness( subLayerIdx ) );
671 }
672 }
673
674 e_r = e_r / totalHeight;
675 lossTangent = lossTangent / totalHeight;
676 totalHeight /= 1000.0; // Convert from mm to m
677
678 return { totalHeight, e_r, lossTangent };
679}
680
681
682void PANEL_SETUP_TUNING_PROFILE_INFO::getDielectricLayers( const std::vector<BOARD_STACKUP_ITEM*>& aStackupLayerList,
683 const int aSignalLayerId, const int aReferenceLayerId,
684 std::vector<int>& aDielectricLayerStackupIds )
685{
686 for( int i = std::min( aSignalLayerId, aReferenceLayerId ) + 1; i < std::max( aSignalLayerId, aReferenceLayerId );
687 ++i )
688 {
689 const BOARD_STACKUP_ITEM* layer = aStackupLayerList.at( i );
690
691 if( layer->GetType() != BS_ITEM_TYPE_DIELECTRIC )
692 continue;
693
694 if( !layer->HasEpsilonRValue() )
695 continue;
696
697 aDielectricLayerStackupIds.push_back( i );
698 }
699}
700
701
703{
704 // Determine if this is a stripline or microstrip geometry
705 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
706
707 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
708 return;
709
710 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs.at( signalLayerName );
711 const TUNING_PROFILE::PROFILE_TYPE profileType = m_type->GetSelection() == 0
714 const bool isMicrostrip = IsFrontLayer( signalLayer ) || IsBackLayer( signalLayer );
715 CalculationType calculationType;
716
717 switch( aCol )
718 {
719 case TRACK_GRID_TRACK_WIDTH: calculationType = CalculationType::WIDTH; break;
720 case TRACK_GRID_TRACK_GAP: calculationType = CalculationType::GAP; break;
721 case TRACK_GRID_DELAY: calculationType = CalculationType::DELAY; break;
722 default: calculationType = CalculationType::WIDTH; break;
723 }
724
725 if( profileType == TUNING_PROFILE::PROFILE_TYPE::DIFFERENTIAL ) // Differential tracks mode
726 {
727 int calculatedWidth = 0;
728 int calculatedGap = 0;
729 int calculatedDelay = 0;
730
732
733 if( isMicrostrip )
734 result = calculateDifferentialMicrostrip( aRow, calculationType );
735 else
736 result = calculateDifferentialStripline( aRow, calculationType );
737
738 if( !result.OK )
739 {
740 DisplayErrorMessage( m_parentPanel->m_dlg, wxString::Format( _( "Error: %s" ), result.ErrorMsg ) );
741 return;
742 }
743
744 calculatedWidth = result.Width;
745 calculatedGap = result.DiffPairGap;
746 calculatedDelay = result.Delay;
747
748 const bool widthOk = calculatedWidth > 0;
749 const bool gapOk = calculatedGap > 0;
750 const bool delayOk = calculatedDelay > 0;
751
752 if( !widthOk )
753 {
754 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track width" ) );
755 return;
756 }
757 else if( !gapOk )
758 {
759 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute differential pair gap" ) );
760 return;
761 }
762 else if( !delayOk )
763 {
764 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track propagation delay" ) );
765 return;
766 }
767
768 if( calculationType == CalculationType::WIDTH )
769 {
770 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH, calculatedWidth );
771 }
772 else if( calculationType == CalculationType::GAP )
773 {
774 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_GAP, calculatedGap );
775 }
776
777 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_DELAY, calculatedDelay );
778 }
779 else // Single track mode
780 {
781 int calculatedWidth = 0;
782 int calculatedDelay = 0;
783
785
786 if( isMicrostrip )
787 result = calculateSingleMicrostrip( aRow, calculationType );
788 else
789 result = calculateSingleStripline( aRow, calculationType );
790
791 if( !result.OK )
792 {
793 DisplayErrorMessage( m_parentPanel->m_dlg, wxString::Format( _( "Error: %s" ), result.ErrorMsg ) );
794 return;
795 }
796
797 calculatedWidth = result.Width;
798 calculatedDelay = result.Delay;
799
800 const bool widthOk = calculatedWidth > 0;
801 const bool delayOk = calculatedDelay > 0;
802
803 if( !widthOk )
804 {
805 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track width" ) );
806 return;
807 }
808 else if( !delayOk )
809 {
810 DisplayErrorMessage( m_parentPanel->m_dlg, _( "Could not compute track propagation delay" ) );
811 return;
812 }
813
814 if( calculationType == CalculationType::WIDTH )
815 {
816 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH, calculatedWidth );
817 }
818
819 m_trackPropagationGrid->SetUnitValue( aRow, TRACK_GRID_DELAY, calculatedDelay );
820 }
821}
822
823
825{
826 if( m_name->GetValue() == wxEmptyString )
827 {
828 m_parentPanel->m_tuningProfiles->SetSelection( aPageIndex );
829
830 const wxString msg = _( "Tuning profile must have a name" );
832 return false;
833 }
834
835 std::set<wxString> layerNames;
836
837 for( int i = 0; i < m_trackPropagationGrid->GetNumberRows(); ++i )
838 {
839 const wxString& layerName = m_trackPropagationGrid->GetCellValue( i, TRACK_GRID_SIGNAL_LAYER );
840
841 if( layerNames.contains( layerName ) )
842 {
843 m_parentPanel->m_tuningProfiles->SetSelection( aPageIndex );
844
845 const wxString msg = _( "Duplicated signal layer configuration in tuning profile" );
848 return false;
849 }
850
851 layerNames.insert( layerName );
852 }
853
854 return true;
855}
856
857
858/*****************************************************************************************************************
859 * SIMULATION / ANALYSIS PLUMBING
860 ****************************************************************************************************************/
861
865{
866 // Get the signal layer information from the stackup
867 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
868 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
869
870 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
871
872 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
873 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
874
875 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
876
877 // Microstrip can only be on an outer copper layer
878 if( signalLayer != F_Cu && signalLayer != B_Cu )
879 return { {}, CALCULATION_RESULT{ _( "Internal error: Microstrip can only be on an outer copper layer" ) } };
880
881 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
882
883 if( signalLayerStackupId == -1 )
884 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
885
886 const double signalLayerThickness =
887 aScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
888
889 if( signalLayerThickness <= 0 )
890 return { {}, CALCULATION_RESULT{ _( "Signal layer thickness must be greater than 0" ) } };
891
892 // Get reference layer
893 wxString referenceLayerName;
894
895 if( signalLayer == F_Cu )
896 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
897 else
898 referenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
899
900 if( !m_parentPanel->m_layerNamesToIDs.contains( referenceLayerName ) )
901 return { {}, CALCULATION_RESULT{ _( "Reference layer not found in stackup" ) } };
902
903 const PCB_LAYER_ID referenceLayer = m_parentPanel->m_layerNamesToIDs[referenceLayerName];
904 const int referenceLayerStackupId = getStackupLayerId( stackupLayerList, referenceLayer );
905
906 if( signalLayerStackupId == referenceLayerStackupId )
907 return { {}, CALCULATION_RESULT{ _( "Reference layer must be different to signal layer" ) } };
908
909 // Get the dielectric layers between signal and reference layers
910 std::vector<int> dielectricLayerStackupIds;
911 getDielectricLayers( stackupLayerList, signalLayerStackupId, referenceLayerStackupId, dielectricLayerStackupIds );
912
913 // Calculate geometric average of the dielectric materials
914 const DIELECTRIC_INFO dielectricInfo =
915 calculateAverageDielectricConstants( stackupLayerList, dielectricLayerStackupIds, aScale );
916
917 if( dielectricInfo.Height <= 0.0 )
918 return { {}, CALCULATION_RESULT{ _( "Dielectric height must be greater than 0" ) } };
919
920 CALCULATION_BOARD_PARAMETERS boardParameters{ dielectricInfo.E_r, dielectricInfo.Height, 0.0, signalLayerThickness,
921 dielectricInfo.Loss_Tangent };
923 result.OK = true;
924
925 return { boardParameters, result };
926}
927
928
932{
933 // Get the signal layer information from the stackup
934 BOARD_STACKUP stackup = m_parentPanel->m_board->GetStackupOrDefault();
935 const std::vector<BOARD_STACKUP_ITEM*>& stackupLayerList = stackup.GetList();
936
937 const wxString signalLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_SIGNAL_LAYER );
938
939 if( !m_parentPanel->m_layerNamesToIDs.contains( signalLayerName ) )
940 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
941
942 const PCB_LAYER_ID signalLayer = m_parentPanel->m_layerNamesToIDs[signalLayerName];
943 const int signalLayerStackupId = getStackupLayerId( stackupLayerList, signalLayer );
944
945 if( signalLayerStackupId == -1 )
946 return { {}, CALCULATION_RESULT{ _( "Signal layer not found in stackup" ) } };
947
948 const double signalLayerThickness =
949 aScale.IUTomm( stackupLayerList.at( signalLayerStackupId )->GetThickness() ) / 1000.0;
950
951 if( signalLayerThickness <= 0 )
952 return { {}, CALCULATION_RESULT{ _( "Signal layer thickness must be greater than 0" ) } };
953
954 // Get top reference layer
955 const wxString topReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_TOP_REFERENCE );
956
957 if( !m_parentPanel->m_layerNamesToIDs.contains( topReferenceLayerName ) )
958 return { {}, CALCULATION_RESULT{ _( "Top reference layer not found in stackup" ) } };
959
960 const PCB_LAYER_ID topReferenceLayer = m_parentPanel->m_layerNamesToIDs[topReferenceLayerName];
961 const int topReferenceLayerStackupId = getStackupLayerId( stackupLayerList, topReferenceLayer );
962
963 if( !IsCopperLayerLowerThan( signalLayer, topReferenceLayer ) )
964 return { {}, CALCULATION_RESULT{ _( "Top reference layer must be above signal layer in board stackup" ) } };
965
966 // Get bottom reference layer
967 wxString bottomReferenceLayerName = m_trackPropagationGrid->GetCellValue( aRow, TRACK_GRID_BOTTOM_REFERENCE );
968
969 if( !m_parentPanel->m_layerNamesToIDs.contains( bottomReferenceLayerName ) )
970 return { {}, CALCULATION_RESULT{ _( "Bottom reference layer not found in stackup" ) } };
971
972 const PCB_LAYER_ID bottomReferenceLayer = m_parentPanel->m_layerNamesToIDs[bottomReferenceLayerName];
973 const int bottomReferenceLayerStackupId = getStackupLayerId( stackupLayerList, bottomReferenceLayer );
974
975 if( !IsCopperLayerLowerThan( bottomReferenceLayer, signalLayer ) )
976 return { {}, CALCULATION_RESULT{ _( "Bottom reference layer must be below signal layer in board stackup" ) } };
977
978 // Get the dielectric layers between signal and reference layers
979 std::vector<int> topDielectricLayerStackupIds, bottomDielectricLayerStackupIds;
980
981 getDielectricLayers( stackupLayerList, signalLayerStackupId, topReferenceLayerStackupId,
982 topDielectricLayerStackupIds );
983 getDielectricLayers( stackupLayerList, signalLayerStackupId, bottomReferenceLayerStackupId,
984 bottomDielectricLayerStackupIds );
985
986 // Calculate geometric average of the dielectric materials
987 std::vector<int> allDielectricLayerStackupIds( topDielectricLayerStackupIds );
988 allDielectricLayerStackupIds.insert( allDielectricLayerStackupIds.end(), bottomDielectricLayerStackupIds.begin(),
989 bottomDielectricLayerStackupIds.end() );
990
991 const DIELECTRIC_INFO topDielectricInfo =
992 calculateAverageDielectricConstants( stackupLayerList, topDielectricLayerStackupIds, aScale );
993 const DIELECTRIC_INFO bottomDielectricInfo =
994 calculateAverageDielectricConstants( stackupLayerList, bottomDielectricLayerStackupIds, aScale );
995 const DIELECTRIC_INFO allDielectricInfo =
996 calculateAverageDielectricConstants( stackupLayerList, allDielectricLayerStackupIds, aScale );
997
998 if( topDielectricInfo.Height <= 0.0 && bottomDielectricInfo.Height <= 0.0 )
999 return { {}, CALCULATION_RESULT{ _( "Dielectric heights must be greater than 0" ) } };
1000
1001 CALCULATION_BOARD_PARAMETERS boardParameters{ allDielectricInfo.E_r, topDielectricInfo.Height,
1002 bottomDielectricInfo.Height, signalLayerThickness,
1003 allDielectricInfo.Loss_Tangent };
1005 result.OK = true;
1006
1007 return { boardParameters, result };
1008}
1009
1010
1013{
1014 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1015
1016 // Get the target impedance
1017 const double targetZ = getTargetImpedance();
1018
1019 if( targetZ <= 0 )
1020 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1021
1022 // Get board parameters
1023 auto [boardParameters, result] = getMicrostripBoardParameters( aRow, iuScale );
1024
1025 if( !result.OK )
1026 return result;
1027
1028 // Set calculation parameters
1029 if( aCalculationType == CalculationType::WIDTH )
1030 {
1032 }
1033 else if( aCalculationType == CalculationType::DELAY )
1034 {
1035 const int widthInt = m_trackPropagationGrid->GetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1036
1037 const double width = iuScale.IUTomm( widthInt ) / 1000.0;
1039 }
1040
1041 // Run the synthesis or analysis
1042 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, 1.0 / RHO );
1044 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, calculateSkinDepth( 1.0, 1.0, 1.0 / RHO ) );
1045 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1046 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::H_T, 1e+20 );
1047 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness );
1048 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1049 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0, targetZ );
1050 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1052 m_microstripCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, boardParameters.LossTangent );
1057
1058 if( aCalculationType == CalculationType::WIDTH )
1060 else
1061 m_microstripCalc.Analyse();
1062
1063 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1064 [this, aCalculationType]() -> decltype( m_microstripCalc.GetSynthesisResults() )
1065 {
1066 if( aCalculationType == CalculationType::WIDTH )
1067 return m_microstripCalc.GetSynthesisResults();
1068
1069 return m_microstripCalc.GetAnalysisResults();
1070 }();
1071
1073 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1074
1076 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1077
1078 int width = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1079 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1080 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1082
1083 return CALCULATION_RESULT{ width, propDelay };
1084}
1085
1086
1089{
1090 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1091
1092 // Get the target impedance
1093 const double targetZ = getTargetImpedance();
1094
1095 if( targetZ <= 0 )
1096 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1097
1098 // Get board parameters
1099 auto [boardParameters, result] = getStriplineBoardParameters( aRow, iuScale );
1100
1101 if( !result.OK )
1102 return result;
1103
1104 // Set calculation parameters
1105 if( aCalculationType == CalculationType::WIDTH )
1106 {
1108 }
1109 else if( aCalculationType == CalculationType::DELAY )
1110 {
1111 const int widthInt = m_trackPropagationGrid->GetUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1112
1113 const double width = iuScale.IUTomm( widthInt ) / 1000.0;
1115 }
1116
1117 // Run the synthesis
1118 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, calculateSkinDepth( 1.0, 1.0, 1.0 / RHO ) );
1119 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1120 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1121 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::STRIPLINE_A, boardParameters.TopDielectricLayerThickness );
1122 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness
1123 + boardParameters.SignalLayerThickness
1124 + boardParameters.BottomDielectricLayerThickness );
1125 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0, targetZ );
1127 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1128 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, boardParameters.LossTangent );
1129 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, 1.0 );
1130 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, 1.0 / RHO );
1132
1133 if( aCalculationType == CalculationType::WIDTH )
1135 else
1136 m_striplineCalc.Analyse();
1137
1138 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1139 [this, aCalculationType]() -> decltype( m_striplineCalc.GetSynthesisResults() )
1140 {
1141 if( aCalculationType == CalculationType::WIDTH )
1142 return m_striplineCalc.GetSynthesisResults();
1143
1144 return m_striplineCalc.GetAnalysisResults();
1145 }();
1146
1148 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1149
1151 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1152
1153 int width = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1154 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1155 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1157
1158 return CALCULATION_RESULT{ width, propDelay };
1159}
1160
1161
1164{
1165 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1166
1167 // Get the target impedance
1168 const double targetZ = getTargetImpedance();
1169
1170 if( targetZ <= 0 )
1171 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1172
1173 // Get board parameters
1174 auto [boardParameters, result] = getMicrostripBoardParameters( aRow, iuScale );
1175
1176 if( !result.OK )
1177 return result;
1178
1179 // Set calculation parameters
1180 double width = 0.0;
1181 double gap = 0.0;
1182
1183 const std::optional<int> widthOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1184 const std::optional<int> gapOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_GAP );
1185
1186 if( aCalculationType == CalculationType::WIDTH )
1187 {
1188 if( !gapOpt || *gapOpt <= 0 )
1189 return CALCULATION_RESULT{ _( "Diff pair gap must be greater than 0 to calculate width" ) };
1190
1191 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1192 }
1193 else if( aCalculationType == CalculationType::GAP )
1194 {
1195 if( !widthOpt || *widthOpt <= 0 )
1196 return CALCULATION_RESULT{ _( "Width must be greater than 0 to calculate diff pair gap" ) };
1197
1198 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1199 }
1200 else if( aCalculationType == CalculationType::DELAY )
1201 {
1202 if( !widthOpt || !gapOpt || *widthOpt <= 0 || *gapOpt <= 0 )
1203 return CALCULATION_RESULT{ _( "Width and diff pair gap must be greater than 0 to calculate delay" ) };
1204
1205 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1206 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1207 }
1208
1209 // Run the synthesis
1210 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, targetZ / 2.0 );
1211 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, targetZ / 2.0 );
1215 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1217 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness );
1218 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1220 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1225 m_coupledMicrostripCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, boardParameters.LossTangent );
1227
1228 switch( aCalculationType )
1229 {
1232 case CalculationType::DELAY: m_coupledMicrostripCalc.Analyse(); break;
1233 }
1234
1235 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1236 [this, aCalculationType]() -> decltype( m_microstripCalc.GetSynthesisResults() )
1237 {
1238 if( aCalculationType == CalculationType::WIDTH || aCalculationType == CalculationType::GAP )
1239 return m_coupledMicrostripCalc.GetSynthesisResults();
1240
1241 return m_coupledMicrostripCalc.GetAnalysisResults();
1242 }();
1243
1245 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1246
1247 if( results[TRANSLINE_PARAMETERS::PHYS_S].second != TRANSLINE_STATUS::OK )
1248 return CALCULATION_RESULT{ _( "Diff pair gap calculation failed" ) };
1249
1251 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1252
1253 int calcWidth = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1254 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1255 int calcGap = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1256 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_S].first * 1000.0 ) );
1257 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1259
1260 return CALCULATION_RESULT{ calcWidth, calcGap, propDelay };
1261}
1262
1263
1266{
1267 const EDA_IU_SCALE& iuScale = m_parentPanel->m_unitsProvider->GetIuScale();
1268
1269 // Get the target impedance
1270 const double targetZ = getTargetImpedance();
1271
1272 if( targetZ <= 0 )
1273 return CALCULATION_RESULT{ _( "Target impedance must be greater than 0" ) };
1274
1275 // Get board parameters
1276 auto [boardParameters, result] = getStriplineBoardParameters( aRow, iuScale );
1277
1278 if( !result.OK )
1279 return result;
1280
1281 // Set calculation parameters
1282 double width = 0.0;
1283 double gap = 0.0;
1284
1285 const std::optional<int> widthOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_WIDTH );
1286 const std::optional<int> gapOpt = m_trackPropagationGrid->GetOptionalUnitValue( aRow, TRACK_GRID_TRACK_GAP );
1287
1288 if( aCalculationType == CalculationType::WIDTH )
1289 {
1290 if( !gapOpt || *gapOpt <= 0 )
1291 return CALCULATION_RESULT{ _( "Diff pair gap must be greater than 0 to calculate width" ) };
1292
1293 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1294 }
1295 else if( aCalculationType == CalculationType::GAP )
1296 {
1297 if( !widthOpt || *widthOpt <= 0 )
1298 return CALCULATION_RESULT{ _( "Width must be greater than 0 to calculate diff pair gap" ) };
1299
1300 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1301 }
1302 else if( aCalculationType == CalculationType::DELAY )
1303 {
1304 if( !widthOpt || !gapOpt || *widthOpt <= 0 || *gapOpt <= 0 )
1305 return CALCULATION_RESULT{ _( "Width and diff pair gap must be greater than 0 to calculate delay" ) };
1306
1307 width = iuScale.IUTomm( widthOpt.value() ) / 1000.0;
1308 gap = iuScale.IUTomm( gapOpt.value() ) / 1000.0;
1309 }
1310
1311 // Run the synthesis
1312 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, targetZ / 2.0 );
1313 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, targetZ / 2.0 );
1317 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, boardParameters.SignalLayerThickness );
1318 m_coupledStriplineCalc.SetParameter(
1319 TRANSLINE_PARAMETERS::H, boardParameters.TopDielectricLayerThickness + boardParameters.SignalLayerThickness
1320 + boardParameters.BottomDielectricLayerThickness );
1321 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, boardParameters.DielectricConstant );
1324 m_coupledStriplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, 1000000000.0 );
1328
1329 switch( aCalculationType )
1330 {
1333 case CalculationType::DELAY: m_coupledStriplineCalc.Analyse(); break;
1334 }
1335
1336 std::unordered_map<TRANSLINE_PARAMETERS, std::pair<double, TRANSLINE_STATUS>>& results =
1337 [this, aCalculationType]() -> decltype( m_coupledStriplineCalc.GetSynthesisResults() )
1338 {
1339 if( aCalculationType == CalculationType::WIDTH || aCalculationType == CalculationType::GAP )
1340 return m_coupledStriplineCalc.GetSynthesisResults();
1341
1342 return m_coupledStriplineCalc.GetAnalysisResults();
1343 }();
1344
1346 return CALCULATION_RESULT{ _( "Width calculation failed" ) };
1347
1348 if( results[TRANSLINE_PARAMETERS::PHYS_S].second != TRANSLINE_STATUS::OK )
1349 return CALCULATION_RESULT{ _( "Diff pair gap calculation failed" ) };
1350
1352 return CALCULATION_RESULT{ _( "Delay calculation failed" ) };
1353
1354 int calcWidth = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1355 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first * 1000.0 ) );
1356 int calcGap = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1357 iuScale, EDA_UNITS::MM, results[TRANSLINE_PARAMETERS::PHYS_S].first * 1000.0 ) );
1358 int propDelay = static_cast<int>( EDA_UNIT_UTILS::UI::FromUserUnit(
1360
1361 return CALCULATION_RESULT{ calcWidth, calcGap, propDelay };
1362}
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:715
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.
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