Add transformation function for characteristic curves of tuners
This commit is contained in:
parent
f004665df8
commit
8167c69508
|
@ -142,7 +142,7 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
|
|||
m_splitterPlotAndConsole->SetMinimumPaneSize( 50 );
|
||||
|
||||
m_plotPanel = new wxPanel( m_splitterPlotAndConsole, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
m_plotPanel->SetMinSize( wxSize( -1,200 ) );
|
||||
m_plotPanel->SetMinSize( wxSize( -1,250 ) );
|
||||
|
||||
m_sizerPlot = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
|
|
|
@ -686,7 +686,7 @@
|
|||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size">-1,200</property>
|
||||
<property name="minimum_size">-1,250</property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_plotPanel</property>
|
||||
<property name="pane_border">1</property>
|
||||
|
|
|
@ -31,6 +31,132 @@
|
|||
#include <template_fieldnames.h>
|
||||
#include <sim/netlist_exporter_pspice_sim.h>
|
||||
|
||||
#include <cmath> // log log1p expm1
|
||||
#include <complex> // norm
|
||||
|
||||
|
||||
// characteristic curves (default: 0B Lin)
|
||||
static const struct { double m_law, m_mid; } CURVES[] =
|
||||
{
|
||||
// same order as choices in m_curve
|
||||
{ 1.00, 0.10 }, // 10A Log
|
||||
{ 1.00, 0.15 }, // 15A Log
|
||||
{ 0.90, 0.13 }, // 15A Log S
|
||||
{ 0.00, 0.10 }, // 10C Rev Log
|
||||
{ 0.00, 0.15 }, // 15C Rev Log
|
||||
{ 0.10, 0.13 }, // 15C Rev Log S
|
||||
{ 0.50, 0.50 }, // 0B Lin
|
||||
{ 0.50, 0.15 }, // 4B S-Curve
|
||||
{ 0.50, 0.10 }, // 5B S-Curve
|
||||
{ 0.50, 0.00 } // Switch
|
||||
};
|
||||
|
||||
template <typename T, int S>
|
||||
static inline int arraysize( const T (&v)[S] ) { return S; }
|
||||
|
||||
|
||||
/**
|
||||
* Transform ratio according to linear, logarithmic or reverse logarithmic laws
|
||||
* (characteristic curve or taper) of rotary or slide potentiometer (pot or fader).
|
||||
*
|
||||
* Parameters corresponding to *IEC 60393-1:2008* and *JIS C 5260-1* code letters:
|
||||
*
|
||||
* | @p aLaw | @p aMid | Code | Resistance Law (Taper)
|
||||
* | ------: | ------: | ---: | :---------------------
|
||||
* | 1.00 | 0.10 | 10A | CW logarithmic
|
||||
* | ^ | 0.15 | 15A | CW logarithmic (audio)
|
||||
* | 0.90 | 0.13 | ^ | CW logarithmic (high-end audio)
|
||||
* | 0.00 | 0.10 | 10C | CCW/reverse logarithmic
|
||||
* | ^ | 0.15 | 15C | CCW/reverse logarithmic (reverse audio)
|
||||
* | 0.10 | 0.13 | ^ | CCW/reverse logarithmic (high-end reverse audio)
|
||||
* | 0.50 | 0.50 | 0B | (ideal) linear
|
||||
* | ^ | 0.15 | 4B | symmetric (audio S-curve)
|
||||
* | ^ | 0.10 | 5B | symmetric (S-curve)
|
||||
* | ^ | 0.00 | — | switch
|
||||
*
|
||||
* Standards code letters cross-reference:
|
||||
*
|
||||
* | IEC 60393-1:2008 | IEC 60393-1:1989 | MIL-R-94 | Resistance Law
|
||||
* | ----------------: | :--------------: | :------: | :-------------
|
||||
* | 0B | A | A | linear
|
||||
* | 10A | B | C | logarithmic
|
||||
* | 15A | ^ | — | ^
|
||||
* | 10C | C | F | reverse logarithmic
|
||||
* | 15C | ^ | — | ^
|
||||
*
|
||||
* **Logarithmic Law** is for *levels* (logarithmic units) and is actually an exponential curve.
|
||||
* **Reverse** refers to a reverse-mounted resistive element or shaft on a potentiometer
|
||||
* (resulting in a reflected curve). An **S-curve** is a curve joined to its (scaled) reflection,
|
||||
* and *may* be symmetric or linear. **Inverse** refers to the mathematical inverse of a function.
|
||||
*
|
||||
* @tparam F is a floating point type.
|
||||
* @param aRatio is the input (travel) ratio or moving contact (wiper) position, from
|
||||
* 0%/CCW/left (0) through 50%/mid-travel/center (½) to 100%/CW/right (1).
|
||||
* @param aMid is the logarithmic laws' output ratio at 50%/mid-travel/center (½)
|
||||
* input ratio.
|
||||
* @param aLaw is the (resistance) law, interpolating from *reverse logarithmic* (0)
|
||||
* through *symmetric/linear* (½) to *logarithmic* (1).
|
||||
* @param aInverse swaps input and output ratios (inverse function, where possible),
|
||||
* if @c true.
|
||||
* @return the output (resistance or voltage) ratio in [0, 1].
|
||||
*/
|
||||
template <typename F>
|
||||
static F taper( F aRatio, F aMid = 0.5, F aLaw = 1.0, bool aInverse = false )
|
||||
{
|
||||
// clamp to [0, 1] and short-cut
|
||||
if( aRatio <= 0 )
|
||||
return 0;
|
||||
if( aRatio >= 1 )
|
||||
return 1;
|
||||
|
||||
// short-cut for ideal linear or at S-curve inflection point
|
||||
if( aMid == 0.5 || aRatio == aLaw )
|
||||
return aRatio;
|
||||
|
||||
F t = aRatio;
|
||||
|
||||
// clamp to [0, 1] and short-cut at (non-invertible) limits
|
||||
if( aMid <= 0 )
|
||||
t = aInverse ? 1 : 0;
|
||||
else if( aMid >= 1 )
|
||||
t = aInverse ? 0 : 1;
|
||||
else
|
||||
{
|
||||
// clamp, and reflect and/or scale for reverse…symmetric…normal laws
|
||||
if( aLaw >= 1 )
|
||||
t = t;
|
||||
else if( aLaw <= 0 )
|
||||
t = 1-t;
|
||||
else if( aRatio <= aLaw )
|
||||
t = t / aLaw;
|
||||
else
|
||||
t = ( 1-t ) / ( 1-aLaw );
|
||||
|
||||
// scaling factors for domain and range in [0, 1]
|
||||
F a = std::norm( 1 - 1/aMid );
|
||||
F b = std::log( a );
|
||||
F c = a - 1;
|
||||
|
||||
// scaling: a = (1 - 1/m)²
|
||||
// log law: (aᵗ - 1) / (a - 1)
|
||||
// inverse: logₐ(1 + t (a - 1))
|
||||
t = aInverse ? std::log1p( t * c ) / b : std::expm1( t * b ) / c;
|
||||
}
|
||||
|
||||
// clamp, and scale and/or reflect for reverse…symmetric…normal laws
|
||||
if( aLaw >= 1 )
|
||||
t = t;
|
||||
else if( aLaw <= 0 )
|
||||
t = 1 - t;
|
||||
else if( aRatio <= aLaw )
|
||||
t = t * aLaw;
|
||||
else
|
||||
t = 1 - t * ( 1-aLaw );
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
TUNER_SLIDER::TUNER_SLIDER( SIM_PLOT_FRAME* aFrame, wxWindow* aParent, SCH_SYMBOL* aSymbol ) :
|
||||
TUNER_SLIDER_BASE( aParent ),
|
||||
m_symbol( aSymbol ),
|
||||
|
@ -142,7 +268,12 @@ void TUNER_SLIDER::updateSlider()
|
|||
{
|
||||
assert( m_max >= m_value && m_value >= m_min );
|
||||
|
||||
m_slider->SetValue( ( ( m_value - m_min ) / ( m_max - m_min ) ).ToDouble() * 100.0 );
|
||||
int choice = m_curve->GetSelection();
|
||||
wxCHECK( choice >= 0 && choice < arraysize( CURVES ), /*void*/ );
|
||||
|
||||
double ratio = ( ( m_value - m_min ) / ( m_max - m_min ) ).ToDouble();
|
||||
double travel = taper( ratio, CURVES[choice].m_mid, CURVES[choice].m_law, true );
|
||||
m_slider->SetValue( KiROUND( travel * 100.0 ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -213,13 +344,24 @@ void TUNER_SLIDER::onSave( wxCommandEvent& event )
|
|||
|
||||
void TUNER_SLIDER::onSliderChanged( wxScrollEvent& event )
|
||||
{
|
||||
m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( m_slider->GetValue() / 100.0 );
|
||||
int choice = m_curve->GetSelection();
|
||||
wxCHECK( choice >= 0 && choice < arraysize( CURVES ), /*void*/ );
|
||||
|
||||
double travel = m_slider->GetValue() / 100.0;
|
||||
double ratio = taper( travel, CURVES[choice].m_mid, CURVES[choice].m_law, false );
|
||||
m_value = m_min + ( m_max - m_min ) * SPICE_VALUE( ratio );
|
||||
updateValueText();
|
||||
updateComponentValue();
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
|
||||
void TUNER_SLIDER::onCurveChoice( wxCommandEvent& event )
|
||||
{
|
||||
updateValue();
|
||||
}
|
||||
|
||||
|
||||
void TUNER_SLIDER::onMaxKillFocus( wxFocusEvent& event )
|
||||
{
|
||||
updateMax();
|
||||
|
|
|
@ -85,6 +85,7 @@ private:
|
|||
void onClose( wxCommandEvent& event ) override;
|
||||
void onSave( wxCommandEvent& event ) override;
|
||||
void onSliderChanged( wxScrollEvent& event ) override;
|
||||
void onCurveChoice( wxCommandEvent& event ) override;
|
||||
|
||||
void onMaxKillFocus( wxFocusEvent& event ) override;
|
||||
void onValueKillFocus( wxFocusEvent& event ) override;
|
||||
|
|
|
@ -63,6 +63,14 @@ TUNER_SLIDER_BASE::TUNER_SLIDER_BASE( wxWindow* parent, wxWindowID id, const wxP
|
|||
|
||||
bSizerMain->Add( bSizerMiddle, 1, wxEXPAND, 5 );
|
||||
|
||||
wxString m_curveChoices[] = { _("10A Log"), _("15A Log"), _("15A Log S"), _("10C Rev Log"), _("15C Rev Log"), _("15C Rev Log S"), _("0B Lin"), _("4B S-Curve"), _("5B S-Curve"), _("Switch") };
|
||||
int m_curveNChoices = sizeof( m_curveChoices ) / sizeof( wxString );
|
||||
m_curve = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_curveNChoices, m_curveChoices, 0 );
|
||||
m_curve->SetSelection( 6 );
|
||||
m_curve->SetToolTip( _("Characteristic Curve") );
|
||||
|
||||
bSizerMain->Add( m_curve, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
m_saveBtn = new wxButton( this, wxID_ANY, _("Save"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerMain->Add( m_saveBtn, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
|
@ -87,6 +95,7 @@ TUNER_SLIDER_BASE::TUNER_SLIDER_BASE( wxWindow* parent, wxWindowID id, const wxP
|
|||
m_valueText->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( TUNER_SLIDER_BASE::onValueTextEnter ), NULL, this );
|
||||
m_minText->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( TUNER_SLIDER_BASE::onMinKillFocus ), NULL, this );
|
||||
m_minText->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( TUNER_SLIDER_BASE::onMinTextEnter ), NULL, this );
|
||||
m_curve->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( TUNER_SLIDER_BASE::onCurveChoice ), NULL, this );
|
||||
m_saveBtn->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( TUNER_SLIDER_BASE::onSave ), NULL, this );
|
||||
}
|
||||
|
||||
|
@ -109,6 +118,7 @@ TUNER_SLIDER_BASE::~TUNER_SLIDER_BASE()
|
|||
m_valueText->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( TUNER_SLIDER_BASE::onValueTextEnter ), NULL, this );
|
||||
m_minText->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( TUNER_SLIDER_BASE::onMinKillFocus ), NULL, this );
|
||||
m_minText->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( TUNER_SLIDER_BASE::onMinTextEnter ), NULL, this );
|
||||
m_curve->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( TUNER_SLIDER_BASE::onCurveChoice ), NULL, this );
|
||||
m_saveBtn->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( TUNER_SLIDER_BASE::onSave ), NULL, this );
|
||||
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<property name="minimum_size"></property>
|
||||
<property name="name">TUNER_SLIDER_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">126,283</property>
|
||||
<property name="size">126,322</property>
|
||||
<property name="subclass"></property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
|
@ -503,6 +503,71 @@
|
|||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxChoice" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="choices">"10A Log" "15A Log" "15A Log S" "10C Rev Log" "15C Rev Log" "15C Rev Log S" "0B Lin" "4B S-Curve" "5B S-Curve" "Switch"</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_curve</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="selection">6</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip">Characteristic Curve</property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnChoice">onCurveChoice</event>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL</property>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <wx/sizer.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -42,6 +43,7 @@ class TUNER_SLIDER_BASE : public wxPanel
|
|||
wxTextCtrl* m_maxText;
|
||||
wxTextCtrl* m_valueText;
|
||||
wxTextCtrl* m_minText;
|
||||
wxChoice* m_curve;
|
||||
wxButton* m_saveBtn;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
|
@ -53,12 +55,13 @@ class TUNER_SLIDER_BASE : public wxPanel
|
|||
virtual void onValueTextEnter( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onMinKillFocus( wxFocusEvent& event ) { event.Skip(); }
|
||||
virtual void onMinTextEnter( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onCurveChoice( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onSave( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
TUNER_SLIDER_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 126,283 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
|
||||
TUNER_SLIDER_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 126,322 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
|
||||
|
||||
~TUNER_SLIDER_BASE();
|
||||
|
||||
|
|
Loading…
Reference in New Issue