Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/forums/c/)
-   -   unable to generate square wave (http://www.go4expert.com/forums/unable-generate-square-wave-t26508/)

ogopa 16Aug2011 19:12

unable to generate square wave
 
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.

jose_peeterson 17Aug2011 09:45

Re: unable to generate square wave
 
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.

xpi0t0s 17Aug2011 12:58

Re: unable to generate square wave
 
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).

ogopa 17Aug2011 21:54

Re: unable to generate square wave
 
Quote:

Originally Posted by jose_peeterson (Post 86108)
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.

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.

ogopa 17Aug2011 21:54

Re: unable to generate square wave
 
Quote:

Originally Posted by xpi0t0s (Post 86118)
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).


Of course. How silly of me. Thanks

ogopa 17Aug2011 22:19

Re: unable to generate square wave
 
Solution:
The sgn function should only be for the sin function
int a = amplitude_scale * sgn(sin(phase)) * maxval;

ogopa 17Aug2011 22:25

Re: unable to generate square wave
 
Quote:

Originally Posted by jose_peeterson (Post 86108)
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.

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.


All times are GMT +5.5. The time now is 02:28.