KiCad PCB EDA Suite
Loading...
Searching...
No Matches
tuner_slider.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 (C) 2016 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Maciej Suminski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 3
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23
24#include <ki_exception.h>
26#include <sim/simulator_frame.h>
27#include <sch_symbol.h>
28#include <template_fieldnames.h>
31
32#include <algorithm>
33#include <cmath> // log log1p expm1
34#include <complex> // norm
35
36// Must be after other includes to avoid conflict with a window header on msys2
37#include "tuner_slider.h"
38#include "core/kicad_algo.h"
39
41 const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol ) :
42 TUNER_SLIDER_BASE( aParent ),
43 m_symbol( aSymbol->m_Uuid ),
44 m_sheetPath( aSheetPath ),
45 m_ref( aSymbol->GetRef( &aSheetPath ) ),
46 m_min( 0.0 ),
47 m_max( 0.0 ),
48 m_value( 0.0 ),
50 m_frame( aFrame )
51{
52#if _WIN32
53 // BORDER_RAISED/SUNKEN look pretty on every platform but Windows
54 long style = GetWindowStyleFlag();
55 style &= ~wxBORDER_MASK;
56 style |= wxBORDER_SIMPLE;
57 SetWindowStyleFlag( style );
58#endif // _WIN32
59
60 const SPICE_ITEM* item = m_frame->GetExporter()->FindItem( m_ref );
61
62 if( !item )
63 throw KI_PARAM_ERROR( wxString::Format( _( "%s not found" ), m_ref ) );
64
65 m_name->SetLabel( wxString::Format( _( "Tune %s" ), m_ref ) );
67
68 m_e24->SetBitmap( KiBitmapBundle( BITMAPS::e_24 ) );
69 m_e24->SetIsCheckButton();
70 m_separator->SetIsSeparator();
71 m_e48->SetBitmap( KiBitmapBundle( BITMAPS::e_48 ) );
72 m_e48->SetIsCheckButton();
73 m_e96->SetBitmap( KiBitmapBundle( BITMAPS::e_96 ) );
74 m_e96->SetIsCheckButton();
75 m_e192->SetBitmap( KiBitmapBundle( BITMAPS::e_192 ) );
76 m_e192->SetIsCheckButton();
77
78 m_modeChoice->SetSelection( 0 );
79 m_stepCount->SetRange( 2, 100 );
80 m_stepCount->SetValue( 5 );
82
83 const SIM_MODEL::PARAM* tunerParam = item->model->GetTunerParam();
84
85 if( !tunerParam )
86 {
87 throw KI_PARAM_ERROR( wxString::Format( _( "%s has simulation model of type '%s %s'.\n\n"
88 "Only passive R, L, C models and voltage and "
89 "current sources may be tuned." ),
90 m_ref,
91 item->model->GetDeviceInfo().fieldValue,
92 item->model->GetTypeInfo().fieldValue ) );
93 }
94
95 // Special case for potentiometers because we don't have value ranges implemented yet.
96 if( item->model->GetType() == SIM_MODEL::TYPE::R_POT )
97 {
98 std::string valueStr = SIM_VALUE::ToSpice( item->model->GetTunerParam()->value );
99
100 if( valueStr != "" )
101 m_value = SPICE_VALUE( valueStr );
102 else
103 m_value = SPICE_VALUE( "0.5" );
104
105 m_min = SPICE_VALUE( 0 );
106 m_max = SPICE_VALUE( 1 );
107 }
108 else
109 {
111 m_min = SPICE_VALUE( 0.5 ) * m_value;
112 m_max = SPICE_VALUE( 2.0 ) * m_value;
113 }
114
115 m_minText->SetValue( m_min.ToOrigString() );
116 m_maxText->SetValue( m_max.ToOrigString() );
117
119 updateSlider();
120
121 Layout();
122}
123
124
126{
127 return std::max( 2, m_stepCount->GetValue() );
128}
129
130
132{
133 m_name->SetLabel( wxString::Format( _( "Tune %s" ), m_ref ) );
134
135 wxArrayString modeChoices;
136 modeChoices.Add( _( "Single Run" ) );
137 modeChoices.Add( _( "Multi Run" ) );
138
139 int selection = m_modeChoice->GetSelection();
140
141 m_modeChoice->Set( modeChoices );
142
143 if( selection < 0 || selection >= static_cast<int>( modeChoices.size() ) )
144 selection = 0;
145
146 m_modeChoice->SetSelection( selection );
147
148 m_stepsLabel->SetLabel( _( "Steps" ) );
149
151}
152
153
154void TUNER_SLIDER::onESeries( wxCommandEvent& event )
155{
156 for( BITMAP_BUTTON* btn : { m_e24, m_e48, m_e96, m_e192 } )
157 {
158 if( btn != event.GetEventObject() )
159 btn->Check( false );
160 }
161
162 wxString oldValue = m_valueText->GetValue();
163
165
166 if( m_valueText->GetValue() != oldValue )
168
169 event.Skip();
170}
171
172
173void TUNER_SLIDER::onRunModeChanged( wxCommandEvent& event )
174{
175 int selection = m_modeChoice->GetSelection();
176
177 if( selection == wxNOT_FOUND )
178 selection = 0;
179
180 m_runMode = ( selection == 1 ) ? RUN_MODE::MULTI : RUN_MODE::SINGLE;
181
184
185 event.Skip();
186}
187
188
190{
191 // Get the value into the current range boundaries
192 if( aVal > m_max )
193 m_value = m_max;
194 else if( aVal < m_min )
195 m_value = m_min;
196 else
197 m_value = aVal;
198
200 updateSlider();
202
203 return true;
204}
205
206
208{
209 if( aVal >= m_max )
210 return false;
211
212 m_min = aVal;
213
214 if( m_value < aVal ) // Limit the current value
215 SetValue( aVal );
216
217 m_minText->SetValue( aVal.ToOrigString() );
218 updateSlider();
219
220 return true;
221}
222
223
225{
226 if( aVal <= m_min )
227 return false;
228
229 m_max = aVal;
230
231 if( m_value > aVal ) // Limit the current value
232 SetValue( aVal );
233
234 m_maxText->SetValue( aVal.ToOrigString() );
235 updateSlider();
236
237 return true;
238}
239
240
242{
243 wxQueueEvent( m_frame, new wxCommandEvent( EVT_SIM_UPDATE ) );
244}
245
247{
248 bool enableSteps = ( m_runMode == RUN_MODE::MULTI );
249
250 m_stepCount->Enable( enableSteps );
251 m_stepsLabel->Enable( enableSteps );
252
253 // In Multi Run mode, the middle value text and slider are not directly editable,
254 // and save actions are disabled. Re-enable for Single Run.
255 bool enableDirectControls = ( m_runMode == RUN_MODE::SINGLE );
256 m_valueText->Enable( enableDirectControls );
257 m_slider->Enable( enableDirectControls );
258 m_saveBtn->Enable( enableDirectControls );
259 m_closeBtn->Enable( true );
260}
261
262
264{
265 wxASSERT( m_max >= m_value && m_value >= m_min );
266 double value = ( ( m_value - m_min ) / ( m_max - m_min ) ).ToDouble();
267 m_slider->SetValue( KiROUND( value * 100.0 ) );
268}
269
270
272{
273 static std::vector<double> e24 = { 1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0,
274 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1 };
275
276 static std::vector<double> e192 = { 1.00, 1.01, 1.02, 1.04, 1.05, 1.06, 1.07, 1.09, 1.10, 1.11,
277 1.13, 1.14, 1.15, 1.17, 1.18, 1.20, 1.21, 1.23, 1.24, 1.26,
278 1.27, 1.29, 1.30, 1.32, 1.33, 1.35, 1.37, 1.38, 1.40, 1.42,
279 1.43, 1.45, 1.47, 1.49, 1.50, 1.52, 1.54, 1.56, 1.58, 1.60,
280 1.62, 1.64, 1.65, 1.67, 1.69, 1.72, 1.74, 1.76, 1.78, 1.80,
281 1.82, 1.84, 1.87, 1.89, 1.91, 1.93, 1.96, 1.98, 2.00, 2.03,
282 2.05, 2.08, 2.10, 2.13, 2.15, 2.18, 2.21, 2.23, 2.26, 2.29,
283 2.32, 2.34, 2.37, 2.40, 2.43, 2.46, 2.49, 2.52, 2.55, 2.58,
284 2.61, 2.64, 2.67, 2.71, 2.74, 2.77, 2.80, 2.84, 2.87, 2.91,
285 2.94, 2.98, 3.01, 3.05, 3.09, 3.12, 3.16, 3.20, 3.24, 3.28,
286 3.32, 3.36, 3.40, 3.44, 3.48, 3.52, 3.57, 3.61, 3.65, 3.70,
287 3.74, 3.79, 3.83, 3.88, 3.92, 3.97, 4.02, 4.07, 4.12, 4.17,
288 4.22, 4.27, 4.32, 4.37, 4.42, 4.48, 4.53, 4.59, 4.64, 4.70,
289 4.75, 4.81, 4.87, 4.93, 4.99, 5.05, 5.11, 5.17, 5.23, 5.30,
290 5.36, 5.42, 5.49, 5.56, 5.62, 5.69, 5.76, 5.83, 5.90, 5.97,
291 6.04, 6.12, 6.19, 6.26, 6.34, 6.42, 6.49, 6.57, 6.65, 6.73,
292 6.81, 6.90, 6.98, 7.06, 7.15, 7.23, 7.32, 7.41, 7.50, 7.59,
293 7.68, 7.77, 7.87, 7.96, 8.06, 8.16, 8.25, 8.35, 8.45, 8.56,
294 8.66, 8.76, 8.87, 8.98, 9.09, 9.20, 9.31, 9.42, 9.53, 9.65,
295 9.76, 9.88 };
296
297 int precision = 3;
298 wxString prefix;
299 double value = m_value.ToNormalizedDouble( &prefix );
300
301 bool e_24 = m_e24->IsChecked();
302 bool e_extended = m_e48->IsChecked() || m_e96->IsChecked() || m_e192->IsChecked();
303
304 if( e_24 || e_extended )
305 {
306 std::vector<double> table;
307 table.reserve( 192 + 24 + 1 /* worst case */ );
308
309 if( e_extended )
310 {
311 int step = m_e48->IsChecked() ? 4 : m_e96->IsChecked() ? 2 : 1;
312
313 for( size_t ii = 0; ii < e192.size(); ii += step )
314 table.push_back( e192[ii] );
315 }
316
317 if( e_24 )
318 table.insert( table.end(), e24.begin(), e24.end() );
319
320 table.push_back( 10.0 );
321
322 std::sort( table.begin(), table.end() );
324
325 for( double decade : { 1.0, 10.0, 100.0 } )
326 {
327 for( size_t ii = 0; ii < table.size() - 1; ++ii )
328 {
329 if( value < ( table[ii] + table[ii+1] ) * decade / 2 )
330 {
331 precision = 0;
332
333 if( decade == 1.0 )
334 precision++;
335
336 if( e_extended && decade != 100.0 )
337 precision++;
338
339 m_valueText->SetValue( wxString::Format( wxT( "%.*f%s" ),
340 precision,
341 table[ii] * decade,
342 prefix ) );
343 return;
344 }
345 }
346 }
347 }
348
349 wxString valueStr = wxString::Format( wxT( "%.3f" ), value );
350 SPICE_VALUE::StripZeros( valueStr );
351 m_valueText->SetValue( valueStr + prefix );
352}
353
354
356{
357 try
358 {
359 SPICE_VALUE newMax( m_maxText->GetValue() );
360 SetMax( newMax );
361 // If in Multi Run mode, changing the range should trigger a re-run
364 }
365 catch( const KI_PARAM_ERROR& )
366 {
367 // Restore the previous value
368 m_maxText->SetValue( m_max.ToOrigString() );
369 }
370}
371
372
374{
375 try
376 {
377 SPICE_VALUE newCur( m_valueText->GetValue() );
378 SetValue( newCur );
379 }
380 catch( const KI_PARAM_ERROR& )
381 {
382 // Restore the previous value
383 m_valueText->SetValue( m_value.ToOrigString() );
384 }
385}
386
387
389{
390 try
391 {
392 SPICE_VALUE newMin( m_minText->GetValue() );
393 SetMin( newMin );
394 // If in Multi Run mode, changing the range should trigger a re-run
397 }
398 catch( const KI_PARAM_ERROR& )
399 {
400 // Restore the previous value
401 m_minText->SetValue( m_min.ToOrigString() );
402 }
403}
404
405
406void TUNER_SLIDER::onClose( wxCommandEvent& event )
407{
408 m_frame->RemoveTuner( this );
409}
410
411
412void TUNER_SLIDER::onSave( wxCommandEvent& event )
413{
414 m_frame->UpdateTunerValue( m_sheetPath, m_symbol, GetSymbolRef(), m_valueText->GetValue() );
415}
416
417
418void TUNER_SLIDER::onSliderScroll( wxScrollEvent& event )
419{
420 m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( m_slider->GetValue() / 100.0 );
422}
423
424
425void TUNER_SLIDER::onSliderChanged( wxScrollEvent& event )
426{
427 m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( m_slider->GetValue() / 100.0 );
430}
431
432
433void TUNER_SLIDER::onMaxKillFocus( wxFocusEvent& event )
434{
435 updateMax();
436 event.Skip(); // Mandatory in wxFocusEvent
437}
438
439
440void TUNER_SLIDER::onValueKillFocus( wxFocusEvent& event )
441{
442 updateValue();
443 event.Skip(); // Mandatory in wxFocusEvent
444}
445
446
447void TUNER_SLIDER::onMinKillFocus( wxFocusEvent& event )
448{
449 updateMin();
450 event.Skip(); // Mandatory in wxFocusEvent
451}
452
453
454void TUNER_SLIDER::onMaxTextEnter( wxCommandEvent& event )
455{
456 updateMax();
457 event.Skip(); // Mandatory in wxFocusEvent
458}
459
460
461void TUNER_SLIDER::onValueTextEnter( wxCommandEvent& event )
462{
463 updateValue();
464}
465
466
467void TUNER_SLIDER::onMinTextEnter( wxCommandEvent& event )
468{
469 updateMin();
470}
471
472
473void TUNER_SLIDER::onStepsChanged( wxSpinEvent& event )
474{
476 event.Skip();
477}
478
479
480void TUNER_SLIDER::onStepsTextEnter( wxCommandEvent& event )
481{
482 long steps;
483
484 if( !event.GetString().ToLong( &steps ) )
485 steps = m_stepCount->GetValue();
486
487 if( steps < 2 )
488 steps = 2;
489
490 m_stepCount->SetValue( static_cast<int>( steps ) );
491
493 event.Skip();
494}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
Hold a translatable error message and may be used when throwing exceptions containing a translated er...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Schematic symbol object.
Definition sch_symbol.h:69
The SIMULATOR_FRAME_UI holds the main user-interface for running simulations.
virtual const PARAM * GetTunerParam() const
Definition sim_model.h:478
DEVICE_INFO GetDeviceInfo() const
Definition sim_model.h:454
INFO GetTypeInfo() const
Definition sim_model.h:455
TYPE GetType() const
Definition sim_model.h:458
static std::string ToSpice(const std::string &aString)
Helper class to recognize Spice formatted values.
Definition spice_value.h:52
static void StripZeros(wxString &aString)
wxString ToOrigString() const
Return either a normal string or Spice format string, depending on the original value format.
STD_BITMAP_BUTTON * m_closeBtn
BITMAP_BUTTON * m_separator
wxStaticText * m_stepsLabel
BITMAP_BUTTON * m_e96
wxSpinCtrl * m_stepCount
wxTextCtrl * m_valueText
TUNER_SLIDER_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxBORDER_NONE|wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
BITMAP_BUTTON * m_e48
BITMAP_BUTTON * m_e24
BITMAP_BUTTON * m_e192
wxStaticText * m_name
void onESeries(wxCommandEvent &event) override
bool SetMin(const SPICE_VALUE &aVal)
int GetStepCount() const
void onStepsTextEnter(wxCommandEvent &event) override
void onRunModeChanged(wxCommandEvent &event) override
void onValueTextEnter(wxCommandEvent &event) override
void onMinKillFocus(wxFocusEvent &event) override
wxString m_ref
void onValueKillFocus(wxFocusEvent &event) override
bool SetValue(const SPICE_VALUE &aVal)
void onSave(wxCommandEvent &event) override
void onStepsChanged(wxSpinEvent &event) override
TUNER_SLIDER(SIMULATOR_FRAME_UI *aPanel, wxWindow *aParent, const SCH_SHEET_PATH &aSheetPath, SCH_SYMBOL *aSymbol)
wxString GetSymbolRef() const
SPICE_VALUE m_max
void onMaxTextEnter(wxCommandEvent &event) override
void updateComponentValue()
bool SetMax(const SPICE_VALUE &aVal)
void updateValueText()
void onMaxKillFocus(wxFocusEvent &event) override
void onSliderScroll(wxScrollEvent &event) override
SCH_SHEET_PATH m_sheetPath
void onMinTextEnter(wxCommandEvent &event) override
void onClose(wxCommandEvent &event) override
SIMULATOR_FRAME_UI * m_frame
SPICE_VALUE m_value
SPICE_VALUE m_min
RUN_MODE m_runMode
void onSliderChanged(wxScrollEvent &event) override
void ShowChangedLanguage()
void updateModeControls()
#define _(s)
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition kicad_algo.h:157
std::string value
Definition sim_model.h:397
const SIM_MODEL * model
std::vector< std::vector< std::string > > table