1 //
2 // conversion_example.c
3 //
4 // This example demonstrates conversion from complex baseband to a real-valued
5 // signal, and then down-conversion back to complex baseband while removing the
6 // negative image.
7 //
8 //  STEP 1: A signal is generated at complex baseband consisting of narrow-band
9 //          filtered noise and an offset tone (to show asymmetry in the transmit
10 //          spectrum).
11 //
12 //  STEP 2: The signal is mixed up to a carrier 'fc' (relative to the sampling
13 //          frequency) and the real-component of the result is retained. This is
14 //          the DAC output. The spectrum of this signal has two images: one at
15 //          +fc, the other at -fc.
16 //
17 //  STEP 3: The DAC output is mixed back down to complex baseband and the lower
18 //          image is (mostly) filtered off. Reminants of the lower frequency
19 //          component are still visible due to the wide-band and low-order
20 //          filter on the receiver. The received complex baseband signal also
21 //          has a reduction in power by 2 because half the signal's energy (the
22 //          negative image) is filtered off.
23 //
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <math.h>
28 
29 #include "liquid.h"
30 
31 #define OUTPUT_FILENAME "conversion_example.m"
32 
main()33 int main()
34 {
35     // spectral periodogram options
36     unsigned int nfft        =   1200;  // spectral periodogram FFT size
37     unsigned int num_samples =  64000;  // number of samples
38     float        fc          =   0.20f; // carrier (relative to sampling rate)
39 
40     // create objects
41     iirfilt_crcf   filter_tx    = iirfilt_crcf_create_lowpass(15, 0.05);
42     nco_crcf       mixer_tx     = nco_crcf_create(LIQUID_VCO);
43     nco_crcf       mixer_rx     = nco_crcf_create(LIQUID_VCO);
44     iirfilt_crcf   filter_rx    = iirfilt_crcf_create_lowpass(7, 0.2);
45 
46     // set carrier frequencies
47     nco_crcf_set_frequency(mixer_tx, fc * 2*M_PI);
48     nco_crcf_set_frequency(mixer_rx, fc * 2*M_PI);
49 
50     // create objects for measuring power spectral density
51     spgramcf spgram_tx  = spgramcf_create_default(nfft);
52     spgramf  spgram_dac = spgramf_create_default(nfft);
53     spgramcf spgram_rx  = spgramcf_create_default(nfft);
54 
55     // run through loop one step at a time
56     unsigned int i;
57     for (i=0; i<num_samples; i++) {
58         // STEP 1: generate input signal (filtered noise with offset tone)
59         float complex v1 = (randnf() + randnf()*_Complex_I) + 3.0f*cexpf(-_Complex_I*0.2f*i);
60         iirfilt_crcf_execute(filter_tx, v1, &v1);
61 
62         // save spectrum
63         spgramcf_push(spgram_tx, v1);
64 
65         // STEP 2: mix signal up and save real part (DAC output)
66         nco_crcf_mix_up(mixer_tx, v1, &v1);
67         float v2 = crealf(v1);
68         nco_crcf_step(mixer_tx);
69 
70         // save spectrum
71         spgramf_push(spgram_dac, v2);
72 
73         // STEP 3: mix signal down and filter off image
74         float complex v3;
75         nco_crcf_mix_down(mixer_rx, v2, &v3);
76         iirfilt_crcf_execute(filter_rx, v3, &v3);
77         nco_crcf_step(mixer_rx);
78 
79         // save spectrum
80         spgramcf_push(spgram_rx, v3);
81     }
82 
83     // compute power spectral density output
84     float   psd_tx  [nfft];
85     float   psd_dac [nfft];
86     float   psd_rx  [nfft];
87     spgramcf_get_psd(spgram_tx,  psd_tx);
88     spgramf_get_psd( spgram_dac, psd_dac);
89     spgramcf_get_psd(spgram_rx,  psd_rx);
90 
91     // destroy objects
92     spgramcf_destroy(spgram_tx);
93     spgramf_destroy(spgram_dac);
94     spgramcf_destroy(spgram_rx);
95 
96     iirfilt_crcf_destroy(filter_tx);
97     nco_crcf_destroy(mixer_tx);
98     nco_crcf_destroy(mixer_rx);
99     iirfilt_crcf_destroy(filter_rx);
100 
101     //
102     // export output file
103     //
104     FILE * fid = fopen(OUTPUT_FILENAME,"w");
105     fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
106     fprintf(fid,"clear all;\n");
107     fprintf(fid,"close all;\n\n");
108 
109     fprintf(fid,"nfft   = %u;\n", nfft);
110     fprintf(fid,"f      = [0:(nfft-1)]/nfft - 0.5;\n");
111     fprintf(fid,"psd_tx = zeros(1,nfft);\n");
112     fprintf(fid,"psd_dac= zeros(1,nfft);\n");
113     fprintf(fid,"psd_rx = zeros(1,nfft);\n");
114 
115     for (i=0; i<nfft; i++) {
116         fprintf(fid,"psd_tx (%6u) = %12.4e;\n", i+1, psd_tx [i]);
117         fprintf(fid,"psd_dac(%6u) = %12.4e;\n", i+1, psd_dac[i]);
118         fprintf(fid,"psd_rx (%6u) = %12.4e;\n", i+1, psd_rx [i]);
119     }
120 
121     fprintf(fid,"figure;\n");
122     fprintf(fid,"hold on;\n");
123     fprintf(fid,"  plot(f, psd_tx,  '-', 'LineWidth',1.5,'Color',[0.7 0.7 0.7]);\n");
124     fprintf(fid,"  plot(f, psd_dac, '-', 'LineWidth',1.5,'Color',[0.0 0.5 0.3]);\n");
125     fprintf(fid,"  plot(f, psd_rx,  '-', 'LineWidth',1.5,'Color',[0.0 0.3 0.5]);\n");
126     fprintf(fid,"hold off;\n");
127     fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n");
128     fprintf(fid,"ylabel('Power Spectral Density [dB]');\n");
129     fprintf(fid,"grid on;\n");
130     fprintf(fid,"axis([-0.5 0.5 -100 60]);\n");
131     fprintf(fid,"legend('transmit (complex)','DAC output (real)','receive (complex)','location','northeast');\n");
132 
133     fclose(fid);
134     printf("results written to %s.\n", OUTPUT_FILENAME);
135 
136     printf("done.\n");
137     return 0;
138 }
139 
140