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., 51 Franklin Street,
16 Boston, MA 02110-1301, USA.
19 // Application level includes
29 #include <boost/scoped_array.hpp>
31 // System level includes
34 // TODO: read from ezdop.h
35 #define SAMPLERATE 8000
36 #define MAXSAMPLE 0x3FF // 12 bit ADC
37 #define DEFAULT_SELECTED_ROTATION_RATE 2 // 500 Hz until told otherwise
39 #define QUANTUM 0.2 // Sample period in seconds
40 #define DEFAULT_FILTER_LEVEL 20
42 #define NORMALIZEPHASE(x) \
48 unsigned char rotation_rates[] = {
57 const wxEventType wxEVT_DOPPLER_UPDATE = wxNewEventType();
59 EZDopplerUpdate::EZDopplerUpdate(const wxEventType &event, float &in_phase,
60 float &quadrature, float &volume) :
63 m_in_phase = in_phase;
64 m_quadrature = quadrature;
68 DopplerBackground::DopplerBackground(wxWindow *window, EZDoppler *doppler)
79 // It's in thread.h but somehow gets undef'd
80 typedef void *ExitCode;
81 ExitCode DopplerBackground::Entry()
83 float in_phase, quadrature, phase, magnitude, volume, rflevel;
86 while (!TestDestroy()) {
87 if (m_doppler->Sample(in_phase, quadrature, volume)) {
88 EZDopplerUpdate update(wxEVT_DOPPLER_UPDATE, in_phase, quadrature, volume);
89 wxPostEvent(m_dest, update);
95 EZDoppler::EZDoppler(wxWindow *gui)
102 m_phase = complex<float>(0.0, 0.0);
103 m_output = complex<float>(0.0, 0.0);
104 m_alpha = complex<float>(0.0, 0.0);
105 m_beta = complex<float>(0.0, 0.0);
110 for(int i = 0; i < NUM_RATES; i++)
111 m_calibration[i] = 0.0;
113 m_ezdop = ezdop_sptr(new ezdop());
114 m_selected_rate = DEFAULT_SELECTED_ROTATION_RATE;
117 EZDoppler::~EZDoppler()
119 if (m_ezdop->is_online()) {
120 wxLogMessage(_T("EZDoppler::~EZDoppler(): doppler still online in destructor, finalizing"));
125 bool EZDoppler::Initialize()
128 if (m_ezdop->is_online())
131 return m_ezdop->is_online();
134 bool EZDoppler::Finalize()
136 if (m_thread && m_thread->IsRunning()) {
137 wxLogDebug(_T("EZDoppler::Finalize: finalizing a running doppler"));
142 bool EZDoppler::IsOnline()
144 return m_ezdop->is_online();
147 bool EZDoppler::Reset()
149 if (m_thread && m_thread->IsRunning()) {
150 wxLogDebug(_T("EZDoppler::Reset: resetting running doppler"));
154 return m_ezdop->reset();
157 bool EZDoppler::Start()
159 if (!(m_ezdop->rotate() && m_ezdop->stream()))
162 m_thread = new DopplerBackground(m_gui, this);
166 bool EZDoppler::Stop()
168 if (m_thread && m_thread->IsRunning()) {
170 while (m_thread->IsRunning()) {
176 return (m_ezdop->stop_streaming() && m_ezdop->stop_rotating());
179 bool EZDoppler::SelectRotationRate(int n)
181 wxASSERT(n >= 0 && n < 6);
182 wxLogDebug(_T("EZDoppler::SelectRotationRate: %i %i"), n, (int)(2000/rotation_rates[n]));
184 return m_ezdop->set_rate(2000/rotation_rates[n]);
187 int EZDoppler::GetRotationRate()
189 return m_selected_rate;
192 bool EZDoppler::SetFilter(int n)
194 float beta = 30.0/(n*m_ezdop->rate()); // Empirically determined
196 m_alpha = complex<float>(1.0-beta, 0.0);
197 m_beta = complex<float>(beta, 0.0);
202 typedef boost::scoped_array<complex<float> > complexf_scoped_array;
204 // IQ is 2 complex floats, maximum rate is 2000, QUANTUM is period in seconds
205 complex<float> buffer[(int)(2*QUANTUM*2000)];
207 bool EZDoppler::Sample(float &in_phase, float &quadrature, float &volume)
209 int nsamples = (int)(m_ezdop->rate()*QUANTUM);
211 if (!m_ezdop->read_iq(buffer, nsamples, volume))
214 for (int i=0; i < nsamples; i++)
215 m_phase = m_alpha*m_phase + m_beta*buffer[i];
217 // m_angle is the actual instrument reading regardless of calibration
218 m_angle = atan2(m_phase.imag(), m_phase.real());
220 // Calibration angle is sum of equalized offset and global offset
221 float cal_angle = m_calibration[m_selected_rate] + m_offset;
223 // Rotate I, Q by calibration angle
224 complex<float> cal = complex<float>(cos(cal_angle), sin(cal_angle));
225 m_output = m_phase*cal;
227 in_phase = m_output.real()*nsamples/512.0;
228 quadrature = m_output.imag()*nsamples/512.0;
231 // wxLogDebug(_T("%f %f %f"), in_phase, quadrature, volume);
235 bool EZDoppler::Calibrate(float phase)
238 float offset = phase - m_angle;
239 NORMALIZEPHASE(offset);
240 m_calibration[m_selected_rate] = offset;
245 bool EZDoppler::SetCalibration(int rate, float offset)
248 wxASSERT(rate >= 0 && rate < 7);
250 m_calibration[rate] = offset;
257 float EZDoppler::GetCalibration(int rate)
259 wxASSERT(rate >= 0 && rate < 7);
261 return m_calibration[rate];
268 bool EZDoppler::SetOffset(float offset)
270 m_offset = offset-m_angle-m_calibration[m_selected_rate];
271 NORMALIZEPHASE(m_offset);
272 NORMALIZEPHASE(m_offset);
273 NORMALIZEPHASE(m_offset);
276 bool EZDoppler::Nudge(float amount)
278 float cal = m_calibration[m_selected_rate];
281 m_calibration[m_selected_rate] = cal;
286 bool EZDoppler::NudgeAll(float amount)
289 NORMALIZEPHASE(m_offset);