File: iirdes_pll_example.c

package info (click to toggle)
liquid-dsp 1.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,216 kB
  • sloc: ansic: 115,859; sh: 3,513; makefile: 1,350; python: 274; asm: 11
file content (150 lines) | stat: -rw-r--r-- 4,680 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//
// iirdes_pll_example.c
//
// This example demonstrates 2nd-order IIR phase-locked loop filter
// design with a practical simulation.
//
// SEE ALSO: nco_pll_example.c
//           nco_pll_modem_example.c
//

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <getopt.h>

#include "liquid.h"

#define OUTPUT_FILENAME "iirdes_pll_example.m"

// print usage/help message
void usage()
{
    printf("iirdes_pll_example [options]\n");
    printf("  u/h   : print usage\n");
    printf("  b     : pll bandwidth, default: 0.01\n");
    printf("  z     : zeta (damping factor), default 0.70711\n");
    printf("  K     : loop filter gain, default: 1000\n");
    printf("  n     : number of samples, default: 512\n");
    printf("  p     : phase offset (radians), default: pi/4\n");
    printf("  f     : frequency offset (radians), default: 0.3\n");
}

int main(int argc, char*argv[]) {
    srand( time(NULL) );

    // options
    float phase_offset = M_PI / 4.0f;   // phase offset
    float frequency_offset = 0.3f;      // frequency offset
    float pll_bandwidth = 0.01f;        // PLL bandwidth
    float zeta = 1/sqrtf(2.0f);         // PLL damping factor
    float K = 1000.0f;                  // PLL loop gain
    unsigned int n=512;                 // number of iterations

    int dopt;
    while ((dopt = getopt(argc,argv,"uhb:z:K:n:p:f:")) != EOF) {
        switch (dopt) {
        case 'u':
        case 'h':   usage();    return 0;
        case 'b':   pll_bandwidth = atof(optarg);   break;
        case 'z':   zeta = atof(optarg);            break;
        case 'K':   K = atof(optarg);               break;
        case 'n':   n = atoi(optarg);               break;
        case 'p':   phase_offset = atof(optarg);    break;
        case 'f':   frequency_offset= atof(optarg); break;
        default:
            exit(1);
        }
    }
    unsigned int d=n/32;      // print every "d" lines

    // validate input
    if (pll_bandwidth <= 0.0f) {
        fprintf(stderr,"error: bandwidth must be greater than 0\n");
        exit(1);
    } else if (zeta <= 0.0f) {
        fprintf(stderr,"error: damping factor must be greater than 0\n");
        exit(1);
    } else if (K <= 0.0f) {
        fprintf(stderr,"error: loop gain must be greater than 0\n");
        exit(1);
    }

    // data arrays
    float complex x[n];         // input complex sinusoid
    float complex y[n];         // output complex sinusoid
    float phase_error[n];       // output phase error

    // generate PLL filter
    float b[3];
    float a[3];
    iirdes_pll_active_lag(pll_bandwidth, zeta, K, b, a);
    iirfilt_rrrf pll = iirfilt_rrrf_create(b,3,a,3);
    iirfilt_rrrf_print(pll);

    unsigned int i;
    float phi;
    for (i=0; i<n; i++) {
        phi = phase_offset + i*frequency_offset;
        x[i] = cexpf(_Complex_I*phi);
    }

    // run loop
    float theta = 0.0f;
    y[0] = 1.0f;
    for (i=0; i<n; i++) {

        // generate complex sinusoid
        y[i] = cexpf(_Complex_I*theta);

        // compute phase error
        phase_error[i] = cargf(x[i]*conjf(y[i]));

        // update pll
        iirfilt_rrrf_execute(pll, phase_error[i], &theta);

        // print phase error
        if ((i)%d == 0 || i==n-1 || i==0)
            printf("%4u : phase error = %12.8f\n", i, phase_error[i]);
    }

    // destroy filter object
    iirfilt_rrrf_destroy(pll);

    // write output file
    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all;\n");
    fprintf(fid,"close all;\n");
    fprintf(fid,"n = %u;\n", n);
    fprintf(fid,"x = zeros(1,n);\n");
    fprintf(fid,"y = zeros(1,n);\n");
    for (i=0; i<n; i++) {
        fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i]));
        fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i]));
        fprintf(fid,"e(%4u) = %12.4e;\n", i+1, phase_error[i]);
    }
    fprintf(fid,"t=0:(n-1);\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"subplot(2,1,1);\n");
    fprintf(fid,"  plot(t,real(x),t,real(y));\n");
    fprintf(fid,"  xlabel('time');\n");
    fprintf(fid,"  ylabel('real');\n");
    fprintf(fid,"subplot(2,1,2);\n");
    fprintf(fid,"  plot(t,imag(x),t,imag(y));\n");
    fprintf(fid,"  xlabel('time');\n");
    fprintf(fid,"  ylabel('imag');\n");

    fprintf(fid,"figure;\n");
    fprintf(fid,"plot(t,e);\n");
    fprintf(fid,"xlabel('time');\n");
    fprintf(fid,"ylabel('phase error');\n");
    fprintf(fid,"grid on;\n");

    fclose(fid);
    printf("results written to %s.\n",OUTPUT_FILENAME);

    printf("done.\n");
    return 0;
}