diff --git a/Storage/Disk/DigitalPhaseLockedLoop.cpp b/Storage/Disk/DigitalPhaseLockedLoop.cpp index 231b71e4a..fc1dcd214 100644 --- a/Storage/Disk/DigitalPhaseLockedLoop.cpp +++ b/Storage/Disk/DigitalPhaseLockedLoop.cpp @@ -18,9 +18,12 @@ DigitalPhaseLockedLoop::DigitalPhaseLockedLoop(int clocks_per_bit, int tolerance phase_(0), window_length_(clocks_per_bit), phase_error_pointer_(0), - phase_error_history_(length_of_history, 0) {} + phase_error_history_(length_of_history, 0), + offset_history_(length_of_history, 0), + offset_(0) {} void DigitalPhaseLockedLoop::run_for_cycles(int number_of_cycles) { + offset_ += number_of_cycles; phase_ += number_of_cycles; if(phase_ >= window_length_) { int windows_crossed = phase_ / window_length_; @@ -41,16 +44,33 @@ void DigitalPhaseLockedLoop::add_pulse() { if(!window_was_filled_) { if(delegate_) delegate_->digital_phase_locked_loop_output_bit(1); window_was_filled_ = true; - post_phase_error(phase_ - (window_length_ >> 1)); + post_phase_offset(phase_, offset_); + offset_ = 0; } } -void DigitalPhaseLockedLoop::post_phase_error(int error) { +void DigitalPhaseLockedLoop::post_phase_offset(int phase, int offset) { + offset_history_[phase_error_pointer_] = offset; + phase_error_pointer_ = (phase_error_pointer_ + 1) % offset_history_.size(); + + int total_spacing = 0; + int total_divisor = 0; + for(int offset : offset_history_) { + int multiple = (offset + (clocks_per_bit_ >> 1)) / clocks_per_bit_; + if(!multiple) continue; + total_divisor += multiple; + total_spacing += offset; + } + window_length_ = total_spacing / total_divisor; + window_length_ = std::max(std::min(window_length_, clocks_per_bit_ + tolerance_), clocks_per_bit_ - tolerance_); + + int error = phase - (window_length_ >> 1); + // use a simple spring mechanism as a lowpass filter for phase phase_ -= (error + 1) >> 1; // use the average of the last few errors to affect frequency - size_t phase_error_history_size = phase_error_history_.size(); +/* size_t phase_error_history_size = phase_error_history_.size(); phase_error_history_[phase_error_pointer_] = error; phase_error_pointer_ = (phase_error_pointer_ + 1)%phase_error_history_size; @@ -61,5 +81,5 @@ void DigitalPhaseLockedLoop::post_phase_error(int error) { } int denominator = (int)(phase_error_history_size * 4); window_length_ += (total_error + (denominator >> 1)) / denominator; - window_length_ = std::max(std::min(window_length_, clocks_per_bit_ + tolerance_), clocks_per_bit_ - tolerance_); + window_length_ = std::max(std::min(window_length_, clocks_per_bit_ + tolerance_), clocks_per_bit_ - tolerance_);*/ } diff --git a/Storage/Disk/DigitalPhaseLockedLoop.hpp b/Storage/Disk/DigitalPhaseLockedLoop.hpp index d4b38153e..78ef3e146 100644 --- a/Storage/Disk/DigitalPhaseLockedLoop.hpp +++ b/Storage/Disk/DigitalPhaseLockedLoop.hpp @@ -51,10 +51,13 @@ class DigitalPhaseLockedLoop { private: Delegate *delegate_; - void post_phase_error(int error); + void post_phase_offset(int phase, int offset); std::vector phase_error_history_; size_t phase_error_pointer_; + std::vector offset_history_; + int offset_; + int phase_; int window_length_; bool window_was_filled_;