Shop OBEX P1 Docs P2 Docs Learn Events
Single Sideband Transmitter - Page 2 — Parallax Forums

Single Sideband Transmitter

2»

Comments

  • @bob_g4bby said:
    What do folks interested in P2 sdr consider the 'best fit' sample size for IQ maths? The first generation PC based sdrs were based on 16 bit stereo sound cards. Nowadays 24 bit a/ds are cheaply available from ebay and the like, although it's not clear to me how many useful bits they deliver. The modulator code above is 16 bit - is that the best? I note the cordic engine works with larger integers / fixed point floats, although that doesn't stop you feeding it with 16 bit data. What maths precision are you using, @SaucySoliton ? I guess the choices are 16, 24 or 32 bit.

    Another aspect I'm not familiar with is integer dsp. I've modified and extended several PC based sdr programs, but those were floating point, internally. Any advice on useful reference books or papers for integer radio dsp?

    Since I was writing a transmitter, audio is 16 bits. But I use 32 bit accumulators for FIR filter output. The cordic converts 32 bit Cartesian to 32 bit polar. I convert phase changes to frequency, that stays 32 bit. Amplitude I scale down to 11 bits for my color-space converter based modulator.

    I don't know of any references for integer DSP. I just try to keep track of the maximum values for each stage. Since multiplication causes the number of bits in use to grow rapidy, strategically placed right shifts are needed. For a lowpass FIR filter I sum up the coefficients to see how much gain the filter has. It's a balancing act. Using too few bits for filter coefficients, or sine/cosine will distort the signal.

    For the filters I used in the posted code, I assume the audio is full range 16 bit signed. I want the filter to run fast, so every single coefficient must fit into 16 bits signed. That way it only needs one MULS instruction. That also ensure that each product fits within a 32 bit signed register. For runtime speed, I also want to use a 32 bit accumulator. So the coefficients need to be reduced slightly from a peak value of 32767. Then I also try to scale the filter coefficients so the gain is a power of 2. That way I can reduce it back to 1 with a fast SAR instruction, instead of costly division. Note that since some coefficients are negative, the sum may be less than the maximum coefficient.

    Would there be any benefits to running a receiver at 24 bits instead of 16? I don't know. Those last 8 bits from the ADC would be really noisy. A 24x16 multiply would be a lot slower than 16x16. It would take two 16x16 multiplies and some shifts and adds. But the P2 would do a 32x16 in the same cycles.

  • AJLAJL Posts: 517
    edited 2023-03-02 09:18

    Ok, another approach, reducing the transfer time between Hub and Cog, taking into account that @bob_g4bby said the loop count might be between 64 and 2048, and presuming that the loop count is likely to be a power of 2 (or at least blocks of 64).
    This code can be wrapped in an outer loop that executes this between 1 and 32 times for 64 to 2048 loops total.

    While the calculation takes approximately twice as long per pair of inputs (a, ib, c, id) the reduction in time taken waiting for the HubRAM to deliver the parameters means the worst case execution time for 64 input pairs should be around 50% of the last effort from @TonyB_
    This code makes heavy use of the powerful indirection capability of the alti instruction. Without it, the code would be bigger and take longer to run with all of the pointer operations being separate instructions. I wouldn't expect anything like my code below to come out of a compiler, but I'm willing to be proven wrong on that point. ;-)

    Note that this consumes at least 167 longs (filling over half of a cog), and I haven't tested this code.
    This could be used in a dedicated cog with no start-up delay using coginit with the e bit set.

    ' On entry:
    '  ptra points to a block of a, ib pairs, signed 16 bits per long
    '  ptrb points to a block of c, id pairs, signed 16 bits per long
    '
    ' On exit:
    ' a 64 long block of processed signed 32 bit results has overwritten the block pointed to by ptra
    ' ptra and ptrb are unchanged allowing this code to be called repeatedly (by coginit with e bit set) if the same Hub RAM buffers are used each time.
    ' BUFA can be relocated in Hub RAM if a SETQ with the new Hub address is executed before the coginit.
    ' If movement of BUFB is desired, a prefix sequence will be required that fetches the address of BUFB from a mailbox in Hub and sets ptrb before falling through to this routine.
    '
      setq #64-1
      rdlong CBUFA, ptra     'BUFA to Reg RAM on a 64 long boundary
      setq #64-1
      rdlong CBUFB, ptrb     'BUFB to Reg RAM on a 64 long boundary
      mov wrt, wrt_d          ' defaults: no redirection, D = CBUFA, S = t1
      mov ptrs, ptrs_d       ' defaults: R = t1, D = CBUFA, S = CBUFB
      rep @.end, #64
      alti ptrs, #RincDincS   ' redirect result, R = t1 D = a S = c, update to R = t2 D = b S = d
      muls 0-0, 0-0               ' t1 = ac
      alti ptrs, #RdecD        '  redirect result, R = t2 D = b S = d, update to R = t2 D = a S = d
      muls 0-0, 0-0               ' t2 = bd
      adds t1, t2                   ' t1 = ac + bd
      alti ptrs, #RincDdecS  ' redirect result, R = t2 D = a S = d, update to R = t3 D = b S = c
      muls 0-0, 0-0                ' t2 = ad
      alti ptrs, #RincDincS   ' redirect result, R = t3 D = b S = c, update to R = 't4' D = nexta S = d
      muls 0-0, 0-0               ' t3 = bc
      adds t2, t3                   ' t2 = ad + bc
      add ptrs, #1                ' update D = nexta S = nextc
      alti wrt, #incDincS     ' no redirection, D = CBUFA + offset S = t1, update to D = CBUFA + offset + 1 S = t2
      mov 0-0, 0-0               ' write t1 to current xx position in CBUFA
      alti wrt, #incDdecS   '  no redirection, D = CBUFA + offset + 1 S = t2, update to D = CBUFA + nextoffset S = t1
      mov 0-0, 0-0              ' write t2 to current yy position in CBUFA
      setr ptrs, #t1             ' point result to t1 for next loop
    .end
      setq #64-1
      wrlong CBUFA, ptra ' write results back to Hub
    
    ptrs_d  #t1<<19 + #CBUFA<<9 + #CBUFB
    wrt_d   #CBUFA<<9 + #t1
    
    RincDincS  %111_011_011_111_111_111
    RdecD        %111_011_011_100_110_100
    RincDdecS %111_011_011_111_111_110
    incDincS    % 011_011_011_000_111_111
    incDdecS   % 011_011_011_000_111_110
    
    ptrs res 1
    wrt res 1
    CBUFA res 64  ' needs to sit on a 64 long boundary
    CBUFB res 64  ' needs to sit on a 64 long boundary
    t1 res 1   'needs to sit on a 4 long boundary
    t2 res 1
    t3 res 1
    

    Feel free to try it or ignore it as you see fit :-)

  • @SaucySoliton said:
    Would there be any benefits to running a receiver at 24 bits instead of 16? I don't know. Those last 8 bits from the ADC would be really noisy. A 24x16 multiply would be a lot slower than 16x16.

    I have to admit that I don't have experience with building my own, so far, but as I understand it I could imagine that higher resolution might have some benefits. If you make voice radio transmissions there are usually many channels with multiple transmitters sending on different channels. If the transmitter you want to receive is far away or has much less power than another transmitter on a nearby channel the stronger signal can override the selected channel by saturating the pre-amplifier or saturate the ADC input.

    In an analogue superheterodyne receiver the channel selection happens in the bandpass filter after the IF mixer. It's all analogue and can have a very high dynamic range.

    However, in a software defined radio the sum of the signals of all channels goes into the ADC input.

    It's input range has to be large enough so that the signal of the strongest transmitter is not clipped. The signal of the selected channel might be 1000 times weaker which means you get only 6 usable bits out of a 16 bit ADC. An adjustable gain amplifier doesn't help because the amplifier sees the sum of all channels.

    As you said, most 24 bit ADCs only have around 16 ENOB. The last 8 bits are noisy. If you choose a very high quality ADC and spend a lot of effort on supply filtering and shielding you might get 18 ENOB. But you don't need hifi adio quality. For speech a bandwidth of 4kHz is sufficient. So you might get 19 or even 20 bits.

  • @ManAtWork said:
    It's input range has to be large enough so that the signal of the strongest transmitter is not clipped. The signal of the selected channel might be 1000 times weaker which means you get only 6 usable bits out of a 16 bit ADC. An adjustable gain amplifier doesn't help because the amplifier sees the sum of all channels.

    As you said, most 24 bit ADCs only have around 16 ENOB. The last 8 bits are noisy. If you choose a very high quality ADC and spend a lot of effort on supply filtering and shielding you might get 18 ENOB. But you don't need hifi adio quality. For speech a bandwidth of 4kHz is sufficient. So you might get 19 or even 20 bits.

    1000 times less voltage means 1000000 times less power or 60 dB. That is ok dynamic range. The FIR filters I design have an ultimate rejection just slightly better than 60 dB. Maybe I need to change from a Hamming window to Blackman or similar.

    The bit depth can be increased with filters. This is how the ADC operates. The data starts as 1 bit at a multi-MHz rate but can become 24 bits at 192kHz. There is no free lunch. This involves a significant reduction in signal bandwidth. An effective 6 bits at 96ksps, when reduced to 8ksps would be almost 10 bits. That's enough for speech.

    I haven't built a receiver or transmitter yet. But the P2 puts out AM/FM/SSB directly so I have tested that.

  • bob_g4bbybob_g4bby Posts: 440
    edited 2023-03-13 14:48

    As the only system I've ever used is Taqoz on P2, I know nothing about the other ides. They all seem a bit beta at present if the forum threads are anything to go by - lots of bug reporting and so on. What is currently my best choice of IDE for writing an sdr application which is a mix of high level language for control signals and assembly language for the signal path? Is it possible to set breakpoints, single step and monitor memory in both high level language and assembly?

  • ManAtWorkManAtWork Posts: 2,178
    edited 2023-03-13 16:38

    Good question. My favorite setup currently is Eric's FlexSpin/C compiler and VSC as IDE plus PNut as debugger. It works but be prepared to spend some time to install it. The QuickByte tutorial is a bit outdated and doesn't tell anything about debugging. You have to read the discussions.

    AKAIK, there is currently no source level single step debugger for anything other than assembly. It is not of much use for real time systems, anyway, where you have to monitor signals on the fly. Graphical debug features of PNut are very well suited for that. If I have to test complicated algorithms with single stepping I do that on a PC and port it to the P2 later.

Sign In or Register to comment.