1 /*
2 * guide_algorithm_ra.cpp
3 * PHD Guiding
4 *
5 * Created by Bret McKee
6 * Copyright (c) 2012 Bret McKee
7 * All rights reserved.
8 *
9 * Based upon work by Craig Stark.
10 * Copyright (c) 2006-2010 Craig Stark.
11 * All rights reserved.
12 *
13 * This source code is distributed under the following "BSD" license
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are met:
16 * Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * Neither the name of Bret McKee, Dad Dog Development,
22 * Craig Stark, Stark Labs nor the names of its
23 * contributors may be used to endorse or promote products derived from
24 * this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 */
39
40 #include "phd.h"
41
42 static const double DefaultMinMove = 0.2;
43 static const double DefaultHysteresis = 0.1;
44 static const double DefaultAggression = 0.7;
45 static const double MaxAggression = 2.0;
46 static const double MaxHysteresis = 0.99;
47
GuideAlgorithmHysteresis(Mount * pMount,GuideAxis axis)48 GuideAlgorithmHysteresis::GuideAlgorithmHysteresis(Mount *pMount, GuideAxis axis)
49 : GuideAlgorithm(pMount, axis)
50 {
51 wxString configPath = GetConfigPath();
52
53 double minMove = pConfig->Profile.GetDouble(configPath + "/minMove", DefaultMinMove);
54 SetMinMove(minMove);
55
56 double hysteresis = pConfig->Profile.GetDouble(configPath + "/hysteresis", DefaultHysteresis);
57 SetHysteresis(hysteresis);
58
59 double aggression = pConfig->Profile.GetDouble(configPath + "/aggression", DefaultAggression);
60 SetAggression(aggression);
61
62 reset();
63 }
64
~GuideAlgorithmHysteresis(void)65 GuideAlgorithmHysteresis::~GuideAlgorithmHysteresis(void)
66 {
67 }
68
Algorithm() const69 GUIDE_ALGORITHM GuideAlgorithmHysteresis::Algorithm() const
70 {
71 return GUIDE_ALGORITHM_HYSTERESIS;
72 }
reset(void)73 void GuideAlgorithmHysteresis::reset(void)
74 {
75 m_lastMove = 0;
76 }
77
result(double input)78 double GuideAlgorithmHysteresis::result(double input)
79 {
80 double dReturn = (1.0 - m_hysteresis) * input + m_hysteresis * m_lastMove;
81
82 dReturn *= m_aggression;
83
84 if (fabs(input) < m_minMove)
85 {
86 dReturn = 0.0;
87 }
88
89 m_lastMove = dReturn;
90
91 Debug.Write(wxString::Format("GuideAlgorithmHysteresis::Result() returns %.2f from input %.2f\n", dReturn, input));
92
93 return dReturn;
94 }
95
SetMinMove(double minMove)96 bool GuideAlgorithmHysteresis::SetMinMove(double minMove)
97 {
98 bool bError = false;
99
100 try
101 {
102 if (minMove < 0.0)
103 {
104 throw ERROR_INFO("invalid minMove");
105 }
106
107 m_minMove = minMove;
108
109 }
110 catch (const wxString& Msg)
111 {
112 POSSIBLY_UNUSED(Msg);
113 bError = true;
114 m_minMove = DefaultMinMove;
115 }
116
117 pConfig->Profile.SetDouble(GetConfigPath() + "/minMove", m_minMove);
118
119 return bError;
120 }
121
SetHysteresis(double hysteresis)122 bool GuideAlgorithmHysteresis::SetHysteresis(double hysteresis)
123 {
124 bool bError = false;
125
126 try
127 {
128 if (hysteresis < 0.0 || hysteresis > MaxHysteresis)
129 {
130 throw ERROR_INFO("invalid hysteresis");
131 }
132
133 m_hysteresis = hysteresis;
134
135 }
136 catch (const wxString& Msg)
137 {
138 POSSIBLY_UNUSED(Msg);
139 bError = true;
140 m_hysteresis = wxMin(wxMax(hysteresis, 0.0), MaxHysteresis);
141 }
142
143 pConfig->Profile.SetDouble(GetConfigPath() + "/hysteresis", m_hysteresis);
144
145 return bError;
146 }
147
SetAggression(double aggression)148 bool GuideAlgorithmHysteresis::SetAggression(double aggression)
149 {
150 bool bError = false;
151
152 try
153 {
154 if (aggression < 0.0 || aggression > MaxAggression)
155 {
156 throw ERROR_INFO("invalid aggression");
157 }
158
159 m_aggression = aggression;
160 }
161 catch (const wxString& Msg)
162 {
163 POSSIBLY_UNUSED(Msg);
164 bError = true;
165 m_aggression = DefaultAggression;
166 }
167
168 m_lastMove = 0.0;
169 pConfig->Profile.SetDouble(GetConfigPath() + "/aggression", m_aggression);
170
171 return bError;
172 }
173
GetSettingsSummary() const174 wxString GuideAlgorithmHysteresis::GetSettingsSummary() const
175 {
176 // return a loggable summary of current mount settings
177 return wxString::Format("Hysteresis = %.3f, Aggression = %.3f, Minimum move = %.3f\n",
178 GetHysteresis(),
179 GetAggression(),
180 GetMinMove()
181 );
182 }
183
GetParamNames(wxArrayString & names) const184 void GuideAlgorithmHysteresis::GetParamNames(wxArrayString& names) const
185 {
186 names.push_back("minMove");
187 names.push_back("hysteresis");
188 names.push_back("aggression");
189 }
190
GetParam(const wxString & name,double * val) const191 bool GuideAlgorithmHysteresis::GetParam(const wxString& name, double *val) const
192 {
193 bool ok = true;
194
195 if (name == "minMove")
196 *val = GetMinMove();
197 else if (name == "hysteresis")
198 *val = GetHysteresis();
199 else if (name == "aggression")
200 *val = GetAggression();
201 else
202 ok = false;
203
204 return ok;
205 }
206
SetParam(const wxString & name,double val)207 bool GuideAlgorithmHysteresis::SetParam(const wxString& name, double val)
208 {
209 bool err;
210
211 if (name == "minMove")
212 err = SetMinMove(val);
213 else if (name == "hysteresis")
214 err = SetHysteresis(val);
215 else if (name == "aggression")
216 err = SetAggression(val);
217 else
218 err = true;
219
220 return !err;
221 }
222
GetConfigDialogPane(wxWindow * pParent)223 ConfigDialogPane *GuideAlgorithmHysteresis::GetConfigDialogPane(wxWindow *pParent)
224 {
225 return new GuideAlgorithmHysteresisConfigDialogPane(pParent, this);
226 }
227
228 GuideAlgorithmHysteresis::
229 GuideAlgorithmHysteresisConfigDialogPane::
GuideAlgorithmHysteresisConfigDialogPane(wxWindow * pParent,GuideAlgorithmHysteresis * pGuideAlgorithm)230 GuideAlgorithmHysteresisConfigDialogPane(wxWindow *pParent, GuideAlgorithmHysteresis *pGuideAlgorithm)
231 : ConfigDialogPane(_("Hysteresis Guide Algorithm"), pParent)
232 {
233 int width;
234
235 m_pGuideAlgorithm = pGuideAlgorithm;
236
237 width = StringWidth(_T("000"));
238 m_pHysteresis = pFrame->MakeSpinCtrl(pParent, wxID_ANY,_T(""), wxDefaultPosition,
239 wxSize(width, -1), wxSP_ARROW_KEYS, 0.0, MaxHysteresis * 100.0, 0.0, _T("Hysteresis"));
240
241 DoAdd(_("Hysteresis"), m_pHysteresis,
242 wxString::Format(_("How much history of previous guide pulses should be applied\nDefault = %.f%%, increase to smooth out guiding commands"), DefaultHysteresis * 100.0));
243
244 width = StringWidth(_T("000"));
245 m_pAggression = pFrame->MakeSpinCtrl(pParent, wxID_ANY, _T(" "), wxDefaultPosition,
246 wxSize(width, -1), wxSP_ARROW_KEYS, 0.0, MaxAggression * 100.0, 0.0, _T("Aggressiveness"));
247
248 DoAdd(_("Aggressiveness"), m_pAggression,
249 wxString::Format(_("What percentage of the computed correction should be applied? Default = %.f%%, adjust if responding too much or too slowly"), DefaultAggression * 100.0));
250
251 width = StringWidth(_T("00.00"));
252 m_pMinMove = pFrame->MakeSpinCtrlDouble(pParent, wxID_ANY, _T(" "), wxDefaultPosition,
253 wxSize(width, -1), wxSP_ARROW_KEYS, 0.0, 20.0, 0.0, 0.01, _T("MinMove"));
254 m_pMinMove->SetDigits(2);
255
256 DoAdd(_("Minimum Move (pixels)"), m_pMinMove,
257 wxString::Format(_("How many (fractional) pixels must the star move to trigger a guide pulse? \n"
258 "If camera is binned, this is a fraction of the binned pixel size. Default = %.2f"), DefaultMinMove));
259 }
260
261 GuideAlgorithmHysteresis::
262 GuideAlgorithmHysteresisConfigDialogPane::
~GuideAlgorithmHysteresisConfigDialogPane(void)263 ~GuideAlgorithmHysteresisConfigDialogPane(void)
264 {
265 }
266
267 void GuideAlgorithmHysteresis::
268 GuideAlgorithmHysteresisConfigDialogPane::
LoadValues(void)269 LoadValues(void)
270 {
271 m_pHysteresis->SetValue(100.0 * m_pGuideAlgorithm->GetHysteresis());
272 m_pAggression->SetValue(100.0 * m_pGuideAlgorithm->GetAggression());
273 m_pMinMove->SetValue(m_pGuideAlgorithm->GetMinMove());
274 }
275
276 void GuideAlgorithmHysteresis::
277 GuideAlgorithmHysteresisConfigDialogPane::
UnloadValues(void)278 UnloadValues(void)
279 {
280 m_pGuideAlgorithm->SetHysteresis(m_pHysteresis->GetValue() / 100.0);
281 m_pGuideAlgorithm->SetAggression(m_pAggression->GetValue() / 100.0);
282 m_pGuideAlgorithm->SetMinMove(m_pMinMove->GetValue());
283 }
284
285 void GuideAlgorithmHysteresis::
OnImageScaleChange()286 GuideAlgorithmHysteresisConfigDialogPane::OnImageScaleChange()
287 {
288 GuideAlgorithm::AdjustMinMoveSpinCtrl(m_pMinMove);
289 }
290
291 void GuideAlgorithmHysteresis::
EnableDecControls(bool enable)292 GuideAlgorithmHysteresisConfigDialogPane::EnableDecControls(bool enable)
293 {
294 m_pAggression->Enable(enable);
295 m_pMinMove->Enable(enable);
296 m_pHysteresis->Enable(enable);
297 }
298
GetGraphControlPane(wxWindow * pParent,const wxString & label)299 GraphControlPane *GuideAlgorithmHysteresis::GetGraphControlPane(wxWindow *pParent, const wxString& label)
300 {
301 return new GuideAlgorithmHysteresisGraphControlPane(pParent, this, label);
302 }
303
304 GuideAlgorithmHysteresis::
305 GuideAlgorithmHysteresisGraphControlPane::
GuideAlgorithmHysteresisGraphControlPane(wxWindow * pParent,GuideAlgorithmHysteresis * pGuideAlgorithm,const wxString & label)306 GuideAlgorithmHysteresisGraphControlPane(wxWindow *pParent, GuideAlgorithmHysteresis *pGuideAlgorithm, const wxString& label)
307 : GraphControlPane(pParent, label)
308 {
309 int width;
310
311 m_pGuideAlgorithm = pGuideAlgorithm;
312
313 // Aggression
314 width = StringWidth(_T("000"));
315 m_pAggression = pFrame->MakeSpinCtrl(this, wxID_ANY, _T(""), wxDefaultPosition,
316 wxSize(width, -1), wxSP_ARROW_KEYS | wxALIGN_RIGHT, 0.0, MaxAggression * 100.0, 0.0, _T("Aggressiveness"));
317 m_pAggression->SetToolTip(wxString::Format(_("What percentage of the computed correction should be applied?? Default = %.f%%, adjust if responding too much or too slowly"), DefaultAggression * 100.0));
318 m_pAggression->Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &GuideAlgorithmHysteresis::GuideAlgorithmHysteresisGraphControlPane::OnAggressionSpinCtrl, this);
319 DoAdd(m_pAggression, _("Agr"));
320
321 // Hysteresis
322 width = StringWidth(_T("000"));
323 m_pHysteresis = pFrame->MakeSpinCtrl(this, wxID_ANY, _T(""), wxDefaultPosition,
324 wxSize(width, -1), wxSP_ARROW_KEYS | wxALIGN_RIGHT, 0.0, MaxHysteresis * 100.0, 0.0, _T("Hysteresis"));
325 m_pHysteresis->SetToolTip(wxString::Format(_("How much history of previous guide pulses should be applied\nDefault = %.f%%, increase to smooth out guiding commands"), DefaultHysteresis * 100.0));
326 m_pHysteresis->Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &GuideAlgorithmHysteresis::GuideAlgorithmHysteresisGraphControlPane::OnHysteresisSpinCtrl, this);
327 DoAdd(m_pHysteresis,_("Hys"));
328
329 // Min move
330 width = StringWidth(_T("00.00"));
331 m_pMinMove = pFrame->MakeSpinCtrlDouble(this, wxID_ANY, _T(""), wxPoint(-1, -1),
332 wxSize(width, -1), wxSP_ARROW_KEYS, 0.0, 20.0, 0.0, 0.01, _T("MinMove"));
333 m_pMinMove->SetDigits(2);
334 m_pMinMove->SetToolTip(wxString::Format(_("How many (fractional) pixels must the star move to trigger a guide pulse? \n"
335 "If camera is binned, this is a fraction of the binned pixel size. Default = %.2f"), DefaultMinMove));
336 m_pMinMove->Bind(wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, &GuideAlgorithmHysteresis::GuideAlgorithmHysteresisGraphControlPane::OnMinMoveSpinCtrlDouble, this);
337 DoAdd(m_pMinMove,_("MnMo"));
338
339 m_pHysteresis->SetValue(100.0 * m_pGuideAlgorithm->GetHysteresis());
340 m_pAggression->SetValue(100.0 * m_pGuideAlgorithm->GetAggression());
341 m_pMinMove->SetValue(m_pGuideAlgorithm->GetMinMove());
342
343 if (TheScope() && pGuideAlgorithm->GetAxis() == "DEC")
344 {
345 DEC_GUIDE_MODE currDecGuideMode = TheScope()->GetDecGuideMode();
346 m_pAggression->Enable(currDecGuideMode != DEC_NONE);
347 m_pMinMove->Enable(currDecGuideMode != DEC_NONE);
348 m_pHysteresis->Enable(currDecGuideMode != DEC_NONE);
349 }
350 }
351
352 GuideAlgorithmHysteresis::
353 GuideAlgorithmHysteresisGraphControlPane::
~GuideAlgorithmHysteresisGraphControlPane(void)354 ~GuideAlgorithmHysteresisGraphControlPane(void)
355 {
356 }
357
358 void GuideAlgorithmHysteresis::
EnableDecControls(bool enable)359 GuideAlgorithmHysteresisGraphControlPane::EnableDecControls(bool enable)
360 {
361 m_pAggression->Enable(enable);
362 m_pHysteresis->Enable(enable);
363 m_pMinMove->Enable(enable);
364 }
365
366 void GuideAlgorithmHysteresis::
367 GuideAlgorithmHysteresisGraphControlPane::
OnAggressionSpinCtrl(wxSpinEvent & WXUNUSED (evt))368 OnAggressionSpinCtrl(wxSpinEvent& WXUNUSED(evt))
369 {
370 m_pGuideAlgorithm->SetAggression(m_pAggression->GetValue() / 100.0);
371 pFrame->NotifyGuidingParam(m_pGuideAlgorithm->GetAxis() + " Hysteresis aggression", m_pAggression->GetValue());
372 }
373
374 void GuideAlgorithmHysteresis::
375 GuideAlgorithmHysteresisGraphControlPane::
OnHysteresisSpinCtrl(wxSpinEvent & WXUNUSED (evt))376 OnHysteresisSpinCtrl(wxSpinEvent& WXUNUSED(evt))
377 {
378 m_pGuideAlgorithm->SetHysteresis(this->m_pHysteresis->GetValue() / 100.0);
379 pFrame->NotifyGuidingParam(m_pGuideAlgorithm->GetAxis() + " Hysteresis hysteresis", m_pHysteresis->GetValue());
380 }
381
382 void GuideAlgorithmHysteresis::
383 GuideAlgorithmHysteresisGraphControlPane::
OnMinMoveSpinCtrlDouble(wxSpinDoubleEvent & WXUNUSED (evt))384 OnMinMoveSpinCtrlDouble(wxSpinDoubleEvent& WXUNUSED(evt))
385 {
386 m_pGuideAlgorithm->SetMinMove(m_pMinMove->GetValue());
387 pFrame->NotifyGuidingParam(m_pGuideAlgorithm->GetAxis() + " Hysteresis minimum move", m_pMinMove->GetValue());
388 }
389