KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <maciej.suminski@cern.ch>
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#if _WIN32
55 // BORDER_RAISED/SUNKEN look pretty on every platform but Windows
56 long style = GetWindowStyleFlag();
57 style &= ~wxBORDER_MASK;
58 style |= wxBORDER_SIMPLE;
59 SetWindowStyleFlag( style );
60#endif // _WIN32
61
62 const SPICE_ITEM* item = m_frame->GetExporter()->FindItem( m_ref );
63
64 if( !item )
65 throw KI_PARAM_ERROR( wxString::Format( _( "%s not found" ), m_ref ) );
66
67 m_name->SetLabel( wxString::Format( _( "Tune %s" ), m_ref ) );
68 m_closeBtn->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
69
70 m_e24->SetBitmap( KiBitmapBundle( BITMAPS::e_24 ) );
73 m_e48->SetBitmap( KiBitmapBundle( BITMAPS::e_48 ) );
75 m_e96->SetBitmap( KiBitmapBundle( BITMAPS::e_96 ) );
77 m_e192->SetBitmap( KiBitmapBundle( BITMAPS::e_192 ) );
79
80 const SIM_MODEL::PARAM* tunerParam = item->model->GetTunerParam();
81
82 if( !tunerParam )
83 {
84 throw KI_PARAM_ERROR( wxString::Format( _( "%s has simulation model of type '%s %s'.\n\n"
85 "Only passvie R, L, C models and voltage and "
86 "current sources may be tuned." ),
87 m_ref,
88 item->model->GetDeviceInfo().fieldValue,
89 item->model->GetTypeInfo().fieldValue ) );
90 }
91
92 // Special case for potentiometers because we don't have value ranges implemented yet.
93 if( item->model->GetType() == SIM_MODEL::TYPE::R_POT )
94 {
95 std::string valueStr = SIM_VALUE::ToSpice( item->model->GetTunerParam()->value );
96
97 if( valueStr != "" )
98 m_value = SPICE_VALUE( valueStr );
99 else
100 m_value = SPICE_VALUE( "0.5" );
101
102 m_min = SPICE_VALUE( 0 );
103 m_max = SPICE_VALUE( 1 );
104 }
105 else
106 {
108 m_min = SPICE_VALUE( 0.5 ) * m_value;
109 m_max = SPICE_VALUE( 2.0 ) * m_value;
110 }
111
112 m_minText->SetValue( m_min.ToOrigString() );
113 m_maxText->SetValue( m_max.ToOrigString() );
114
116 updateSlider();
117
118 Layout();
119}
120
121
123{
124 m_name->SetLabel( wxString::Format( _( "Tune %s" ), m_ref ) );
125}
126
127
128void TUNER_SLIDER::onESeries( wxCommandEvent& event )
129{
130 for( BITMAP_BUTTON* btn : { m_e24, m_e48, m_e96, m_e192 } )
131 {
132 if( btn != event.GetEventObject() )
133 btn->Check( false );
134 }
135
136 wxString oldValue = m_valueText->GetValue();
137
139
140 if( m_valueText->GetValue() != oldValue )
142
143 event.Skip();
144}
145
146
148{
149 // Get the value into the current range boundaries
150 if( aVal > m_max )
151 m_value = m_max;
152 else if( aVal < m_min )
153 m_value = m_min;
154 else
155 m_value = aVal;
156
158 updateSlider();
160
161 return true;
162}
163
164
166{
167 if( aVal >= m_max )
168 return false;
169
170 m_min = aVal;
171
172 if( m_value < aVal ) // Limit the current value
173 SetValue( aVal );
174
175 m_minText->SetValue( aVal.ToOrigString() );
176 updateSlider();
177
178 return true;
179}
180
181
183{
184 if( aVal <= m_min )
185 return false;
186
187 m_max = aVal;
188
189 if( m_value > aVal ) // Limit the current value
190 SetValue( aVal );
191
192 m_maxText->SetValue( aVal.ToOrigString() );
193 updateSlider();
194
195 return true;
196}
197
198
200{
201 wxQueueEvent( m_frame, new wxCommandEvent( EVT_SIM_UPDATE ) );
202}
203
204
206{
207 wxASSERT( m_max >= m_value && m_value >= m_min );
208 double value = ( ( m_value - m_min ) / ( m_max - m_min ) ).ToDouble();
209 m_slider->SetValue( KiROUND( value * 100.0 ) );
210}
211
212
214{
215 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,
216 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1 };
217
218 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,
219 1.13, 1.14, 1.15, 1.17, 1.18, 1.20, 1.21, 1.23, 1.24, 1.26,
220 1.27, 1.29, 1.30, 1.32, 1.33, 1.35, 1.37, 1.38, 1.40, 1.42,
221 1.43, 1.45, 1.47, 1.49, 1.50, 1.52, 1.54, 1.56, 1.58, 1.60,
222 1.62, 1.64, 1.65, 1.67, 1.69, 1.72, 1.74, 1.76, 1.78, 1.80,
223 1.82, 1.84, 1.87, 1.89, 1.91, 1.93, 1.96, 1.98, 2.00, 2.03,
224 2.05, 2.08, 2.10, 2.13, 2.15, 2.18, 2.21, 2.23, 2.26, 2.29,
225 2.32, 2.34, 2.37, 2.40, 2.43, 2.46, 2.49, 2.52, 2.55, 2.58,
226 2.61, 2.64, 2.67, 2.71, 2.74, 2.77, 2.80, 2.84, 2.87, 2.91,
227 2.94, 2.98, 3.01, 3.05, 3.09, 3.12, 3.16, 3.20, 3.24, 3.28,
228 3.32, 3.36, 3.40, 3.44, 3.48, 3.52, 3.57, 3.61, 3.65, 3.70,
229 3.74, 3.79, 3.83, 3.88, 3.92, 3.97, 4.02, 4.07, 4.12, 4.17,
230 4.22, 4.27, 4.32, 4.37, 4.42, 4.48, 4.53, 4.59, 4.64, 4.70,
231 4.75, 4.81, 4.87, 4.93, 4.99, 5.05, 5.11, 5.17, 5.23, 5.30,
232 5.36, 5.42, 5.49, 5.56, 5.62, 5.69, 5.76, 5.83, 5.90, 5.97,
233 6.04, 6.12, 6.19, 6.26, 6.34, 6.42, 6.49, 6.57, 6.65, 6.73,
234 6.81, 6.90, 6.98, 7.06, 7.15, 7.23, 7.32, 7.41, 7.50, 7.59,
235 7.68, 7.77, 7.87, 7.96, 8.06, 8.16, 8.25, 8.35, 8.45, 8.56,
236 8.66, 8.76, 8.87, 8.98, 9.09, 9.20, 9.31, 9.42, 9.53, 9.65,
237 9.76, 9.88 };
238
239 int precision = 3;
240 wxString prefix;
241 double value = m_value.ToNormalizedDouble( &prefix );
242
243 bool e_24 = m_e24->IsChecked();
244 bool e_extended = m_e48->IsChecked() || m_e96->IsChecked() || m_e192->IsChecked();
245
246 if( e_24 || e_extended )
247 {
248 std::vector<double> table;
249 table.reserve( 192 + 24 + 1 /* worst case */ );
250
251 if( e_extended )
252 {
253 int step = m_e48->IsChecked() ? 4 : m_e96->IsChecked() ? 2 : 1;
254
255 for( size_t ii = 0; ii < e192.size(); ii += step )
256 table.push_back( e192[ii] );
257 }
258
259 if( e_24 )
260 table.insert( table.end(), e24.begin(), e24.end() );
261
262 table.push_back( 10.0 );
263
264 std::sort( table.begin(), table.end() );
266
267 for( double decade : { 1.0, 10.0, 100.0 } )
268 {
269 for( size_t ii = 0; ii < table.size() - 1; ++ii )
270 {
271 if( value < ( table[ii] + table[ii+1] ) * decade / 2 )
272 {
273 precision = 0;
274
275 if( decade == 1.0 )
276 precision++;
277
278 if( e_extended && decade != 100.0 )
279 precision++;
280
281 m_valueText->SetValue( wxString::Format( wxT( "%.*f%s" ),
282 precision,
283 table[ii] * decade,
284 prefix ) );
285 return;
286 }
287 }
288 }
289 }
290
291 wxString valueStr = wxString::Format( wxT( "%.3f" ), value );
292 SPICE_VALUE::StripZeros( valueStr );
293 m_valueText->SetValue( valueStr + prefix );
294}
295
296
298{
299 try
300 {
301 SPICE_VALUE newMax( m_maxText->GetValue() );
302 SetMax( newMax );
303 }
304 catch( const KI_PARAM_ERROR& )
305 {
306 // Restore the previous value
307 m_maxText->SetValue( m_max.ToOrigString() );
308 }
309}
310
311
313{
314 try
315 {
316 SPICE_VALUE newCur( m_valueText->GetValue() );
317 SetValue( newCur );
318 }
319 catch( const KI_PARAM_ERROR& )
320 {
321 // Restore the previous value
322 m_valueText->SetValue( m_value.ToOrigString() );
323 }
324}
325
326
328{
329 try
330 {
331 SPICE_VALUE newMin( m_minText->GetValue() );
332 SetMin( newMin );
333 }
334 catch( const KI_PARAM_ERROR& )
335 {
336 // Restore the previous value
337 m_minText->SetValue( m_min.ToOrigString() );
338 }
339}
340
341
342void TUNER_SLIDER::onClose( wxCommandEvent& event )
343{
344 m_frame->RemoveTuner( this );
345}
346
347
348void TUNER_SLIDER::onSave( wxCommandEvent& event )
349{
351}
352
353
354void TUNER_SLIDER::onSliderScroll( wxScrollEvent& event )
355{
356 m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( m_slider->GetValue() / 100.0 );
358}
359
360
361void TUNER_SLIDER::onSliderChanged( wxScrollEvent& event )
362{
363 m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( m_slider->GetValue() / 100.0 );
366}
367
368
369void TUNER_SLIDER::onMaxKillFocus( wxFocusEvent& event )
370{
371 updateMax();
372 event.Skip(); // Mandatory in wxFocusEvent
373}
374
375
376void TUNER_SLIDER::onValueKillFocus( wxFocusEvent& event )
377{
378 updateValue();
379 event.Skip(); // Mandatory in wxFocusEvent
380}
381
382
383void TUNER_SLIDER::onMinKillFocus( wxFocusEvent& event )
384{
385 updateMin();
386 event.Skip(); // Mandatory in wxFocusEvent
387}
388
389
390void TUNER_SLIDER::onMaxTextEnter( wxCommandEvent& event )
391{
392 updateMax();
393 event.Skip(); // Mandatory in wxFocusEvent
394}
395
396
397void TUNER_SLIDER::onValueTextEnter( wxCommandEvent& event )
398{
399 updateValue();
400}
401
402
403void TUNER_SLIDER::onMinTextEnter( wxCommandEvent& event )
404{
405 updateMin();
406}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
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:75
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:477
DEVICE_INFO GetDeviceInfo() const
Definition: sim_model.h:453
INFO GetTypeInfo() const
Definition: sim_model.h:454
TYPE GetType() const
Definition: sim_model.h:457
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