I'm working on a crude circuit simulator with the goal of implementing PAL encoding and decoding, so that I can experiment with generating images that look like video transmissions.
In the simulation engine, a circuit consists of circuit elements with input and output ports that express a voltage level as a double. Output ports are connected by wires to input ports of other elements. At each timestep, the sources (elements with no inputs) propagate their output values to other elements, which are evaluated once they have all inputs ready, repeating until every element has been visited. Feedback is handled using special feedback elements that act like wires but with a one timestep delay.
A simple flashing LED circuit is defined as follows:
var circuit = new Circuit(); // add a 5V power source var power = circuit.AddElement(new VoltageSourceDC(5.0)); // add a 1Hz 50% duty cycle square wave oscillator var clock = circuit.AddElement(new SquareOscillator(1.0, 0.5)); // add an LED var led = circuit.AddElement(new LED()); // wire the power source output to the clock level input. circuit.AddWire(new Wire(power.Output, clock.Level)); // wire the clock output to the LED circuit.AddWire(new Wire(clock.Output, led.Input));
I have implemented a fair number of circuit elements, including a sine oscillator, VCO, comparator, logic gates, D flip-flop, 2:1 mux, and a charge pump. Using these elements, I have created a PLL.
The schematic diagram for the PLL looks like this:
Vref is the reference waveform being locked against. In this scenario it is a square wave. The D flip-flops act as a phase detector, identifying which rising edge appears first. If both flip-flops are high, the reset signal is asserted via feedback on the next timestep. The charge pump only acts when either HI or LO are asserted, not both. The charge pump simply increases its output voltage or decreases it depending on which signal is asserted, otherwise it holds steady. The charge pump's dV/dt is configured at time of creation.
The output of the charge pump is fed through a feedback element to the input of the VCO. The feedback element could instead be placed in the feedback path after the comparator, but that seems to produce less stable results. The VCO's output is then compared against Vcmp, which is Vdd/2, to turn it into a square wave for Vout.
This mostly works:
Vpump initially oscillates beyond the target frequency, but then it settles and keep the VCO output locked very closely in phase and frequency. This is what I expected to see - the frequency ramps up to "catch up" with the phase of the reference, then slows down to match the frequency.
Zooming in a bit, we can see the phase error being very small with UP/DOWN mostly being asserted simultaneously:
Unfortunately, this does not hold over long periods of time, and the charge pump voltage begins to oscillate:
Over longer times the oscillation reaches a peak and then locks again, repeating over and over. Changing the charge pump dV/dt has a major effect on this.
The timestep is small in comparison with the signal frequencies, and there is little behavioural change between 10us and 1us steps.
Why is this occurring? What should I do to fix it?