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 (C) 2022-2023 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, you may find one here:
21 * https://www.gnu.org/licenses/gpl-3.0.html
22 * or you may search the http://www.gnu.org website for the version 3 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27
28#include <ki_exception.h>
30#include <sim/simulator_frame.h>
31#include <sch_symbol.h>
32#include <template_fieldnames.h>
35
36#include <cmath> // log log1p expm1
37#include <complex> // norm
38
39// Must be after other includes to avoid conflict with a window header on msys2
40#include "tuner_slider.h"
41#include "core/kicad_algo.h"
42
44 const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol ) :
45 TUNER_SLIDER_BASE( aParent ),
46 m_symbol( aSymbol->m_Uuid ),
47 m_sheetPath( aSheetPath ),
48 m_ref( aSymbol->GetRef( &aSheetPath ) ),
49 m_min( 0.0 ),
50 m_max( 0.0 ),
51 m_value( 0.0 ),
52 m_frame( aFrame )
53{
54 const SPICE_ITEM* item = m_frame->GetExporter()->FindItem( m_ref );
55
56 if( !item )
57 throw KI_PARAM_ERROR( wxString::Format( _( "%s not found" ), m_ref ) );
58
59 m_name->SetLabel( wxString::Format( _( "Tune %s" ), m_ref ) );
60 m_closeBtn->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
61
62 m_e24->SetBitmap( KiBitmapBundle( BITMAPS::e_24 ) );
65 m_e48->SetBitmap( KiBitmapBundle( BITMAPS::e_48 ) );
67 m_e96->SetBitmap( KiBitmapBundle( BITMAPS::e_96 ) );
69 m_e192->SetBitmap( KiBitmapBundle( BITMAPS::e_192 ) );
71
72 const SIM_MODEL::PARAM* tunerParam = item->model->GetTunerParam();
73
74 if( !tunerParam )
75 {
76 throw KI_PARAM_ERROR( wxString::Format( _( "%s has simulation model of type '%s %s'; "
77 "only RLC passives be tuned" ),
78 m_ref,
79 item->model->GetDeviceInfo().fieldValue,
80 item->model->GetTypeInfo().fieldValue ) );
81 }
82
83 // Special case for potentiometers because we don't have value ranges implemented yet.
84 if( item->model->GetType() == SIM_MODEL::TYPE::R_POT )
85 {
86 std::string valueStr = SIM_VALUE::ToSpice( item->model->GetTunerParam()->value );
87
88 if( valueStr != "" )
89 m_value = SPICE_VALUE( valueStr );
90 else
91 m_value = SPICE_VALUE( "0.5" );
92
93 m_min = SPICE_VALUE( 0 );
94 m_max = SPICE_VALUE( 1 );
95 }
96 else
97 {
99 m_min = SPICE_VALUE( 0.5 ) * m_value;
100 m_max = SPICE_VALUE( 2.0 ) * m_value;
101 }
102
103 m_minText->SetValue( m_min.ToOrigString() );
104 m_maxText->SetValue( m_max.ToOrigString() );
105
107 updateSlider();
108
109 Layout();
110}
111
112
114{
115 m_name->SetLabel( wxString::Format( _( "Tune %s" ), m_ref ) );
116}
117
118
119void TUNER_SLIDER::onESeries( wxCommandEvent& event )
120{
121 for( BITMAP_BUTTON* btn : { m_e24, m_e48, m_e96, m_e192 } )
122 {
123 if( btn != event.GetEventObject() )
124 btn->Check( false );
125 }
126
127 wxString oldValue = m_valueText->GetValue();
128
130
131 if( m_valueText->GetValue() != oldValue )
133
134 event.Skip();
135}
136
137
139{
140 // Get the value into the current range boundaries
141 if( aVal > m_max )
142 m_value = m_max;
143 else if( aVal < m_min )
144 m_value = m_min;
145 else
146 m_value = aVal;
147
149 updateSlider();
151
152 return true;
153}
154
155
157{
158 if( aVal >= m_max )
159 return false;
160
161 m_min = aVal;
162
163 if( m_value < aVal ) // Limit the current value
164 SetValue( aVal );
165
166 m_minText->SetValue( aVal.ToOrigString() );
167 updateSlider();
168
169 return true;
170}
171
172
174{
175 if( aVal <= m_min )
176 return false;
177
178 m_max = aVal;
179
180 if( m_value > aVal ) // Limit the current value
181 SetValue( aVal );
182
183 m_maxText->SetValue( aVal.ToOrigString() );
184 updateSlider();
185
186 return true;
187}
188
189
191{
192 wxQueueEvent( m_frame, new wxCommandEvent( EVT_SIM_UPDATE ) );
193}
194
195
197{
198 wxASSERT( m_max >= m_value && m_value >= m_min );
199 double value = ( ( m_value - m_min ) / ( m_max - m_min ) ).ToDouble();
200 m_slider->SetValue( KiROUND( value * 100.0 ) );
201}
202
203
205{
206 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,
207 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1 };
208
209 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,
210 1.13, 1.14, 1.15, 1.17, 1.18, 1.20, 1.21, 1.23, 1.24, 1.26,
211 1.27, 1.29, 1.30, 1.32, 1.33, 1.35, 1.37, 1.38, 1.40, 1.42,
212 1.43, 1.45, 1.47, 1.49, 1.50, 1.52, 1.54, 1.56, 1.58, 1.60,
213 1.62, 1.64, 1.65, 1.67, 1.69, 1.72, 1.74, 1.76, 1.78, 1.80,
214 1.82, 1.84, 1.87, 1.89, 1.91, 1.93, 1.96, 1.98, 2.00, 2.03,
215 2.05, 2.08, 2.10, 2.13, 2.15, 2.18, 2.21, 2.23, 2.26, 2.29,
216 2.32, 2.34, 2.37, 2.40, 2.43, 2.46, 2.49, 2.52, 2.55, 2.58,
217 2.61, 2.64, 2.67, 2.71, 2.74, 2.77, 2.80, 2.84, 2.87, 2.91,
218 2.94, 2.98, 3.01, 3.05, 3.09, 3.12, 3.16, 3.20, 3.24, 3.28,
219 3.32, 3.36, 3.40, 3.44, 3.48, 3.52, 3.57, 3.61, 3.65, 3.70,
220 3.74, 3.79, 3.83, 3.88, 3.92, 3.97, 4.02, 4.07, 4.12, 4.17,
221 4.22, 4.27, 4.32, 4.37, 4.42, 4.48, 4.53, 4.59, 4.64, 4.70,
222 4.75, 4.81, 4.87, 4.93, 4.99, 5.05, 5.11, 5.17, 5.23, 5.30,
223 5.36, 5.42, 5.49, 5.56, 5.62, 5.69, 5.76, 5.83, 5.90, 5.97,
224 6.04, 6.12, 6.19, 6.26, 6.34, 6.42, 6.49, 6.57, 6.65, 6.73,
225 6.81, 6.90, 6.98, 7.06, 7.15, 7.23, 7.32, 7.41, 7.50, 7.59,
226 7.68, 7.77, 7.87, 7.96, 8.06, 8.16, 8.25, 8.35, 8.45, 8.56,
227 8.66, 8.76, 8.87, 8.98, 9.09, 9.20, 9.31, 9.42, 9.53, 9.65,
228 9.76, 9.88 };
229
230 int precision = 3;
231 wxString prefix;
232 double value = m_value.ToNormalizedDouble( &prefix );
233
234 bool e_24 = m_e24->IsChecked();
235 bool e_extended = m_e48->IsChecked() || m_e96->IsChecked() || m_e192->IsChecked();
236
237 if( e_24 || e_extended )
238 {
239 std::vector<double> table;
240 table.reserve( 192 + 24 + 1 /* worst case */ );
241
242 if( e_extended )
243 {
244 int step = m_e48->IsChecked() ? 4 : m_e96->IsChecked() ? 2 : 1;
245
246 for( size_t ii = 0; ii < e192.size(); ii += step )
247 table.push_back( e192[ii] );
248 }
249
250 if( e_24 )
251 table.insert( table.end(), e24.begin(), e24.end() );
252
253 table.push_back( 10.0 );
254
255 std::sort( table.begin(), table.end() );
256 alg::remove_duplicates( table );
257
258 for( double decade : { 1.0, 10.0, 100.0 } )
259 {
260 for( size_t ii = 0; ii < table.size() - 1; ++ii )
261 {
262 if( value < ( table[ii] + table[ii+1] ) * decade / 2 )
263 {
264 precision = 0;
265
266 if( decade == 1.0 )
267 precision++;
268
269 if( e_extended && decade != 100.0 )
270 precision++;
271
272 m_valueText->SetValue( wxString::Format( wxT( "%.*f%s" ),
273 precision,
274 table[ii] * decade,
275 prefix ) );
276 return;
277 }
278 }
279 }
280 }
281
282 wxString valueStr = wxString::Format( wxT( "%.3f" ), value );
283 SPICE_VALUE::StripZeros( valueStr );
284 m_valueText->SetValue( valueStr + prefix );
285}
286
287
289{
290 try
291 {
292 SPICE_VALUE newMax( m_maxText->GetValue() );
293 SetMax( newMax );
294 }
295 catch( const KI_PARAM_ERROR& )
296 {
297 // Restore the previous value
298 m_maxText->SetValue( m_max.ToOrigString() );
299 }
300}
301
302
304{
305 try
306 {
307 SPICE_VALUE newCur( m_valueText->GetValue() );
308 SetValue( newCur );
309 }
310 catch( const KI_PARAM_ERROR& )
311 {
312 // Restore the previous value
313 m_valueText->SetValue( m_value.ToOrigString() );
314 }
315}
316
317
319{
320 try
321 {
322 SPICE_VALUE newMin( m_minText->GetValue() );
323 SetMin( newMin );
324 }
325 catch( const KI_PARAM_ERROR& )
326 {
327 // Restore the previous value
328 m_minText->SetValue( m_min.ToOrigString() );
329 }
330}
331
332
333void TUNER_SLIDER::onClose( wxCommandEvent& event )
334{
335 m_frame->RemoveTuner( this );
336}
337
338
339void TUNER_SLIDER::onSave( wxCommandEvent& event )
340{
342}
343
344
345void TUNER_SLIDER::onSliderScroll( wxScrollEvent& event )
346{
347 m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( m_slider->GetValue() / 100.0 );
349}
350
351
352void TUNER_SLIDER::onSliderChanged( wxScrollEvent& event )
353{
354 m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( m_slider->GetValue() / 100.0 );
357}
358
359
360void TUNER_SLIDER::onMaxKillFocus( wxFocusEvent& event )
361{
362 updateMax();
363 event.Skip(); // Mandatory in wxFocusEvent
364}
365
366
367void TUNER_SLIDER::onValueKillFocus( wxFocusEvent& event )
368{
369 updateValue();
370 event.Skip(); // Mandatory in wxFocusEvent
371}
372
373
374void TUNER_SLIDER::onMinKillFocus( wxFocusEvent& event )
375{
376 updateMin();
377 event.Skip(); // Mandatory in wxFocusEvent
378}
379
380
381void TUNER_SLIDER::onMaxTextEnter( wxCommandEvent& event )
382{
383 updateMax();
384 event.Skip(); // Mandatory in wxFocusEvent
385}
386
387
388void TUNER_SLIDER::onValueTextEnter( wxCommandEvent& event )
389{
390 updateValue();
391}
392
393
394void TUNER_SLIDER::onMinTextEnter( wxCommandEvent& event )
395{
396 updateMin();
397}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
Definition: bitmap_button.h:42
bool IsChecked() const
void SetIsSeparator()
Render button as a toolbar separator.
void SetIsCheckButton()
Setup the control as a two-state button (checked or unchecked).
void SetBitmap(const wxBitmapBundle &aBmp)
Set the bitmap shown when the button is enabled.
Hold a translatable error message and may be used when throwing exceptions containing a translated er...
Definition: ki_exception.h:46
const SPICE_ITEM * FindItem(const wxString &aRefName) const
Find and return the item corresponding to aRefName.
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:77
The SIMULATOR_FRAME_UI holds the main user-interface for running simulations.
void UpdateTunerValue(const SCH_SHEET_PATH &aSheetPath, const KIID &aSymbol, const wxString &aRef, const wxString &aValue)
Safely update a field of the associated symbol without dereferencing the symbol.
void RemoveTuner(TUNER_SLIDER *aTuner)
Remove an existing tuner.
const SPICE_CIRCUIT_MODEL * GetExporter() const
Return the netlist exporter object used for simulations.
virtual const PARAM * GetTunerParam() const
Definition: sim_model.h:484
DEVICE_INFO GetDeviceInfo() const
Definition: sim_model.h:460
INFO GetTypeInfo() const
Definition: sim_model.h:461
TYPE GetType() const
Definition: sim_model.h:464
static std::string ToSpice(const std::string &aString)
Definition: sim_value.cpp:419
Helper class to recognize Spice formatted values.
Definition: spice_value.h:56
double ToNormalizedDouble(wxString *aPrefix)
static void StripZeros(wxString &aString)
wxString ToOrigString() const
Return either a normal string or Spice format string, depending on the original value format.
Definition: spice_value.h:122
void SetBitmap(const wxBitmapBundle &aBmp)
Class TUNER_SLIDER_BASE.
wxTextCtrl * m_minText
STD_BITMAP_BUTTON * m_closeBtn
BITMAP_BUTTON * m_separator
wxTextCtrl * m_maxText
BITMAP_BUTTON * m_e96
wxTextCtrl * m_valueText
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)
void updateSlider()
void updateValue()
void onValueTextEnter(wxCommandEvent &event) override
void onMinKillFocus(wxFocusEvent &event) override
wxString m_ref
Definition: tuner_slider.h:107
void onValueKillFocus(wxFocusEvent &event) override
bool SetValue(const SPICE_VALUE &aVal)
void onSave(wxCommandEvent &event) override
TUNER_SLIDER(SIMULATOR_FRAME_UI *aPanel, wxWindow *aParent, const SCH_SHEET_PATH &aSheetPath, SCH_SYMBOL *aSymbol)
wxString GetSymbolRef() const
Definition: tuner_slider.h:49
SPICE_VALUE m_max
Definition: tuner_slider.h:110
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
Definition: tuner_slider.h:106
void onMinTextEnter(wxCommandEvent &event) override
void onClose(wxCommandEvent &event) override
SIMULATOR_FRAME_UI * m_frame
Definition: tuner_slider.h:113
SPICE_VALUE m_value
Definition: tuner_slider.h:111
SPICE_VALUE m_min
Definition: tuner_slider.h:109
void onSliderChanged(wxScrollEvent &event) override
void ShowChangedLanguage()
#define _(s)
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition: kicad_algo.h:183
std::string value
Definition: sim_model.h:400
const SIM_MODEL * model