2 Copyright 2006 Johnathan Corgan.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2
6 as published by the Free Software Foundation.
8 This software is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with GNU Radio; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 Boston, MA 02111-1307, USA.
19 // Application level includes
28 // System level includes
33 const wxEventType wxEVT_SEARCH_UPDATE = wxNewEventType();
35 SearchUpdate::SearchUpdate(const wxEventType &event, bool done) :
41 TransmitterSearch::TransmitterSearch(wxEvtHandler *dest) :
45 m_resolution = 0.0005; // 182 foot granularity
48 m_scale = 0.85; // Estimated from Mt. Umunhum data
50 Create(); // wxThreadHelper
54 TransmitterSearch::~TransmitterSearch()
56 GetThread()->Delete();
59 void TransmitterSearch::Reset()
62 m_initialized = false;
63 m_solution = Spherical(0.0, 0.0);
68 void TransmitterSearch::ClearStats()
73 void *TransmitterSearch::Entry()
75 wxLogDebug(_T("TransmitterSearch::Entry(): entered"));
78 while (!GetThread()->TestDestroy())
79 if (m_condition.WaitTimeout(1000) == wxCOND_NO_ERROR)
83 wxLogDebug(_T("TransmitterSearch::Entry(): exited"));
86 void TransmitterSearch::background_solve()
92 int count = m_log->Count();
96 if (count == 0) // No data to solve from
97 return post_update(true);
99 if (!m_initialized) { // Get initial solution from first sample, but only once
100 m_solution = m_log->Samples().begin()->Location();
101 m_initialized = true;
105 return post_update(true);
109 while (++m_iterations <= MaxIterations) {
110 wxMutexLocker locker(m_log->Mutex());
111 if (hillclimb(m_log->Samples())) { // true return indicates solution of some sort achieved
112 m_histogram.Calc(m_log->Samples(), m_solution);
113 return post_update(true);
117 // Max iterations reached, send interim solution
118 m_histogram.Calc(m_log->Samples(), m_solution);
123 void TransmitterSearch::post_update(bool done)
125 SearchUpdate update(wxEVT_SEARCH_UPDATE, done);
126 wxPostEvent(m_dest, update);
130 void TransmitterSearch::Solve(SampleLog *log)
132 // FIXME: what if we get here while background thread is still busy?
133 if (m_log && (m_log != log))
134 wxLogError(_T("TransmitterSearch::Solve: supplied log different from current one."));
137 m_condition.Signal();
140 // Return value indicates solution of some sort achieved
141 bool TransmitterSearch::hillclimb(vector<Sample> &samples)
144 int min_x = 0, min_y = 0;
152 // Initialize search with current solution
153 if (calc_trial_error(samples, m_solution, min_error) == 0.0) {
154 wxLogDebug(_T("TransmitterSearch::hillclimb: no enabled samples, returning"));
155 return true; // No enabled data points, we're done
158 // Check if moving 'resolution' distance in one of four directions decreases error
159 for (nx = -1; nx < 2; nx++) {
160 trial.SetLongitude(m_solution.Longitude() + nx*m_resolution);
161 for (ny = -1; ny < 2; ny++) {
162 // Skip non-compass directions
165 trial.SetLatitude(m_solution.Latitude() + ny*m_resolution);
166 calc_trial_error(samples, trial, trial_error);
167 if (trial_error < min_error) {
168 min_error = trial_error;
169 min_x = nx; min_y = ny;
174 // Indicate if solution achieved
175 if (min_x == 0 && min_y == 0)
178 m_solution.SetLatitude(m_solution.Latitude()+min_y*m_resolution);
179 m_solution.SetLongitude(m_solution.Longitude()+min_x*m_resolution);
180 return false; // Make outer loop call us again
184 // Return value is number of enabled samples in vector
185 float TransmitterSearch::calc_trial_error(const vector<Sample>&samples,
186 const Spherical &trial,
191 float strength = 1.0;
193 for (int i = 0; i < samples.size(); i++) {
194 const Sample &sample = samples[i];
196 float angle, ierror, qerror;
197 sample.CalcError(trial, angle, ierror, qerror);
199 // Wrapped cauchy distribution
201 //float likelihood = (1-p*p)/(1+p*p-2*p*cos(angle*M_PI/180.0));
202 //trial_error += -log(likelihood)*sample.Strength();
204 // Adjusted exponential distribution
205 trial_error += sqrt(1+angle*angle)*sample.Strength();
206 wsum += sample.Strength();
210 trial_error = trial_error/wsum;