parent
3fd0707a3b
commit
c4d4e7feda
@ -0,0 +1,6 @@ |
||||
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
||||
|
||||
noinst_LIBRARIES = libam.a
|
||||
|
||||
libam_a_SOURCES = \
|
||||
am.c
|
@ -0,0 +1,133 @@ |
||||
/* AM modulation and de-modulation
|
||||
* |
||||
* (C) 2018 by Andreas Eversberg <jolly@eversberg.eu> |
||||
* All Rights Reserved |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <math.h> |
||||
#include "../libsample/sample.h" |
||||
#include "am.h" |
||||
|
||||
#define CARRIER_FILTER 30.0 |
||||
|
||||
/* Amplitude modulation in SDR:
|
||||
* Just use the base band (audio signal) as real value, and 0.0 as imaginary |
||||
* value. The you have two side bands. Be sure to have a DC level, so you |
||||
* have a carrier. |
||||
*/ |
||||
|
||||
int am_mod_init(am_mod_t *mod, double samplerate, double offset, double gain, double bias) |
||||
{ |
||||
memset(mod, 0, sizeof(*mod)); |
||||
mod->gain = gain; |
||||
mod->bias = bias; |
||||
mod->phasestep = 2.0 * M_PI * offset / samplerate; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void am_mod_exit(am_mod_t __attribute__((unused)) *mod) |
||||
{ |
||||
} |
||||
|
||||
void am_modulate_complex(am_mod_t *mod, sample_t *amplitude, int num, float *baseband) |
||||
{ |
||||
int s; |
||||
double vector; |
||||
double phasestep = mod->phasestep; |
||||
double phase = mod->phase; |
||||
double gain = mod->gain; |
||||
double bias = mod->bias; |
||||
|
||||
for (s = 0; s < num; s++) { |
||||
vector = *amplitude++ * gain + bias; |
||||
*baseband++ = cos(phase) * vector; |
||||
*baseband++ = sin(phase) * vector; |
||||
phase += phasestep; |
||||
if (phase < 0.0) |
||||
phase += 2.0 * M_PI; |
||||
else if (phase >= 2.0 * M_PI) |
||||
phase -= 2.0 * M_PI; |
||||
} |
||||
|
||||
mod->phase = phase; |
||||
} |
||||
|
||||
/* init AM demodulator */ |
||||
int am_demod_init(am_demod_t *demod, double samplerate, double offset, double bandwidth, double gain) |
||||
{ |
||||
memset(demod, 0, sizeof(*demod)); |
||||
demod->gain = gain; |
||||
demod->phasestep = 2 * M_PI * -offset / samplerate; |
||||
|
||||
/* use fourth order (2 iter) filter, since it is as fast as second order (1 iter) filter */ |
||||
iir_lowpass_init(&demod->lp[0], bandwidth, samplerate, 2); |
||||
iir_lowpass_init(&demod->lp[1], bandwidth, samplerate, 2); |
||||
|
||||
/* filter carrier */ |
||||
iir_lowpass_init(&demod->lp[2], CARRIER_FILTER, samplerate, 1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void am_demod_exit(am_demod_t __attribute__((unused)) *demod) |
||||
{ |
||||
} |
||||
|
||||
/* do amplitude demodulation of baseband and write them to samples */ |
||||
void am_demodulate_complex(am_demod_t *demod, sample_t *amplitude, int length, float *baseband, sample_t *I, sample_t *Q, sample_t *carrier) |
||||
{ |
||||
int s, ss; |
||||
double phasestep = demod->phasestep; |
||||
double phase = demod->phase; |
||||
double gain = demod->gain; |
||||
double i, q; |
||||
double _sin, _cos; |
||||
|
||||
/* rotate spectrum */ |
||||
for (s = 0, ss = 0; s < length; s++) { |
||||
i = baseband[ss++]; |
||||
q = baseband[ss++]; |
||||
_sin = sin(phase); |
||||
_cos = cos(phase); |
||||
phase += phasestep; |
||||
if (phase < 0.0) |
||||
phase += 2.0 * M_PI; |
||||
else if (phase >= 2.0 * M_PI) |
||||
phase -= 2.0 * M_PI; |
||||
I[s] = i * _cos - q * _sin; |
||||
Q[s] = i * _sin + q * _cos; |
||||
} |
||||
demod->phase = phase; |
||||
|
||||
/* filter bandwidth */ |
||||
iir_process(&demod->lp[0], I, length); |
||||
iir_process(&demod->lp[1], Q, length); |
||||
|
||||
/* demod */ |
||||
for (s = 0; s < length; s++) |
||||
amplitude[s] = carrier[s] = sqrt(I[s] * I[s] + Q[s] * Q[s]); |
||||
|
||||
/* filter carrier */ |
||||
iir_process(&demod->lp[2], carrier, length); |
||||
|
||||
/* normalize */ |
||||
for (s = 0; s < length; s++) |
||||
amplitude[s] = (amplitude[s] - carrier[s]) / carrier[s] * gain; |
||||
} |
||||
|
@ -0,0 +1,26 @@ |
||||
#include "../libfilter/iir_filter.h" |
||||
|
||||
typedef struct am_mod { |
||||
double phasestep; /* angle to rotate vector per sample */ |
||||
double phase; /* current phase */ |
||||
double gain; /* gain to be multiplied to amplitude */ |
||||
double bias; /* DC offset to add (carrier amplitude) */ |
||||
} am_mod_t; |
||||
|
||||
int am_mod_init(am_mod_t *mod, double samplerate, double offset, double gain, double bias); |
||||
void am_mod_exit(am_mod_t *mod); |
||||
void am_modulate_complex(am_mod_t *mod, sample_t *amplitude, int num, float *baseband); |
||||
|
||||
typedef struct am_demod { |
||||
double phasestep; /* angle to rotate vector per sample */ |
||||
double phase; /* current rotation phase (used to shift) */ |
||||
double last_phase; /* last phase of FM (used to demodulate) */ |
||||
iir_filter_t lp[3]; /* filters received IQ signal/carrier */ |
||||
double gain; /* gain to be expected from amplitude */ |
||||
double bias; /* DC offset to be expected (carrier amplitude) */ |
||||
} am_demod_t; |
||||
|
||||
int am_demod_init(am_demod_t *demod, double samplerate, double offset, double gain, double bias); |
||||
void am_demod_exit(am_demod_t *demod); |
||||
void am_demodulate_complex(am_demod_t *demod, sample_t *amplitude, int length, float *baseband, sample_t *I, sample_t *Q, sample_t *carrier); |
||||
|
Loading…
Reference in new issue