Subversion Repositories svnkaklik

Rev

Rev 662 | Details | Compare with Previous | Last modification | View Log

Rev Author Line No. Line
662 kaklik 1
///////////////////////////////////////////////////////////////////////////////////
2
//                        A small demo of sonar.
3
// Program allow distance measuring.
4
// Uses cross-correlation algorithm to find echos
5
//
6
// Author: kaklik  (kaklik@mlab.cz)
7
//$Id:$
8
///////////////////////////////////////////////////////////////////////////////////
9
 
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#include <sched.h>
14
#include <errno.h>
15
#include <getopt.h>
16
#include <alsa/asoundlib.h>
17
#include <sys/time.h>
18
#include <math.h>
19
#include <fftw3.h>
20
 
21
#define SOUND_SPEED	340.0	// sound speed in air in metrs per second
22
#define MAX_RANGE	5.0	// maximal working radius in meters
23
 
24
static char *device = "plughw:0,0";			/* playback device */
25
static snd_pcm_format_t format = SND_PCM_FORMAT_S16;	/* sample format */
26
static unsigned int rate = 96000;			/* stream rate */
27
static unsigned int buffer_time = 2 * (MAX_RANGE / SOUND_SPEED * 1e6);		/* ring buffer length in us */
28
static unsigned int period_time = MAX_RANGE / SOUND_SPEED * 1e6;		/* period time in us */
29
static int resample = 1;				/* enable alsa-lib resampling */
30
 
31
unsigned int chirp_size;
32
 
33
static snd_pcm_sframes_t buffer_size;	// size of buffer at sound card
34
static snd_pcm_sframes_t period_size;	//samples per frame
35
static snd_output_t *output = NULL;
36
 
37
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int channels)
38
{
39
    unsigned int rrate;
40
    snd_pcm_uframes_t size;
41
    int err, dir;
42
 
43
    /* choose all parameters */
44
    err = snd_pcm_hw_params_any(handle, params);
45
    if (err < 0)
46
    {
47
        printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
48
        return err;
49
    }
50
    /* set hardware resampling */
51
    err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
52
    if (err < 0)
53
    {
54
        printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
55
        return err;
56
    }
57
    /* set the interleaved read/write format */
58
    err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
59
    if (err < 0)
60
    {
61
        printf("Access type not available for playback: %s\n", snd_strerror(err));
62
        return err;
63
    }
64
    /* set the sample format */
65
    err = snd_pcm_hw_params_set_format(handle, params, format);
66
    if (err < 0)
67
    {
68
        printf("Sample format not available for playback: %s\n", snd_strerror(err));
69
        return err;
70
    }
71
    /* set the count of channels */
72
    err = snd_pcm_hw_params_set_channels(handle, params, channels);
73
    if (err < 0)
74
    {
75
        printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
76
        return err;
77
    }
78
    /* set the stream rate */
79
    rrate = rate;
80
    err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
81
    if (err < 0)
82
    {
83
        printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
84
        return err;
85
    }
86
    if (rrate != rate)
87
    {
88
        printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
89
        return -EINVAL;
90
    }
91
    else printf("Rate set to %i Hz\n", rate, err);
92
    /* set the buffer time */
93
    err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
94
    if (err < 0)
95
    {
96
        printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
97
        return err;
98
    }
99
    err = snd_pcm_hw_params_get_buffer_size(params, &size);
100
    if (err < 0)
101
    {
102
        printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
103
        return err;
104
    }
105
    buffer_size = size;
106
    printf("Bufffer size set to:  %d  Requested buffer time: %ld \n", (int) buffer_size, (long) buffer_time);
107
 
108
 
109
    // set the period time
110
    err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
111
    if (err < 0)
112
    {
113
        printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
114
        return err;
115
    }
116
 
117
    err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
118
    if (err < 0)
119
    {
120
        printf("Unable to get period size for playback: %s\n", snd_strerror(err));
121
        return err;
122
    }
123
    period_size = size;
124
    printf("Period size set to:  %d Requested period time: %ld \n", (int) period_size, (long) period_time);
125
 
126
    /* write the parameters to device */
127
    err = snd_pcm_hw_params(handle, params);
128
    if (err < 0)
129
    {
130
        printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
131
        return err;
132
    }
133
    return 0;
134
}
135
 
136
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
137
{
138
    int err;
139
 
140
    /* get the current swparams */
141
    err = snd_pcm_sw_params_current(handle, swparams);
142
    if (err < 0)
143
    {
144
        printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
145
        return err;
146
    }
147
    // start the transfer when the buffer is almost full: never fou our case
148
    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 2 * buffer_size);
149
    if (err < 0)
150
    {
151
        printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
152
        return err;
153
    }
154
 
155
    err = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
156
    if (err < 0)
157
    {
158
        printf("Unable to set period event: %s\n", snd_strerror(err));
159
        return err;
160
    }
161
 
162
    /* write the parameters to the playback device */
163
    err = snd_pcm_sw_params(handle, swparams);
164
    if (err < 0)
165
    {
166
        printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
167
        return err;
168
    }
169
    return 0;
170
}
171
 
172
////// SIGNAL GENERATION STUFF
173
unsigned int linear_windowed_chirp(short *pole)  // generate the ping signal
174
{
175
    unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1;
176
 
177
    static const float f0 = 5000;		//starting frequency
178
    static const float fmax = 10000;		//ending frequency
179
    static const float Tw = 0.0015;	// time width of ping in seconds 
180
    static float k;
181
 
182
    unsigned int n=0;
183
    double t;
184
    unsigned int chirp_samples;		// number of samples per period
185
 
186
    k=2*(fmax-f0)/Tw;
187
    chirp_samples = ceil(rate*Tw);	// compute size of ping sinal in samples
188
 
189
    for (n=0;n<=chirp_samples;n++)
190
    {
191
        t = (double) n / (double)rate;
663 kaklik 192
        pole[n] = (short) floor( (0.35875 - 0.48829*cos(2*M_PI*t*1/Tw) + 0.14128*cos(2*M_PI*2*t*1/Tw) - 0.01168*cos(2*M_PI*3*t*1/Tw))*maxval*sin(2*M_PI*(t)*(f0+(k/2)*(t))) ); // ping signal generation formula
662 kaklik 193
    }
194
    return (chirp_samples);	// return count of samples in ping
195
}
196
 
197
int main(int argc, char *argv[])
198
{
663 kaklik 199
    snd_pcm_t *playback_handle, *capture_handle;		//variables for driver handlers
662 kaklik 200
    int err;
663 kaklik 201
    snd_pcm_hw_params_t *hwparams;		// hardware and software parameters arrays
662 kaklik 202
    snd_pcm_sw_params_t *swparams;
203
 
663 kaklik 204
    long int *correlationl, *correlationr;	// pointers to arrays where correlation will be stored
662 kaklik 205
    float k;
663 kaklik 206
    int *L_signal, *R_signal;	// array of captured data from left and right channel
207
    short *chirp, *signal;	// chirp and soundcard buffer output data
662 kaklik 208
    unsigned int i,j,m,n;
209
    unsigned int map_size; //number of points in echo map.
210
    long int l,r;  // store correlation at strict time
211
 
212
    FILE *out;		// dummy variable for file data output
213
 
214
    snd_pcm_hw_params_alloca(&hwparams);	// allocation of soundcard parameters registers
215
    snd_pcm_sw_params_alloca(&swparams);
216
 
217
    printf("Simple PC sonar $Rev:$ starting work.. \n");
218
 
219
//open and set playback device
220
    if ((err = snd_pcm_open(&playback_handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
221
    {
222
        printf("Playback open error: %s\n", snd_strerror(err));
223
        return 0;
224
    }
225
 
226
    if ((err = set_hwparams(playback_handle, hwparams, 1)) < 0)
227
    {
228
        printf("Setting of hwparams failed: %s\n", snd_strerror(err));
229
        exit(EXIT_FAILURE);
230
    }
231
    if ((err = set_swparams(playback_handle, swparams)) < 0)
232
    {
233
        printf("Setting of swparams failed: %s\n", snd_strerror(err));
234
        exit(EXIT_FAILURE);
235
    }
236
 
237
//open and set capture device
238
    if ((err = snd_pcm_open(&capture_handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0)
239
    {
240
        printf("Playback open error: %s\n", snd_strerror(err));
241
        return 0;
242
    }
243
 
244
    if ((err = set_hwparams(capture_handle, hwparams, 2)) < 0)
245
    {
246
        printf("Setting of hwparams failed: %s\n", snd_strerror(err));
247
        exit(EXIT_FAILURE);
248
    }
249
    if ((err = set_swparams(capture_handle, swparams)) < 0)
250
    {
251
        printf("Setting of swparams failed: %s\n", snd_strerror(err));
252
        exit(EXIT_FAILURE);
253
    }
254
 
255
    /*    err = snd_pcm_link( capture_handle, playback_handle); //link capture and playback together seems doesn't work 
256
        if (err < 0)
257
        {
258
            printf("Device linking error: %s\n", snd_strerror(err));
259
            exit(EXIT_FAILURE);
260
        }*/
261
 
262
    k = SOUND_SPEED/rate; // normalising constant - normalise sample number to distance
263
 
264
    correlationl = malloc(period_size * sizeof(long int)); //array to store correlation curve
265
    correlationr = malloc(period_size * sizeof(long int)); //array to store correlation curve
266
    L_signal = malloc(period_size * sizeof(int));
267
    R_signal = malloc(period_size * sizeof(int));
268
    chirp = calloc(2*period_size, sizeof(short));
269
    signal = malloc(2*period_size * sizeof(short));
270
 
271
// generate ping pattern
272
    chirp_size = linear_windowed_chirp(chirp);
273
 
274
// write generated chirp data to souncard buffer
275
    err = snd_pcm_writei(playback_handle, chirp, period_size);
276
    if (err < 0)
277
    {
278
        printf("Initial write error: %s\n", snd_strerror(err));
279
        exit(EXIT_FAILURE);
280
    }
281
 
282
//start sream
283
    err = snd_pcm_start(playback_handle);
284
    if (err < 0)
285
    {
286
        printf("Start error: %s\n", snd_strerror(err));
287
        exit(EXIT_FAILURE);
288
    }
289
 
290
    err = snd_pcm_start(capture_handle);
291
    if (err < 0)
292
    {
293
        printf("Start error: %s\n", snd_strerror(err));
294
        exit(EXIT_FAILURE);
295
    }
296
    else printf("Transmitting all samples of chirp\n");
297
//--------------
298
 
663 kaklik 299
    while ( snd_pcm_avail_update(capture_handle) < period_size)			// wait until one period of data is transmitted
662 kaklik 300
    {
301
        usleep(1000);
302
        printf(".");
303
    }
304
 
305
    err = snd_pcm_drop(playback_handle);		// stop audio stream
306
    err = snd_pcm_drain(capture_handle);
307
    if (err < 0)
308
    {
309
        printf("Stop error: %s\n", snd_strerror(err));
310
        exit(EXIT_FAILURE);
311
    }
312
 
313
    err = snd_pcm_readi(capture_handle, signal, period_size);		//read whole period from audio buffer
314
    if (err < 0)
315
    {
316
        printf("Read error: %s\n", snd_strerror(err));
317
        exit(EXIT_FAILURE);
318
    }
319
 
320
    j=0;
321
    for (i=0;i < period_size;i++)		// separe inretleaved samples to two arrays
322
    {
323
        L_signal[i]=signal[j];
324
        R_signal[i]=signal[j+1];
325
        j+=2;
326
    }
327
 
328
    printf("\nChirp transmitted \ncorrelating\n");
329
    for (n=0; n < (period_size - chirp_size - 1); n++)
330
    {
331
        l=0;
332
        r=0;
333
        for ( m = 0; m < chirp_size;m++)
334
        {
335
            l += chirp[m]*L_signal[m+n];	// correlate with left channel
336
            r += chirp[m]*R_signal[m+n];	// correlate with right channel
337
        }
338
        correlationl[n]=abs(l);
339
        correlationr[n]=abs(r);
340
    }
341
 
342
    printf("Writing output files\n");
663 kaklik 343
    out=fopen("/tmp/sonar.txt","w");		// save captured and computed correlation data for both channels
662 kaklik 344
    for (i=0; i <= (period_size - 1); i++)
345
    {
346
        fprintf(out,"%2.3f %6d %6d %9ld %9ld\n",i*k, L_signal[i], R_signal[i], correlationl[i], correlationr[i]);
347
    }
348
    fclose(out);
349
 
663 kaklik 350
    out=fopen("/tmp/chirp.txt","w");		// save chirp data to someone who want it
662 kaklik 351
    for (i=0; i <= (chirp_size - 1); i++)
352
    {
353
        fprintf(out,"%6d %6d\n", i, chirp[i]);
354
    }
355
    fclose(out);
356
 
357
    printf("Job done.\n");
358
 
663 kaklik 359
				//free all arrays 
662 kaklik 360
    free(correlationl);
361
    free(correlationr);
362
    free(L_signal);
363
    free(R_signal);
364
    free(chirp);
365
    free(signal);
366
 
663 kaklik 367
    snd_pcm_close(playback_handle);	// free driver handlers 
662 kaklik 368
    snd_pcm_close(capture_handle);
369
    return 0;
370
}
371