Thread: Differential PSK Signalling

  1. #1
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,273

    Question Differential PSK Signalling

    Hello,

    Well I've managed to end up going down another tangent (was supposed to be finishing xmas shopping today!) and decided upon exploring how analogue modems work. I'm not really interested in developing my own Winmodem, just looking at the way the signalling works (slow signalling, so I can see the waves and stuff).

    What I'm looking at is developing a means of transferring stuff between two computers via their sound cards. Line In connected to Line Out and vice versa. I've settled upon trying to implement the ITU V.22 standard, which was created in the 80s and provided up to the princely baud rate of 1200. I'm looking to implement only the 600 baud mode!

    Now, V.22 uses differential Phase-shift Keying (PSK). As they have to share the same phone line, the calling modem judders around on 1200 Hz and the answering modem on 2400 Hz.

    I've had a go at creating a small program that takes any file as input and produces a wave file that certainly sounds "datary", but I've come across a couple snags:-

    1. Requiring 80 samples per modulated bit produces massive wave files(!);
    2. I've nothing to compare it against.

    I can probably fix 1. if I knew what the lowest sample rate for this type of thing would still work, but 2. has me stumped.

    Does anyone know where I can find example sound files of a V.22 transmission or other software capable of generating this stuff?

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by SMurf View Post
    1. Requiring 80 samples per modulated bit produces massive wave files(!);
    As you suspect, you can just lower the sample rate. PSK has an okay spectral efficiency, so estimating the highest frequency as a bit above 2400 Hz will probably work -- say, 3000 Hz to be on the safe side. That implies a minimum sampling rate of 6000 Hz. You'll need to round up to the nearest rate supported by the transmitter and the receiver.

    In practice, you could experiment with the sampling rate -- getting it too low for the signal content will introduce aliasing, which will be pretty obvious if you look at a spectrogram.

    EDIT: Another thing you could try, since the total bandwidth is obviously not that big, is to heterodyne the signal down using a lower frequency carrier then resample it at a much lower rate -- in other words, move the signal to the base band instead of sitting centered around 2400 Hz. You'd have to heterodyne it back up again before playback.

    2. I've nothing to compare it against.
    Yeah.. You might be able to find v.22 code somewhere inside GNU Radio or some related project. But really, it's just straight DPSK and you've either implemented it or you haven't. Willing to post any code?

    It's cool to see you working on this. I have a software modem project in the foggy past as well. Honestly, I'd be more interested in applying some of the newer techniques from 802.11 and cellular communication to sonic waveforms -- not sure anyone's really tried that.
    Last edited by brewbuck; 12-22-2010 at 09:02 PM.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  3. #3
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    PSK can be either 2, 3 or 4 tone signalling... with 2 tone signalling at say 800 and 1200hz, which is about the highest you're going to stuff through a phone line, you can probably transfer about 300 bits per second. You need at least 1 full cycle of your lowest frequency to discriminate between 0 and 1... But you need more than that, to keep the transfers synchronized you also need byte framing (start and stop bits), packet framing (header, data footer) and data integrity checking (checksums, ACK and NAK). It's a big job.

    The easiest way to discriminate 0 and 1 is to see how many cycles of ac you got. 1 cycle (i.e. 1 positive and 1 negative edge) usually means 0 and 1.5 (eg. 2+ and 1- or 2- and 1+) usually means a 1. Believe me, this is a lot easier to do with edge triggered hardware than it is in software.

    You should only need 3 or 4 samples per bit, then just count the 1s and 0s that come out of it...
    The trick is to use signalling tones that are not harmonically related.

  4. #4
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,273
    Quote Originally Posted by brewbuck View Post
    Willing to post any code?
    Sure. This was mainly influenced by looking at Ernest R. Schreurs's CAS2WAV source code anyway. Yes, I spent my early childhood listening to data tapes load. I'm sad.
    Code:
    // Converts any file into a 600 baud PSK wave file
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define PI                        3.14159265358979323846
    
    int main(int argc, char **argv)
    {
        double dWave;
        int bPrev, i, j, k, l;
        long lSize;
        unsigned char *lpWave;
        unsigned long ulTemp;
        FILE *fpIn, *fpOut;
    
        printf("Phase Shift Keying (PSK) 1200 Hz Encoder\n");
        if (argc != 2)
        {
            printf("Usage: pskwrite <filename>\n\n");
            return 0;
        }
    
        // This was originally an allocation for a 1 second buffer (48,000 bytes)
        // Could probably take this from the stack now...
        lpWave = malloc(80);
        if (!lpWave)
        {
            printf("ERROR: Couldn't allocate 80 bytes!\n\n");
            return -1;
        }
    
        // get the unit change of the sine wave across the wave buffer
        dWave = (2 * PI * 1200) / 48000;
        // generate the wave for later use
        for (i=0;i<80;i++)
            lpWave[i] = (unsigned char)((sin(i * dWave) * 63) + 127);
    
        // open the source and get size
        fpIn = fopen(argv[1], "rb");
        if (!fpIn)
        {
            printf("ERROR: Couldn't open file for reading!\n\n");
            return -1;
        }
    
        fseek(fpIn, 0, SEEK_END);
        lSize = ftell(fpIn) * 8 * 80; // 80 samples per wave or bit
        // experience told me that this was a good idea :)
        printf("Resultant wave data will be %ld bytes in size.  Continue? (Y/N): ", lSize);
        i = fgetc(stdin);
        if (i != 'y' && i != 'Y')
        {
            fclose(fpIn);
            printf("Aborted.\n\n");
            return 0;
        }
    
        fseek(fpIn, 0, SEEK_SET);
        // open the destination file and write header
        fpOut = fopen("output.wav", "wb");
        fwrite("RIFF", 4, 1, fpOut);
        ulTemp = lSize + 32;
        fwrite(&ulTemp, 4, 1, fpOut);
        fwrite("WAVE", 4, 1, fpOut);
        fwrite("fmt ", 4, 1, fpOut);
        ulTemp = 16;
        fwrite(&ulTemp, 4, 1, fpOut);
        ulTemp = 1;
        fwrite(&ulTemp, 2, 1, fpOut); // WAVE_FORMAT_PCM
        fwrite(&ulTemp, 2, 1, fpOut); // number of channels
        ulTemp = 48000;
        fwrite(&ulTemp, 4, 1, fpOut); // sample rate
        fwrite(&ulTemp, 4, 1, fpOut); // bytes per sec
        ulTemp = 1;
        fwrite(&ulTemp, 2, 1, fpOut); // block alignment
        ulTemp = 8;
        fwrite(&ulTemp, 2, 1, fpOut); // bits per sample
        fwrite("data", 4, 1, fpOut);
        fwrite(&lSize, 4, 1, fpOut);
        bPrev = 0;
        // process all source bytes
        while ((i = fgetc(fpIn)) != EOF)
        {
            // for each bit
            for (j=0;j<8;j++)
            {
                // not sure if this is right...
                // differential is relative to the previous bit,
                // according to the V.22 spec the phase encoding is
                // +90 degrees for a 0 and +270 degrees for a 1
                if (i & (1 << j))
                {
                    k = (!bPrev) ? 20 : 0; 
                    bPrev = 1;
                }
                else
                {
                    k = (bPrev) ? 20 : 0;
                    bPrev = 0;
                }
    
                // write the wave from the buffer to the file
                for (l=0;l<80;l++)
                {
                    if (fputc(lpWave[k], fpOut) == EOF)
                    {
                        fclose(fpOut);
                        fclose(fpIn);
                        free(lpWave);
                        printf("ERROR: Write failure!\n\n");
                        return -1;
                    }
    
                    // circular buffer
                    if (k + 1 < 80)
                        k++;
                    else
                        k = 0;
    
                }
    
            }
    
        }
    
        fclose(fpOut);
        fclose(fpIn);
        free(lpWave);
        return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. differential equation??
    By kypronite in forum Game Programming
    Replies: 11
    Last Post: 09-03-2008, 05:25 PM
  2. Differential Equations - I need Help
    By KneeGrow in forum A Brief History of Cprogramming.com
    Replies: 9
    Last Post: 03-28-2004, 11:30 PM
  3. Differential Equations
    By KneeGrow in forum A Brief History of Cprogramming.com
    Replies: 4
    Last Post: 03-26-2004, 09:54 PM
  4. Differential Equations question
    By PJYelton in forum A Brief History of Cprogramming.com
    Replies: 6
    Last Post: 08-20-2003, 08:54 AM