Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
558 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)
646 kaklik 7
//$Id:$
558 kaklik 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>
563 kaklik 19
#include <fftw3.h>
558 kaklik 20
 
561 kaklik 21
#define SOUND_SPEED	340.0	// sound speed in air in metrs per second
22
#define MAX_RANGE	10.0	// maximal working radius in meters
643 kaklik 23
#define APERTURE	0.2	// distance between microphones
561 kaklik 24
 
558 kaklik 25
static char *device = "plughw:0,0";			/* playback device */
26
static snd_pcm_format_t format = SND_PCM_FORMAT_S16;	/* sample format */
561 kaklik 27
static unsigned int rate = 96000;			/* stream rate */
562 kaklik 28
static unsigned int buffer_time = 2 * (MAX_RANGE / SOUND_SPEED * 1e6);		/* ring buffer length in us */
29
static unsigned int period_time = MAX_RANGE / SOUND_SPEED * 1e6;		/* period time in us */
558 kaklik 30
static int resample = 1;				/* enable alsa-lib resampling */
31
 
32
unsigned int chirp_size;
33
 
34
static snd_pcm_sframes_t buffer_size;	// size of buffer at sound card
35
static snd_pcm_sframes_t period_size;	//samples per frame
36
static snd_output_t *output = NULL;
37
 
38
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int channels)
39
{
561 kaklik 40
    unsigned int rrate;
41
    snd_pcm_uframes_t size;
42
    int err, dir;
558 kaklik 43
 
561 kaklik 44
    /* choose all parameters */
45
    err = snd_pcm_hw_params_any(handle, params);
46
    if (err < 0)
47
    {
48
        printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
49
        return err;
50
    }
51
    /* set hardware resampling */
52
    err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
53
    if (err < 0)
54
    {
55
        printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
56
        return err;
57
    }
58
    /* set the interleaved read/write format */
59
    err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
60
    if (err < 0)
61
    {
62
        printf("Access type not available for playback: %s\n", snd_strerror(err));
63
        return err;
64
    }
65
    /* set the sample format */
66
    err = snd_pcm_hw_params_set_format(handle, params, format);
67
    if (err < 0)
68
    {
69
        printf("Sample format not available for playback: %s\n", snd_strerror(err));
70
        return err;
71
    }
72
    /* set the count of channels */
73
    err = snd_pcm_hw_params_set_channels(handle, params, channels);
74
    if (err < 0)
75
    {
76
        printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
77
        return err;
78
    }
79
    /* set the stream rate */
80
    rrate = rate;
81
    err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
82
    if (err < 0)
83
    {
84
        printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
85
        return err;
86
    }
87
    if (rrate != rate)
88
    {
89
        printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
90
        return -EINVAL;
91
    }
92
    else printf("Rate set to %i Hz\n", rate, err);
93
    /* set the buffer time */
94
    err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
95
    if (err < 0)
96
    {
97
        printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
98
        return err;
99
    }
100
    err = snd_pcm_hw_params_get_buffer_size(params, &size);
101
    if (err < 0)
102
    {
103
        printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
104
        return err;
105
    }
106
    buffer_size = size;
107
    printf("Bufffer size set to:  %d  Requested buffer time: %ld \n", (int) buffer_size, (long) buffer_time);
108
 
109
 
110
    /// set the period time
111
    err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
112
    if (err < 0)
113
    {
114
        printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
115
        return err;
116
    }
117
 
118
    err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
119
    if (err < 0)
120
    {
121
        printf("Unable to get period size for playback: %s\n", snd_strerror(err));
122
        return err;
123
    }
124
    period_size = size;
125
    printf("Period size set to:  %d Requested period time: %ld \n", (int) period_size, (long) period_time);
126
 
127
    /* write the parameters to device */
128
    err = snd_pcm_hw_params(handle, params);
129
    if (err < 0)
130
    {
131
        printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
132
        return err;
133
    }
134
    return 0;
558 kaklik 135
}
136
 
137
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
138
{
561 kaklik 139
    int err;
558 kaklik 140
 
561 kaklik 141
    /* get the current swparams */
142
    err = snd_pcm_sw_params_current(handle, swparams);
143
    if (err < 0)
144
    {
145
        printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
146
        return err;
147
    }
563 kaklik 148
    // start the transfer when the buffer is almost full: never fou our case
561 kaklik 149
    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 2 * buffer_size);
150
    if (err < 0)
151
    {
152
        printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
153
        return err;
154
    }
155
 
156
    err = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
157
    if (err < 0)
158
    {
159
        printf("Unable to set period event: %s\n", snd_strerror(err));
160
        return err;
161
    }
162
 
163
    /* write the parameters to the playback device */
164
    err = snd_pcm_sw_params(handle, swparams);
165
    if (err < 0)
166
    {
167
        printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
168
        return err;
169
    }
170
    return 0;
558 kaklik 171
}
172
 
173
////// SIGNAL GENERATION STUFF
561 kaklik 174
unsigned int linear_windowed_chirp(short *pole)
558 kaklik 175
{
561 kaklik 176
    unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1;
558 kaklik 177
 
562 kaklik 178
    static const float f0 = 5000;		//starting frequency
565 kaklik 179
    static const float fmax = 10000;		//ending frequency
562 kaklik 180
    static const float Tw = 0.0015;
561 kaklik 181
    static float k;
558 kaklik 182
 
561 kaklik 183
    unsigned int n=0;
184
    double t;
185
    unsigned int chirp_samples;		// number of samples per period
558 kaklik 186
 
561 kaklik 187
    k=2*(fmax-f0)/Tw;
188
    chirp_samples = ceil(rate*Tw);
558 kaklik 189
 
561 kaklik 190
    for (n=0;n<=chirp_samples;n++)
191
    {
192
        t = (double) n / (double)rate;
193
        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))) );
194
    }
195
    return (chirp_samples);
558 kaklik 196
}
197
 
198
int main(int argc, char *argv[])
199
{
561 kaklik 200
    snd_pcm_t *playback_handle, *capture_handle;
201
    int err;
202
    snd_pcm_hw_params_t *hwparams;
203
    snd_pcm_sw_params_t *swparams;
558 kaklik 204
 
562 kaklik 205
    long int *correlationl, *correlationr;
646 kaklik 206
    float *echo_map;
562 kaklik 207
    int *L_signal, *R_signal;
208
    short *chirp, *signal;
623 kaklik 209
    float *chirp_spect, *lecho_spect, *recho_spect;
644 kaklik 210
    float x,y;
561 kaklik 211
    unsigned int i,j,m,n;
563 kaklik 212
    unsigned int delayl[10],delayr[10];	//store delay of signifed correlation
561 kaklik 213
    long int l,r;  // store correlation at strict time
563 kaklik 214
    double df;	//frequency resolution 
215
    unsigned int frequency_bins; // number of output frequency bins 
558 kaklik 216
 
563 kaklik 217
    double *inchirp;
218
    fftw_complex *outchirp;
219
    fftw_plan fft_plan_chirp;
220
 
561 kaklik 221
    FILE *out;
558 kaklik 222
 
561 kaklik 223
    snd_pcm_hw_params_alloca(&hwparams);
224
    snd_pcm_sw_params_alloca(&swparams);
558 kaklik 225
 
646 kaklik 226
    printf("Simple PC sonar $Rev:$ starting work.. \n");
558 kaklik 227
 
228
//open and set playback device
561 kaklik 229
    if ((err = snd_pcm_open(&playback_handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
230
    {
231
        printf("Playback open error: %s\n", snd_strerror(err));
232
        return 0;
233
    }
558 kaklik 234
 
561 kaklik 235
    if ((err = set_hwparams(playback_handle, hwparams, 1)) < 0)
236
    {
237
        printf("Setting of hwparams failed: %s\n", snd_strerror(err));
238
        exit(EXIT_FAILURE);
239
    }
240
    if ((err = set_swparams(playback_handle, swparams)) < 0)
241
    {
242
        printf("Setting of swparams failed: %s\n", snd_strerror(err));
243
        exit(EXIT_FAILURE);
244
    }
245
 
558 kaklik 246
//open and set capture device
561 kaklik 247
    if ((err = snd_pcm_open(&capture_handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0)
248
    {
249
        printf("Playback open error: %s\n", snd_strerror(err));
250
        return 0;
251
    }
558 kaklik 252
 
561 kaklik 253
    if ((err = set_hwparams(capture_handle, hwparams, 2)) < 0)
254
    {
255
        printf("Setting of hwparams failed: %s\n", snd_strerror(err));
256
        exit(EXIT_FAILURE);
257
    }
258
    if ((err = set_swparams(capture_handle, swparams)) < 0)
259
    {
260
        printf("Setting of swparams failed: %s\n", snd_strerror(err));
261
        exit(EXIT_FAILURE);
262
    }
263
 
563 kaklik 264
    /*    err = snd_pcm_link( capture_handle, playback_handle); //link capture and playback together
265
        if (err < 0)
266
        {
267
            printf("Device linking error: %s\n", snd_strerror(err));
268
            exit(EXIT_FAILURE);
269
        }*/
558 kaklik 270
 
562 kaklik 271
    correlationl = malloc(period_size * sizeof(long int)); //array to store correlation curve
272
    correlationr = malloc(period_size * sizeof(long int)); //array to store correlation curve
273
    L_signal = malloc(period_size * sizeof(int));
274
    R_signal = malloc(period_size * sizeof(int));
275
    chirp = calloc(2*period_size, sizeof(short));
276
    signal = malloc(2*period_size * sizeof(short));
646 kaklik 277
    echo_map = malloc(3*period_size * sizeof(float));   // Array to store two dimensional image of echos
558 kaklik 278
 
562 kaklik 279
// generate ping pattern
280
    chirp_size = linear_windowed_chirp(chirp);
281
 
563 kaklik 282
    frequency_bins = chirp_size / 2 + 1;
283
    df = (double) rate / (double) chirp_size;
284
    chirp_spect = malloc(frequency_bins * sizeof(float));
623 kaklik 285
    lecho_spect = malloc(frequency_bins * sizeof(float));
286
    recho_spect = malloc(frequency_bins * sizeof(float));
563 kaklik 287
 
288
    inchirp = fftw_malloc(sizeof(double) * chirp_size); 		// allocate input array for FFT
289
    outchirp = fftw_malloc(sizeof(fftw_complex) * frequency_bins);
290
 
291
    fft_plan_chirp = fftw_plan_dft_r2c_1d(chirp_size, inchirp, outchirp, FFTW_ESTIMATE);
292
 
293
    printf("compute chirp spectrum\n");
294
    for(i=0; i < chirp_size; i++) inchirp[i] = chirp[i];
295
    fftw_execute(fft_plan_chirp);
296
    for(i=0; i < frequency_bins; i++) chirp_spect[i] = sqrt( outchirp[i][0] * outchirp[i][0] + outchirp[i][1] * outchirp[i][1] );
297
 
298
// write chirp data to souncard buffer
561 kaklik 299
    err = snd_pcm_writei(playback_handle, chirp, period_size);
300
    if (err < 0)
301
    {
302
        printf("Initial write error: %s\n", snd_strerror(err));
303
        exit(EXIT_FAILURE);
304
    }
560 kaklik 305
 
562 kaklik 306
//start sream
307
    err = snd_pcm_start(playback_handle);
561 kaklik 308
    if (err < 0)
309
    {
562 kaklik 310
        printf("Start error: %s\n", snd_strerror(err));
561 kaklik 311
        exit(EXIT_FAILURE);
312
    }
558 kaklik 313
 
562 kaklik 314
    err = snd_pcm_start(capture_handle);
561 kaklik 315
    if (err < 0)
316
    {
317
        printf("Start error: %s\n", snd_strerror(err));
318
        exit(EXIT_FAILURE);
319
    }
640 kaklik 320
    else printf("Transmitting all samples of chirp\n");
562 kaklik 321
//--------------
564 kaklik 322
 
323
    while ( snd_pcm_avail_update(capture_handle) < period_size)			// wait for one period of data
561 kaklik 324
    {
325
        usleep(1000);
326
        printf(".");
327
    }
558 kaklik 328
 
564 kaklik 329
    err = snd_pcm_drop(playback_handle);		// stop audio stream
562 kaklik 330
    err = snd_pcm_drain(capture_handle);
561 kaklik 331
    if (err < 0)
332
    {
333
        printf("Stop error: %s\n", snd_strerror(err));
334
        exit(EXIT_FAILURE);
335
    }
558 kaklik 336
 
564 kaklik 337
    err = snd_pcm_readi(capture_handle, signal, period_size);		//read period from audio buffer
562 kaklik 338
    if (err < 0)
339
    {
340
        printf("Read error: %s\n", snd_strerror(err));
341
        exit(EXIT_FAILURE);
342
    }
558 kaklik 343
 
561 kaklik 344
    j=0;
562 kaklik 345
    for (i=0;i < period_size;i++)		// separe inretleaved samples to two arrays
561 kaklik 346
    {
347
        L_signal[i]=signal[j];
348
        R_signal[i]=signal[j+1];
349
        j+=2;
350
    }
558 kaklik 351
 
562 kaklik 352
    printf("\nData transmitted \ncorrelating\n");
353
    for (n=0; n < (period_size - chirp_size - 1); n++)
561 kaklik 354
    {
355
        l=0;
356
        r=0;
563 kaklik 357
        for ( m = 0; m < chirp_size;m++)
561 kaklik 358
        {
558 kaklik 359
            l += chirp[m]*L_signal[m+n];	// correlate with left channel
360
            r += chirp[m]*R_signal[m+n];	// correlate with right channel
561 kaklik 361
        }
563 kaklik 362
        correlationl[n]=abs(l);
363
        correlationr[n]=abs(r);
561 kaklik 364
    }
558 kaklik 365
 
646 kaklik 366
    m=0;
643 kaklik 367
    printf("Building echo map\n");		// compute map from left and right correlation data
646 kaklik 368
	for (i=0;i < period_size; i++)
644 kaklik 369
	{
646 kaklik 370
		for(j=0;j < period_size; j++)
371
		{
372
			echo_map[m]=(i*i-j*j+APERTURE*APERTURE)/(2*APERTURE);
373
			echo_map[m+1]=sqrt(-(i-j-APERTURE)*(i+j-APERTURE)*(i-j+APERTURE)*(i+j+APERTURE))/(2*r);
374
			echo_map[m+2]=correlationl[i]*correlationr[j];
375
			m+=3;
376
		}
644 kaklik 377
	}
643 kaklik 378
 
379
 
562 kaklik 380
    printf("Searching echos\n");
561 kaklik 381
    r=0;
382
    l=0;
562 kaklik 383
    for (n=0; n < period_size;n++) 			//najde nejvetsi korelace
561 kaklik 384
    {
385
        if (l < correlationl[n])
386
        {
563 kaklik 387
            delayl[1] = n;
561 kaklik 388
            l = correlationl[n];
389
        }
390
        if (r < correlationr[n])
391
        {
563 kaklik 392
            delayr[1] = n;
561 kaklik 393
            r = correlationr[n];
394
        }
395
    }
558 kaklik 396
 
646 kaklik 397
//spocitej frekvencni spektrum pro levy kanal
564 kaklik 398
    for(i=delayl[1]; i < delayl[1] + chirp_size; i++) inchirp[i-delayl[1]] = L_signal[i];
399
    fftw_execute(fft_plan_chirp);
623 kaklik 400
    for(i=0; i < frequency_bins; i++) lecho_spect[i] = sqrt(outchirp[i][0] * outchirp[i][0] + outchirp[i][1] * outchirp[i][1]);
563 kaklik 401
 
641 kaklik 402
 
403
// napln pole daty z praveho kanalu a spocitej frekvencni spektrum
623 kaklik 404
    for(i=delayr[1]; i < delayr[1] + chirp_size; i++) inchirp[i-delayr[1]] = R_signal[i];
405
    fftw_execute(fft_plan_chirp);
406
    for(i=0; i < frequency_bins; i++) recho_spect[i] = sqrt(outchirp[i][0] * outchirp[i][0] + outchirp[i][1] * outchirp[i][1]);
407
 
564 kaklik 408
    printf("Writing output files\n");
561 kaklik 409
    out=fopen("/tmp/sonar.txt","w");
563 kaklik 410
    for (i=0; i <= (period_size - 1); i++)
561 kaklik 411
    {
565 kaklik 412
        fprintf(out,"%2.3f %6d %6d %9ld %9ld\n",SOUND_SPEED * (float) i / rate,L_signal[i],R_signal[i],correlationl[i], correlationr[i]);
561 kaklik 413
    }
414
    fclose(out);
558 kaklik 415
 
646 kaklik 416
    j=0;
644 kaklik 417
    out=fopen("/tmp/plane_cut.txt","w"); // writes plane cut - e.g. density map to file
646 kaklik 418
    for (i=0;i < period_size; i++)
643 kaklik 419
    {
646 kaklik 420
	fprintf(out,"%3.2f %3.2f %3.2f\n", echo_map[j], echo_map[j+1], echo_map[j+2]);
421
	j+=3;
643 kaklik 422
    }
423
 
563 kaklik 424
    out=fopen("/tmp/chirp.txt","w");
425
    for (i=0; i <= (chirp_size - 1); i++)
426
    {
564 kaklik 427
        fprintf(out,"%6d %6d\n", i, chirp[i]);
563 kaklik 428
    }
429
    fclose(out);
558 kaklik 430
 
564 kaklik 431
    out=fopen("/tmp/echo.txt","w");
623 kaklik 432
    for(i=0; i < chirp_size; i++) fprintf(out,"%6d %6d %6d\n", i, L_signal[i + delayl[1]], R_signal[i + delayr[1]]);
564 kaklik 433
    fclose(out);
434
 
435
    out=fopen("/tmp/spektra.txt","w");
436
    for (i=0; i < frequency_bins; i++)
437
    {
623 kaklik 438
        fprintf(out,"%4.3f %4.3f %4.3f %4.3f\n", (i+0.5) * df, chirp_spect[i], lecho_spect[i], recho_spect[i]);
564 kaklik 439
    }
440
    fclose(out);
441
 
563 kaklik 442
    free(correlationl);
443
    free(correlationr);
444
    free(L_signal);
445
    free(R_signal);
446
    free(chirp);
447
    free(signal);
646 kaklik 448
    free(echo_map);
563 kaklik 449
 
561 kaklik 450
    snd_pcm_close(playback_handle);
451
    snd_pcm_close(capture_handle);
452
    return 0;
558 kaklik 453
}
454