Simple Phase Locked Loop
I didn't find much to say about your coding style.

Maybe in_sig is not a perfect name: signal_in would be easier to read in my opinion (putting the _in at the end is more consistent with you other variable names)


  it would require some re-writing if I wanted to extend it.


What kind of extension ?

Using iterators to get the samples

For your input functions, you could use a generator instead:

def sinusoid(initial_phi, frequency_offset):
    """Generates a sinusoidal signal"""
    phi = initial_phi
    while True:
        yield np.exp(1j*phi)
        phi += frequency_offset


When initially called, this function will return an iterator: iter_sin = sinusoid(3.0, -0.2)

And add set_signal_in and signal_out methods in your SimPLL class:

def set_signal_in(self, signal_in):
    """Set a iterator as input signal"""
    self.signal_in = signal_in

def signal_out(self):
    """Generate the output steps"""
    for sample_in in self.signal_in:
        self.step(sample_in)
        yield self.vco


(maybe signal_out could generate some tuples with the sample_in and phase_difference, or even yield self)

Usage

You can then do a pll.set_signal_in(iter_sin).

If you have a list of data, you can then do pll.set_signal_in(list_of_values).

Plotting

For plotting a limited amount of points, you may use itertools.islice