unable to generate square wave

Discussion in 'C' started by ogopa, Aug 16, 2011.

  1. ogopa

    ogopa New Member

    Joined:
    Aug 16, 2011
    Messages:
    7
    Likes Received:
    1
    Trophy Points:
    0
    Square wave = sign(sinusoidal wave)
    So then why isn't the following code creating a square wave:
    Code:
    int sgn(double d){
      if (d>=0) d=1;
       else d=-1;
      return d;
        }
    
    static void generate_square(const snd_pcm_channel_area_t *areas, 
                               snd_pcm_uframes_t offset,
                               int count, double *_phase)
    {
        static double max_phase = 2. * M_PI;
        double phase = *_phase;
        double step = max_phase*freq/(double)rate;
        unsigned char *samples[channels];
        int steps[channels];
        unsigned int chn;
        int format_bits = snd_pcm_format_width(format);
        unsigned int maxval = (1 << (format_bits - 1)) - 1;
        int bps = format_bits / 8;  // bytes per sample 
        int phys_bps = snd_pcm_format_physical_width(format) / 8;
        int big_endian = snd_pcm_format_big_endian(format) == 1;
        int to_unsigned = snd_pcm_format_unsigned(format) == 1;
        int is_float = (format == SND_PCM_FORMAT_FLOAT_LE ||
                        format == SND_PCM_FORMAT_FLOAT_BE);
        double amplitude_scale = amplitude/8.56;
    
    
        // verify and prepare the contents of areas 
        for (chn = 0; chn < channels; chn++) {
                if ((areas[chn].first % 8) != 0) {
                        printf("areas[%i].first == %i, aborting...", chn , areas[chn].first);
                        exit(EXIT_FAILURE);
                }
                samples[chn] = (((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
               if ((areas[chn].step % 16) != 0) {
                       // printf("areas[%i].step == %i, aborting...  ", chn areas[chn].step);
                       exit(EXIT_FAILURE);
                }
                steps[chn] = areas[chn].step / 8;
                samples[chn] += offset * steps[chn];
        }
        // fill the channel areas 
        while (count-- > 0) {
                union {
                        float f;
                        int i;
                } fval;
                int res, i;
                if (is_float) {
                int a = sgn(amplitude_scale * sin(phase) * maxval);
                        fval.f = (float) a;
                        res = fval.i;
                } else { 
                int b = sgn(amplitude_scale * sin(phase) * maxval);
                        res = b;
            }
                        
    
                if (to_unsigned)
                        res ^= 1U << (format_bits - 1);
                for (chn = 0; chn < channels; chn++) {
                        // Generate data in native endian format 
                        if (big_endian) {
                                for (i = 0; i < bps; i++)
                                        *(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff;
                        } else {
                                for (i = 0; i < bps; i++)
                                        *(samples[chn] + i) = (res >>  i * 8) & 0xff;
                        }
                        samples[chn] += steps[chn];
                }
                phase += step;
                if (phase >= max_phase)
                        phase -= max_phase;
        }
        *_phase = phase;
    
    }
    
    If I take out the sgn function from the code, it generates a sine wave. Any help would be greatly appreciated.
     
  2. jose_peeterson

    jose_peeterson New Member

    Joined:
    May 19, 2011
    Messages:
    56
    Likes Received:
    1
    Trophy Points:
    0
    hi i am studying electrical engineering. and i have not seen anything like this is in c.SORRY i cant help you but can you tell me how you did this and what you are doing.
    how do you do this in c? i might learn and try thanks.
     
  3. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,009
    Likes Received:
    203
    Trophy Points:
    63
    Occupation:
    Senior Support Engineer
    Location:
    England
    Bit tricky as several variables that have a bearing are not defined (freq, rate, amplitude and probably others); you don't say what output you DO get or what output you get when you miss off the sgn (other than that it is a sine wave).

    At a guess you're probably running into C's fondness of converting everything to integers. Try casting maxval to a double and see what happens, i.e.:
    Code:
    int a = sgn(amplitude_scale * sin(phase) * (double)maxval);
    
    Does the sine wave that you get when you miss of sgn() vary from -amplitude_scale*maxval to +amplitude_scale*maxval or from 0 to some maximum? If so then you don't have a sine wave as such, you have sin()+offset, which would not convert to a square with a simple call to sgn(); you would have to subtract the offset, call sgn then add the offset back in.

    For more accurate analysis please upload a minimal program that is complete and that shows the output for the two test points pi/2 and 3pi/2 (i.e. the turning points, which will be +1 and -1 whether sgn is called or not).
     
  4. ogopa

    ogopa New Member

    Joined:
    Aug 16, 2011
    Messages:
    7
    Likes Received:
    1
    Trophy Points:
    0
    Hi this is actually a sample c program that I got form the ALSA website. It is called pcm.c. It is for Linux based systems.
    I can't seem to post the link. So if you google pcm.c, it is the first result.
     
    jose_peeterson likes this.
  5. ogopa

    ogopa New Member

    Joined:
    Aug 16, 2011
    Messages:
    7
    Likes Received:
    1
    Trophy Points:
    0

    Of course. How silly of me. Thanks
     
  6. ogopa

    ogopa New Member

    Joined:
    Aug 16, 2011
    Messages:
    7
    Likes Received:
    1
    Trophy Points:
    0
    Solution:
    The sgn function should only be for the sin function
    int a = amplitude_scale * sgn(sin(phase)) * maxval;
     
  7. ogopa

    ogopa New Member

    Joined:
    Aug 16, 2011
    Messages:
    7
    Likes Received:
    1
    Trophy Points:
    0
    Sorry I realised that I didn't explain fully what I was doing in my first reply to you. I am trying to build a gui that will output a sine and square wave with user inputs of frequency and amplitude. I am using the sample code form the alsa website called pcm.c which generates a sine wave. It is code for alsa on linux systems. I have built the gui and have integrated the sine wave and I am now trying to implement the square wave.
    Good luck in your learnings.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice