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