The 567 tone decoder is perhaps most famous Phase Locked Loop (PLL) chip.
This project looks at an Arduino software PLL.
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
PLL.inoAn untested version of a software PLL Bell1032A modem using an ATTiny85.ino - 7.35 kB - 03/04/2017 at 02:04 |
|
|
PLL_LP2.xlsmThe last version of the PLL that I was working on (contains a steepest descent routine (incomplete)).12 - 306.28 kB - 03/04/2017 at 02:01 |
|
|
PID_pll.xlsmPID version of my software PLL in Excel12 - 48.35 kB - 02/20/2017 at 08:07 |
|
|
PLL_RRC.xlsmThe passive lead lag low pass filter. Also contains the the S to Z transform calculator and the S and Z bode plotter.12 - 288.10 kB - 02/20/2017 at 08:47 |
|
I have been considering what to do next with the software PLL. Do I go the simple low pass filter and move on or spend more time optimising. It is a question of time versus likely outcomes. I have a good result, is it worth trying to make it better?
The second problem is how to optimise this problem? I can see two approaches:
But first what is the problem I am trying to solve?
Here is a very good result from the Bell103A2 modem project:
What are the key attributes:
Here is a less than ideal response:
Here is my current low pass PLL response showing the data input (square wave), the LP output and a fitted sine wave:
So why is this important? Here is version that looked good in the beginning only to blow up latter:
What when wrong?
What controls the output of the PLL? Yes I know about Q (transit overshoot) and natural frequency but the above image shows a stable PLL becoming unstable. To fix the above I increased the lower bound frequency to reduce the work for the PLL to get into lock.
What parameters can I play with?
I am obviously very reluctant to change (increase) the sample rate. But here is the impact (SR = 8065):
And (SR = 16667 Hz):
Note: the fitted sine wave (to the output) uses the last four cycles.
I already know this works but I don't know if the system is stable?
Again, yes but the theory does not translate very well with a low sample rate.
I am thinking that I could get really bogged down here. I have coded a steepest descent optimiser (but not run it ) but based on the rules of thumb that I already know I suspect I will not find anything new. The problem has multiple local optima (due to the discrete nature of a software PLL), so problem will not solve easily or reliable. I think I should move on!
I am familiar with multi-variate analysis so linearising and solving the equations is not too hard. The form of the equation I am trying to solve is:
where:
Separate the Frequency and Phase using:
Therefore (after relabelling the constants):
The error squared function is:
Solving the multi-variate problem:
Where N is the number of samples.
Fortunately the above simplifies if the range of "t" is a multiple of 2 * Pi, to:
Therefore:
Here it is in VBA code:
A0 = 0
A1 = 0
A2 = 0
For Time = Int(SR / 150 + 0.5) To Int(5 * SR / 150 + 0.5)
A0 = A0 + Test(Time)
A1 = A1 + Test(Time...
Read more »
The purpose of this project was to see if I could improve the performance of my Bell 103A2 modem. Initially to see if I could extract the baud clock to mitigate output jitter. Well I have not looked at that (have to investigate other start bit synchronisation methods as well), the FSK Modem is a good platform to test the PLL as most of the code has been written (and debugged) and it has a built in loop-back test.
All I need to do is replace the demodulation code subject to a decision on (1) a binary XOR or (2) a mixer style phase detector.
An unreasonable good results should be expected from the loop-back as the baud generator is not really asynchronous. Well this has to be tested.
For the first port I dropped the sample frequency to 8065 Hz to match the FSK modem. I tested bothe the Anwer and Originate mark/space frequencies. This uncovered a problem for the PID version of the PLL. Although adjustment of the parameters found an acceptable performance solution, the simple low pass PLL worked better. It appears that damping factor and natural frequency are not that important performance controls!
The second port is based on the low pass PLL and an internal loop back test. I am on holidays so no test work, but here is the code:
// Bell 103A2 Modem
// ================
#define ModemMode false // Answer Modem -> Receives Low Channel
#define Baud 300 // Baud rate
#define TimerConst 30 // 8065 Hz sample rate
// Phase steps based on PWM frequency of 31372.5 Hz (=16000000/510)
#define BaudPhase 627 // Baud phase increment (for 31372.5 Hz clock)
#define OriFspace 2235 // Originate modem Space frequency 1070 Hz
#define OriFmark 2653 // Originate modem Mark frequency 1270 Hz
#define AnsFspace 4230 // Answer modem Space frequency 2025 Hz
#define AnsFmark 4648 // Answer modem Mark frequency 2225 Hz
#define AnsPM 7882 // Answer modem tuning word for 970 Hz
#define OriPM 15643 // Originate modem tuning word Fore 1925 Hz
// Constants
const unsigned int SR=12000; // Sample Rate
const unsigned int PL=870; // Originate PLL Low Frequency
const unsigned int PH=1825; // Answer PLL Low Frequency
const unsigned int PML=PL*65536/SR; // Originater DDS Tunning Number
const unsigned int PMH=PH*65536/SR; // Answer DDS Tunning Number
// Define various ADC prescaler
const byte PS_16=(1<<ADPS2);
const byte PS_32=(1<<ADPS2)|(1<<ADPS0);
const byte PS_64=(1<<ADPS2)|(1<<ADPS1);
const byte PS_128=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
// A 64 step byte sized sine table
const byte iSin[64] = {
128,140,153,165,177,188,199,209,
218,226,234,240,245,250,253,254,
255,254,253,250,245,240,234,226,
218,209,199,188,177,165,153,140,
128,116,103, 91, 79, 68, 57, 47,
38, 30, 22, 16, 11, 6, 3, 2,
1, 2, 3, 6, 11, 16, 22, 30,
38, 47, 57, 68, 79, 91,103,116
};
// Debug variables
// volatile int I=0;
// volatile int D0[324];
// volatile int D1[324];
// Get a signal sample
volatile bool dataAvailable=false;
volatile int SX0=0;
volatile int SX1=0;
volatile int SX2=0;
ISR(TIMER0_COMPA_vect) {
// Roll the samples
SX2=SX1;SX1=SX0;
// SX0=analogRead(A0)-512;
SX0=OCR2A-128;
// Flag new sample available
dataAvailable=true;
}
// TRANSMIT
volatile byte DataOut=1;
volatile bool baudUpdate=true;
volatile unsigned int baudTick=0;
ISR(TIMER2_OVF_vect) {
static unsigned int phase=0;
OCR2A = iSin[(phase>>10)]; // Output on pin 11
if (!ModemMode) { // Set true for Answer modem - Invert for audio loopback test
// Answer modem
if (DataOut==0) {
phase+=AnsFspace;
} else {
phase+=AnsFmark;
}
} else {
// Originate modem
if (DataOut==0) {
phase+=OriFspace;
} else {
phase+=OriFmark;
}
}
// Update baud tick
baudTick+=BaudPhase;
if (baudTick<BaudPhase) baudUpdate=true;
}
void setup() {
pinMode(A0,INPUT); // Audio input
pinMode(12,OUTPUT); // Digital data output
pinMode(11,OUTPUT); // Audio output (PWM)
pinMode(10,OUTPUT); // Digital data input
pinMode(LED_BUILTIN,OUTPUT); // Signal detected
digitalWrite(LED_BUILTIN,LOW);
// Set...
Read more »
I have been working my way through the loop filter types, so far:
No problem with the first three:
Low Pass
PID
Lead-Lag
Here are the analog domain basic loop filters. The problem filter is shown at the bottom of the image:
(source: http://www.globalspec.com/reference/38390/203279/2-6-second-order-phase-locked-loops)
I have plotted the S domain versus the the modelled Z domain and the Z domain is good up until about Nyquist, so no problems:
The recursive equation was:The issue is that this filter cannot be used directly. The DC gain is +46dB and as the structure is that of an integrator and the PD is 0 to K, the filter just blows up:
This can be fixed by using a differential PD (i.e. -K/2 to +K/2) or by using a filter like the second filter below:After substituting the PD for a differential PD (i.e. -K/2 to +K/2) I get something that basically works:
(Note that the vertical scale has changed compared to the other PLL filters)
The analog equivalent is:K | 4000 | =KpKv | |
R1 | 5600 | R | |
R2 | 5600 | R | |
C | 0.000000100 | F | |
T1 | 0.00056 | ||
T2 | 0.00056 | ||
WN | 2673 | =sqrt(K/T1) | |
D | 0.75 | =T2/2*sqrt(K/T1) |
The main advantage of the last filter is greater range of control of damping factor and natural frequency.
Now that I have all the filters working which one to use going forward? Active Lead-Lag or PID?
Active Lead-Lag Loop
Inputs:
Intermediate:
Code (after calculating Z-transform coefficients):
PID Loop (First Order)
Inputs:
Intermediate:
Output:
Code:
It looks rather like a "no-brainer" to go with PID from a computational point of view (all other things appearing to be equal). Funny how the common wisdom of PID in the discrete domain is confirmed!
AlanX
The mixing of analog and digital can get very messy. I spent the day transposing the lead-lag low pass filter into digital via the z-transform. I think the coefficients model the filter but how to be sure? The coefficients however are not that integer friendly.
The Wiki PLL uses a "Proportional and Derivative" concept that basically equates to a variable gain one pole low pass.
The Wiki PLL page discusses the problem with a simple RC filter, that independent control of damping factor and natural (i.e. damping) frequency is not possible:
For critical damping (d=0.7071):
Therefore (the low pass corner frequency) should be:
The reason for pursuing the lead-lag filter is that the low pass corner frequency and the damping factor can be separated:
Neat.
What is not said is that we can easily change the K (i.e. KpKv) of the PLL. This is what I did to get rid of the overshoot. We still need a minimum K to ensure capture and lock of the signal.
The digital maths here is much like a Proportional-Integral-Derivative (PID) control. So more research required.
I was looking for some example FSK PLL circuits to analysis (surprising few with component values). I have seen this image many times:
Checking the datasheet:
For a simple RC LPF:
It is clear the designer wanted near critical damping and had no choice but the accept the LPF corner frequency of 885 Hz. In order to compensate the designer used a three stage low pass filter on the demodulated output.
Why did the designer not use a lead-lag filter:
I have noticed that others (more recent) have used a low pass capacitor of 0.15 uF which results in:
Although the low pass filter is better the damping is probably too low.
Analog Domain
In the analog domain the process seems to be:
I did not have success using a two stage single pole low pass filters.
Digital Domain
In the digital domain the "filter" of choice is PID (Proportional, Integral and Derivative), actually just Proportional and Integral. Here we select wn and d and determine Kp and Ki (the factor for proportional and integral):
Where:
A first order discrete equation is:
Results
Both work but the sinple low pass filter worked better in my case.
Here is the simple LP filter version:
And here is the PID version:
The PID output is the orange (LP) curve. Not sure that the PID control signal should swing from limit to limit.
Plotting S Domain and Z Domain Functions
I have not looked at Laplace equations for 30 years and I am not an electrical/electonics engineer so it was a bit of "going back to school". Anyway, worked it out:
I also worked out how to do the Z domain thanks to:
I have also worked out how to build discrete active filters thanks to:
Why it took a week or more to find this webpage I do not understand!
Here is an s and z domain plot for a simple lead-lag filter (in this case R1=8k2, R2=8k2 and C=50nF):
Note: there are only... Read more »The basic components of a PLL are:
Optionally:
Here is my basic PLL diagram:
There are a number of different types of phase detectors (PD). The most common are:
I am only looking at the XOR (exclusive OR) detector here. If you are not aware, the XOR is a logic gate (i.e. 7486):
This can be modelled as:
if (A==B) {
PD=0;
} else {
PD=1;
}
Or more compactly as:
PD=(A==B)?0:1;
A PLL needs some DC loop gain (usually refer to as Kpd*Kvco). For this PLL all the loop gain (PK) is provided by the PD (phase detector). The main reason id that an integer maths digital low pass works best with higher values (i.e 0 and 1 will not cut it).
So here is the final PD:
PD=(A==B)?0:PK;
Here is a simple RC low pass (LP) filter:
(source: www.learningaboutelectronics.com/images/Low-pass-filter-diagram.png)
A simple RC low pass has a corner frequency (Fc) of:
This can modelled as:
(You may recognise this as the exponential smoothing equation)
Where:
Where Fs is the sample frequency (Fs).
This can be reworked as:
LP=LP+A*(PD-LP)/D
Where a = A/D, where A is an integer and D is a power of 2 (i.e. 2, 4, 8, ...).
The reason for D being a power of 2 is that division is expensive for the Arduino and arithmetic shift right (>>) is not.
Although the RC LP filter works the voltage response and can oscillate and a "Lead-Lag" filter is usually preferred as it has a faster response with less overshoot:
(source: mysite.du.edu/~etuttle/electron/circ116.gif)
I have yet to "digitised" the Lead-Lag loop filter (TBC ...).
The generation of a both the test signal (SX) and the PLL oscillator (PX) are based on the Direct Digital Synthesis (DDS) . I will uses a 16 bit phase accumulator both the signal and PLL accumulators (SA and PA). The tuning words (SM ans PM) are:
The DDS's are:
Note: that overflow does nor cause and error.
And to get the binary output frequency:
To increase the PLL oscillator frequency we add the LP output to the phase accumulator:
So what have we done? The PLL VCO low frequency is set by PM and the high frequency by is set by PM+LP, as the LP values range from 0 to PK.
The maximum PLL VCO frequency (PH) is then:
So magic, we can estimate PK from the difference between the required VCO high and low frequencies.
The two equations above code as:
SA=SA+SM; PA=PA+PM+LP;Here is the code written in Excel VBA:
Option Explicit
Sub PPL()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Dim Pi As Double
Pi = 4 * Atn(1)
Dim FS As Long ' Sample Frequency
Dim SX As Long ' Sample Input
Dim SF As Long ' Sample Frequency Frequency
Dim SA As Long ' Sample Frequency Phase Accumulator
Dim SM As Long ' Sample Frequency Phase Increment
Dim PX As Long ' PLL Frequency
Dim PL As Long ' PLL Low Frequency
Dim PM As Long ' PLL Phase Increment
Dim PA As Long ' PLL Phase Accumulator
Dim PD As Long ' PLL Phase Detector
Dim PK As Long ' PLL Phase Detector Gain
Dim LP As Long ' Low Pass Filter
Dim LPF As Long ' Low Pass Filter Corner Frequency
Dim LP2 As Long ' Output Low Pass Filter
Dim A As Long ' Low Pass Filter Constant
Dim D As Long ' Low Pass Filter Divisor
Dim Time As Long ' Time Step
FS = 12000
SF = 1070
SM = SF * 65536 \ FS
SA = 0
SX = 0
PL = 800
PM = PL * 65536 \ FS
PA = 0
PX = 0
PK = 5000
PD = 0
LP = 0
PK = Int(ActiveSheet.Cells(1, 10).Value + 0.5)
LPF = Int(ActiveSheet.Cells(2, 10).Value + 0.5)
D = 128
A = Int(D * Exp(-2 * Pi * LPF / FS) + 0.5)
ActiveSheet.Cells(1, 1).Value = "Time"
ActiveSheet.Cells(1, 2).Value = "FX"
ActiveSheet.Cells(1, 3).Value = "SX"
ActiveSheet.Cells(1, 4).Value = "PX"
ActiveSheet.Cells(...
Read more »
Create an account to leave a comment. Already have an account? Log In.
The main advantage is that product and/or auto-correlation will lock much faster.
if it is a modem have a look at: https://hackaday.io/project/19350-an-old-fashion-acoustic-modem-for-the-iphone. Otherwise look at the product detector. Still many of the techniques may be useful.
Hi @agp.cooper , it's not a modem - actually a modulated signal I'm trying to sync with. Effectively an unbalanced PWM (say 70% duty) with a periodic duty "inversion" of say 30% for one cycle. I'm trying to spot that inverted cycle with the challenge that the signal can intermittently drop to 0 during the time it's supposed to be 1 on any of the periods. I'm hoping to find something that can accomodate such an element of noise, which obviously a zero crossing scheme can't without getting more complicated.
Do you have an example or link to a good reference for a software based product detector?
A PLL is good for recovering the carrier. A "data slicer" combined with a LPF or two could work to recover...
Thanks @agp.cooper , I don't even need to recover a signal per se, just sync up with the expected pattern of 70% x n cycles followed by 30% x 1 cycle, repeat! Thinking a simple autocorrelator may be the best.
Hi Simon, I had forgotten that I went into such depth! Anyway, I did not use it for the modem, I used an auto-correlation method (bit like a product detector).
Regards AlanX
Good idea - do you recall if that was because it was computationally more efficient than the pll?
Hi @agp.cooper , I was digging around for a simple intro to software PLL and this looks great - thank you!
Become a member to follow this project and never miss any updates
By using our website and services, you expressly agree to the placement of our performance, functionality, and advertising cookies. Learn More
what a great idea and a creative software that you shared i read all the information in the article and i think this will be a very useful software in future days you can see my work here on https://www.pcsoftwarepro.com/filmora-9/