This repository has been archived by the owner on Jun 30, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
modulate.c
173 lines (157 loc) · 4.39 KB
/
modulate.c
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// $Id: modulate.c,v 1.14 2018/12/05 09:07:18 karn Exp $
// Simple I/Q AM modulator - will eventually support other modes
// Copyright 2017, Phil Karn, KA9Q
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <complex.h>
#include <limits.h>
#include <fftw3.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "misc.h"
#include "dsp.h"
#include "filter.h"
#include "radio.h"
#define BLOCKSIZE 4096
float const scale = 1./SHRT_MAX;
int Samprate = 192000;
int Verbose = 0;
int main(int argc,char *argv[]){
#if 0 // Better done manually?
// if we have root, up our priority and drop privileges
int prio = getpriority(PRIO_PROCESS,0);
prio = setpriority(PRIO_PROCESS,0,prio - 10);
// Quickly drop root if we have it
// The sooner we do this, the fewer options there are for abuse
if(seteuid(getuid()) != 0)
perror("seteuid");
#endif
// Set defaults
double frequency = 48000;
double amplitude = -20;
double sweep = 0;
char *modtype = "am";
int c;
while((c = getopt(argc,argv,"f:a:s:r:vm:")) != EOF){
switch(c){
case 'v':
Verbose++;
break;
case 'r':
Samprate = strtol(optarg,NULL,0);
break;
case 'f':
frequency = strtod(optarg,NULL);
break;
case 'a':
amplitude = strtod(optarg,NULL);
break;
case 's':
sweep = strtod(optarg,NULL); // sweep rate, Hz/sec
break;
case 'm':
modtype = optarg;
break;
}
}
float low;
float high;
float carrier;
if(strcasecmp(modtype,"am") == 0){
carrier = 1;
high = +5000;
low = -5000;
} else if(strcasecmp(modtype,"usb") == 0){
carrier = 0;
high = +3000;
low = 0;
} else if(strcasecmp(modtype,"lsb") == 0){
carrier = 0;
high = 0;
low = -3000;
} else if(strcasecmp(modtype,"ame") == 0){
// AM enhanced: upper sideband + carrier (as in CHU)
carrier = 1;
high = +3000;
low = 0;
} else {
fprintf(stderr,"Unknown modulation %s\n",modtype);
exit(1);
}
if(Verbose){
fprintf(stderr,"%s modulation on %.1f Hz IF, swept %.1f Hz/s, amplitude %5.1f dBFS, filter blocksize %'d\n",
modtype,frequency,sweep,amplitude,BLOCKSIZE);
}
if(-frequency > low && -frequency < high){
fprintf(stderr,"Warning: low carrier frequency may interfere with receiver DC suppression\n");
}
frequency *= 1./Samprate; // cycles/sample
amplitude = pow(10.,amplitude/20.); // Convert to amplitude ratio
sweep *= 1. / ((double)Samprate*Samprate); // cycles/sample
struct osc osc;
memset(&osc,0,sizeof(osc));
set_osc(&osc,frequency,sweep);
int const L = BLOCKSIZE;
int const M = BLOCKSIZE + 1;
int const N = L + M - 1;
complex float * const response = fftwf_alloc_complex(N);
memset(response,0,N*sizeof(response[0]));
{
float gain = 4./N; // Compensate for FFT/IFFT scaling and 4x upsampling
for(int i=0;i<N;i++){
float f;
f = Samprate * ((float)i/N);
if(f > Samprate/2)
f -= Samprate;
if(f >= low && f <= high)
response[i] = gain;
else
response[i] = 0;
}
}
window_filter(L,M,response,3.0);
struct filter_in * const filter_in = create_filter_input(L,M,REAL);
struct filter_out * const filter_out = create_filter_output(filter_in,response,1,COMPLEX);
while(1){
int16_t samp[L/4];
if(pipefill(0,samp,sizeof(samp)) <= 0)
break;
// Filter will upsample by 4x
for(int j=0,i=0;i<L;){
filter_in->input.r[i++] = samp[j++] * scale;
filter_in->input.r[i++] = 0;
filter_in->input.r[i++] = 0;
filter_in->input.r[i++] = 0;
}
// Form baseband signal (analytic for SSB, pure real for AM/DSB)
execute_filter_input(filter_in);
execute_filter_output(filter_out);
// Add carrier, if present
if(carrier != 0){
for(int i=0;i<L;i++)
filter_out->output.c[i] += carrier;
}
// Spin up to chosen carrier frequency
for(int i=0;i<L;i++){
filter_out->output.c[i] *= step_osc(&osc) * amplitude;
}
int16_t output[2*L];
for(int i=0;i<L;i++){
output[2*i] = crealf(filter_out->output.c[i]) * SHRT_MAX;
output[2*i+1] = cimagf(filter_out->output.c[i]) * SHRT_MAX;
}
int wlen = write(1,output,sizeof(output));
if(wlen != sizeof(output)){
perror("write");
break;
}
}
delete_filter_input(filter_in);
delete_filter_output(filter_out);
exit(0);
}