2016-07-12 02:12:58 +00:00
|
|
|
//
|
|
|
|
// DigitalPhaseLockedLoop.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 11/07/2016.
|
|
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "DigitalPhaseLockedLoop.hpp"
|
2016-07-27 20:24:24 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cstdlib>
|
2016-07-13 00:23:56 +00:00
|
|
|
|
|
|
|
using namespace Storage;
|
|
|
|
|
2016-07-14 23:42:01 +00:00
|
|
|
DigitalPhaseLockedLoop::DigitalPhaseLockedLoop(int clocks_per_bit, int tolerance, int length_of_history) :
|
2016-07-13 00:23:56 +00:00
|
|
|
_clocks_per_bit(clocks_per_bit),
|
|
|
|
_tolerance(tolerance),
|
|
|
|
_length_of_history(length_of_history),
|
2016-07-14 23:42:01 +00:00
|
|
|
_pulse_history(new int[length_of_history]),
|
2016-07-13 00:23:56 +00:00
|
|
|
_current_window_length(clocks_per_bit),
|
|
|
|
_next_pulse_time(0),
|
|
|
|
_window_was_filled(false),
|
2016-07-14 23:42:01 +00:00
|
|
|
_window_offset(0),
|
|
|
|
_samples_collected(0) {}
|
2016-07-13 00:23:56 +00:00
|
|
|
|
2016-07-14 23:42:01 +00:00
|
|
|
void DigitalPhaseLockedLoop::run_for_cycles(int number_of_cycles)
|
2016-07-13 00:23:56 +00:00
|
|
|
{
|
|
|
|
// check whether this triggers any 0s
|
|
|
|
_window_offset += number_of_cycles;
|
|
|
|
if(_delegate)
|
|
|
|
{
|
|
|
|
while(_window_offset > _current_window_length)
|
|
|
|
{
|
|
|
|
if(!_window_was_filled) _delegate->digital_phase_locked_loop_output_bit(0);
|
|
|
|
_window_was_filled = false;
|
|
|
|
_window_offset -= _current_window_length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_window_offset %= _current_window_length;
|
|
|
|
}
|
|
|
|
|
2016-07-13 01:42:23 +00:00
|
|
|
// update timing
|
2016-07-13 00:23:56 +00:00
|
|
|
_next_pulse_time += number_of_cycles;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DigitalPhaseLockedLoop::add_pulse()
|
|
|
|
{
|
2016-07-14 23:42:01 +00:00
|
|
|
int *const _pulse_history_array = (int *)_pulse_history.get();
|
2016-07-27 20:24:24 +00:00
|
|
|
int outgoing_pulse_time = 0;
|
2016-07-13 00:23:56 +00:00
|
|
|
|
2016-07-27 20:24:24 +00:00
|
|
|
if(_samples_collected <= _length_of_history)
|
2016-07-14 11:31:23 +00:00
|
|
|
{
|
2016-07-14 23:42:01 +00:00
|
|
|
_samples_collected++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-07-27 20:24:24 +00:00
|
|
|
outgoing_pulse_time = _pulse_history_array[0];
|
|
|
|
|
|
|
|
// temporary: perform an exhaustive search for the ideal window length
|
|
|
|
int minimum_error = __INT_MAX__;
|
|
|
|
int ideal_length = 0;
|
|
|
|
for(int c = _clocks_per_bit - _tolerance; c < _clocks_per_bit + _tolerance; c++)
|
2016-07-14 23:42:01 +00:00
|
|
|
{
|
2016-07-27 20:24:24 +00:00
|
|
|
int total_error = 0;
|
|
|
|
const int half_window = c >> 1;
|
|
|
|
for(size_t pulse = 1; pulse < _length_of_history; pulse++)
|
|
|
|
{
|
|
|
|
int difference = _pulse_history_array[pulse] - _pulse_history_array[pulse-1];
|
|
|
|
difference += half_window;
|
|
|
|
const int steps = difference / c;
|
|
|
|
const int offset = difference%c - half_window;
|
2016-07-14 23:42:01 +00:00
|
|
|
|
2016-07-27 20:24:24 +00:00
|
|
|
total_error += abs(offset / steps);
|
|
|
|
}
|
|
|
|
if(total_error < minimum_error)
|
|
|
|
{
|
|
|
|
minimum_error = total_error;
|
|
|
|
ideal_length = c;
|
|
|
|
}
|
2016-07-14 23:42:01 +00:00
|
|
|
}
|
|
|
|
|
2016-07-27 20:24:24 +00:00
|
|
|
// use a spring mechanism to effect a lowpass filter
|
|
|
|
_current_window_length = ((ideal_length + (_current_window_length*3)) + 2) >> 2;
|
2016-07-14 11:31:23 +00:00
|
|
|
}
|
2016-07-13 00:23:56 +00:00
|
|
|
|
|
|
|
// therefore, there was a 1 in this window
|
|
|
|
_window_was_filled = true;
|
|
|
|
if(_delegate) _delegate->digital_phase_locked_loop_output_bit(1);
|
|
|
|
|
2016-07-27 20:24:24 +00:00
|
|
|
// shift history one to the left, storing new value, potentially with a centring adjustment
|
2016-07-13 00:23:56 +00:00
|
|
|
for(size_t pulse = 1; pulse < _length_of_history; pulse++)
|
|
|
|
{
|
2016-07-14 11:32:27 +00:00
|
|
|
_pulse_history_array[pulse - 1] = _pulse_history_array[pulse] - outgoing_pulse_time;
|
2016-07-13 00:23:56 +00:00
|
|
|
}
|
|
|
|
_next_pulse_time -= outgoing_pulse_time;
|
|
|
|
_pulse_history_array[_length_of_history-1] = _next_pulse_time;
|
|
|
|
}
|