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