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