Generating spread-spectrum (DSSS) signals

I had play with using the video generator to directly generate binary-phase-shift spread-spectrum signal.

My thought was to switch between sending $55555555 and $AAAAAAAA to the video hardware (running at 80MHz clock, so 40MHz carrier
with 2.5MHz chip-rate.

So the basic step is:
		rcl	chip, #1  wc        
	if_c	mov	patt, HAAAAAAAA
	if_nc	mov	patt, H55555555
		WAITVID colour, patt
With 8 instructions per chip at these rates, and waitvid taking 7 cycles minimum I think, that leaves room for 3 more instructions per chip,
allowing stepping through my 32 long chip table (1024 random bits but with zero disparity), and modulating from a bitstream at about 2.4kbaud.

I used a single long repeated as my bitstream, so about 13ms before the stream repeats, ie 76Hz or so.

Spectrum analyzer traces show the overall modulation envelope, and zoomed right in the 76Hz spaced carriers due
to the repetition rate, pretty clean (owing to the power-of-two FRQA setting of $10000000.


(I'd like to add a low-Q bandpass filter to this of course)



I've also played with baseband generation of the chips, which has the potential to be more insensitive to
PLL not being a power-of-two - the time-domain jitter ought to be less serious, allowing a receiver to vary its
PLL ratio to search for the correlation and then phase lock to the transmitter.

Using differential output PLL mode would be able to directly drive a balanced mixer for upconversion and
demodulation I think.

I've read a bit on Gold codes too, perhaps something to tie in to the chip generation.


  • 13 Comments sorted by Date Added Votes
  • Interesting project! Have you tried receiving and decoding the signals you're sending?

    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • Erm, no, that's more complicated, involves clock recovery, correlation search etc.

    I suppose I could do the decoding logic for baseband, and mix the output down using a 612
    (avoids clock-discovery, but still needs correlation search in the receiving cog. It could vary
    the LO frequency to do this which would test if the non-power-of-two PLL output is an issue
    for this kind of modulation.
  • I was thinking about decoding whilst walking in this morning and realized in non-PLL mode the counter
    can do XOR mode, ie count the correlation values for you, so perhaps using counter A in PLL mode to generate
    the chips and feeding that to one of the pins for counter B which runs in mode %10110, and the limited/schmitt-triggered
    RF input to the other pin for counter B, means the counts for B can be sampled regularly to assess correlation values.

    I presume there's no issue having one counter's output pin used as an input pin for the other counter?
  • Yes, you can use a counter's output pin as the input to another counter.

    Take a look at my AM radio thread for some ideas about using counters in correlation assessment:

    By using both I and Q mixers, their outputs can be used for nearly any kind of demodulation scheme.

    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • Yes I think I'd skimmed that before, but reading avidly this time!
  • So tonight I generated the baseband variation, running at 5MHz not 80, and into a 3-pole low-pass LC pi-filter with a bandwidth of about 2.7MHz.

    Was hoping for more attenuation at higher frequencies than 40dB though, but I think this sort of circuit done on a breadboard isn't ideal - there's scope for an RC stage as well.

    The idea is to put the low-pass filtered baseband spread-spectrum signal direct into a 612 active mixer (which only needs
    50 to 100mV or similar levels).

  • And the 'scope output for the signal before and after low-pass:
  • I think Mark is on a good path with the external mixer and filtering. I'm posting this information here for reference, in case anyone want to make a quick and dirty signal. (It will be dirty from the lack of filtering and the jitter in the PLL.) This was developed from cog_vid.v and is currently untested.

    The broadcast mode part of the video generator switches between 2 values at the carrier frequency. It is able to generate a carrier with a peak to peak amplitude between 7 and 0 using a 3 bit DAC. That's great for AM, but useless for PSK or DSSS. But, don't give up yet. By using only bits 1 and 0 it is possible to reverse the phase of the carrier. The number of possible amplitudes is reduced from 8 to 4, but you gain the capability to apply a 180 degree phase shift. Or use only colors 2 and 4 to generate a differential BPSK / DSSS signal.
    Color	BC+	BC-	2lsb+	2lsb-	difference
    0	7	0	3	0	 3
    1	6	0	2	0	 2
    2	6	1	2	1	 1	differential +
    3	5	1	1	1	 0
    4	5	2	1	2	-1	differential -
    5	4	2	0	2	-2
    6	4	3	0	3	-3
    7	3	3	3	3	 0

    Invention is the Science of Laziness
  • Interesting - I'm not upto speed with the broadcast/baseband/chroma use of the video-generator,
    the Prop manual seems to gloss over the details - do you have the video register settings for the above
  • I'm back looking at signal generation with the Prop and PASM (after a diversion with LFSRs and
    noise generation using resistor-based digital filtering inspired by an example in The Art of Electronics).

    The alternative way to filter a bitstream to the LC-filter mentioned above is digital filtering. The resistor
    based method involves shifting the bits along a register that is written to OUTA on every step. A set of
    resistors whose conductance represents the coefficients of a FIR filter go from the pins to an opamp current
    summing junction at mid-rail.

    There is a trick for when the FIR filter is even-symmetric, you can shift the bits down one register, then up
    another, then combine them to set both DIRA and OUTA (where the bits are the same set pin as output, where
    different, set to input - this sums the two bits in the two registers via one pin and the opamp).

    The negative coefficients can be done either:
    1) With a separate current summing junction and a differential amp to combine the signals
    2) By inverting a copy of the shift registers in the relevant positions before outputing to OUTA.

    Anyway digital filtering can be done in code too - which is where I'm going with this posting. In my example
    code I oversamp by a factor of 5 - so 5 values are output per bit in the bitstream. I use a separate cog for each,
    running interleaved in time, each getting the bit stream from a prop pin (generated by another cog in fact).

    My FIR filter is a raised-cosine one with 31 coefficients. Raised cosine filter gives zero inter-symbol interference
    as the zero coefficients fall on the neighbouring bits (ie +/-5, +/-10, +/-15 from the centre coefficient.

    To avoid sin(x)/x roll-off in the response the bit stream value is sampled every 5 steps, effectively as a +1 or
    -1 value, and is zero inbetween. 1,0,0,0,0,-1,0,0,0,0,-1,0,0,0,0,1...
    Conveniently zero values don't need to be summed in the filter, so across the 31 coefficients only 6 need to
    calculated per step (it would be 7 but the 0th and 30th coefficients happen to be zero anyway)

    So the PASM loop basically sums 6 coefficients, then modifies those instructions to move on for the next
    bit coming in - the instructions are either ADD or SUB according to the bit.
    		mov	t, #0    ' 25 instructions  (100 cycles) - with 5 cogs outputs a sample every 5 instructions
    ins0		add	t, coeff0
    ins1		add	t, coeff5
    ins2		add	t, coeff10
    ins3		add	t, coeff15
    ins4		add	t, coeff20
    ins5		add	t, coeff25
    		sar	t, #15  ' scale output for OUTA[0:15]
                    add     t, H8000  ' offset for DAC
                  	mov	OUTA, t   ' this cog drives OUTA
    		mov	ins5, ins4  ' move the instructions down and skip 5 coefficients
    		add	ins5, #5
    		mov	ins4, ins3
    		add	ins4, #5
                    mov     OUTA, #0  ' let other cogs control OUTA after 5 instructions
    		mov	ins3, ins2
    	       	add	ins3, #5
    		mov	ins2, ins1
    		add	ins2, #5
    		mov	ins1, ins0
    		add	ins1, #5
             	mov	t, INA    ' get next bit
    		test	t, databit  wc
                    muxc    ins0, subbit  ' change instruction to ADD or SUB
    		jmp	#loop
    subbit          long    %000001_0000_0000_000000000_000000000
    Note that setup code updates the ins0 to ins5 instructions depending on which cog number, so they
    point to the right starting coefficients for that cog.

    The coefficient table being:
    coeff0		long	0
    		long	10546116
    		long	21264445
    		long	26204153
    		long	19797545
    coeff5		long	0
    		long	-29221935
    		long	-57451487
    		long	-70177001
    		long	-53550414
    coeff10		long	0
    		long	87491351
    		long	194391085
    		long	297740106
    		long	372646509
    coeff15		long	400000000
    		long	372646509
    		long	297740106
    		long	194391085
    		long	87491351
    coeff20		long	0
    		long	-53550414
    		long	-70177001
    		long	-57451487
    		long	-29221935
    coeff25		long	0
    		long	19797545
    		long	26204153
    		long	21264445  
    		long	10546116      
    coeff30		long	0
    Spectrum (via a crude 8 bit R-2R ladder DAC):

    The nyquist frequency being 4MHz, for 5 instruction write rate, and the signal rolling off at 400kHz (its 800kbaud)

    This gives plenty of room for a simple analog filter to eliminate the aliases around 4MHz
  • Mark_TMark_T Posts: 1,627
    edited September 26 Vote Up0Vote Down
    Note the bits were generated by an LFSR in another cog.

    Mixing up to RF would double the bandwidth to 800kHz of course.
  • I realized the technique can be extended to 4 levels (or more) rather neatly by having
    2 (or more) copies of the coefficients table, and using incoming bits to both select which
    table and whether an add or sub instruction.

    I created a second table with values scaled to 1/3rd of the original. This gives the option
    for 4 evenly spaced levels (3/3, 1/3, -1/3, -3/3) selected by 2 bits (2 prop pins). A few
    more instructions are needed to set up the instructions, so the loop went from 25 instructions
    to 30, ie each cog is responsible for driving the output for 24 cycles (300ns), giving a
    sample rate of 3.33MSPS rather than 4MSPS. However 2 bits per symbol mean the bit
    rate is 2/5*3.33 = 1.33Mb/s rather then 0.8Mb/s.

    With a bit of persistence on the scope (triggered by one of the bit pins), the eye-pattern
    is clearly visible:


    Looking at the trace you can see the 15 sample delay between input bit and output response, as
    well as comfirming that the trigger trace must be the bit selecting which table, not the one selecting
    the sign.

    Its pretty neat how the traces know to thread through the gaps between the eyes!
  • If anyone want to play with this stuff you need a Propeller with some sort of parallel DAC(*) on pins 0-15 (well 8..15 will do fine for an 8 bit DAC, I just happen to output all 16 bits in the code. I attach the code at the end.

    I've upgraded to a version that does 16 levels, encoding 4 bits per symbol (if this was doubled up on two channels it could generate a 256QAM signal given two RF mixers in quadrature). This produces a more complex eye-diagram as can be seen

    Have fun...

    (*) An R-2R ladder is what I'm using, cobbled together from a bunch of 2k2 16-pin DIP resistor packs

    Baseband spectrum straight off the R-2R:

    The sample rate is 3.333MSPS, the symbol rate is 20% of that, 667kHz, and the bit rate 4 times that at 2.667Mb/s. The
    bandwidth of the baseband signal 333kHz+ a bit due to the raised-cosine filter not being a brick wall (I chose beta=0.33)
Sign In or Register to comment.