From: GSB on
I created a Matlab M-file for a FSK demodulator using a Quadrature
Receiver with 4 matching filters. The code is found below. I need
someone to verify that this code works or to point out any problems.
Also, if there is anything I can do to make it stronger and better,
then I would like to hear about it.

My current problem is that awgn(in_signal, 18, 'measured') of 18 is
the lowest SNR I can use before I get bit error rates. Is there a way
to increase this codes ability to remove noise while decoding the
signal? I have tried lowpass and bandpass filters. But this only
produces more bit error rates.


Also, how can I create an automatic gain control (AGC)?

% Keep
function result = test
% test4_quadrature_receiver()
do_loop = 1;
iter = 1;
while do_loop == 1
[result1 result2 result3] = test1();
result3 = 1; % Do not test this
if result1 ~= 20 || result2 ~= 20 || result3 ~=1
disp('ERROR Found!!!');
do_loop = 0;
else
disp(sprintf('PASSED -- Iteration #%d', iter));
end

iter = iter + 1;
% do_loop = 0; % iterate only 1 time
end

% Keep
function [out1 out2 out3] = test1
clear all;

set_rand_seed();

% Create Signal
symbols1 = [1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1];
pattern1 = [2 2 2 1 2 1 1 2 2 1];
num_patterns1 = 20;
for i = 1:num_patterns1
symbols1 = [symbols1, pattern1];
end

len_symbols1 = length(symbols1);

symbols2 = [1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1];
pattern2 = [1 2 3 4 2 3 1 4 3 4 2 1 2 1 4 3];
num_patterns2 = 20;
for i = 1:num_patterns2
symbols2 = [symbols2, pattern2];
end

pattern3 = [1 2 3 4 4 3 2 1 1 2 3 4 4 3 2 1];
symbols2 = [symbols2 pattern3 [1 2 3 4 1 1 2 2 1 3 4 4 2 1 2 2 1 3
3 4 2 1 2 3 4 1 1 2 2 1 3 4 4 2 1 2 2 1 3 3 4 2 1 2 3 4 1 1 2 2 1 3 4 4
2 1 2 2 1 3 3 4 2]];

min_num_samples = 18; % should be a little lower than
samples_per_bit
Fc = 31500;
Fs = 4*Fc;
bps = floor(get_rand_num(7000, 1000));
frequencies = [Fc - 800, Fc + 800, Fc - 2400, Fc + 2400];

samples_per_bit = 26; % ceil(Fs / 4800)
do_loop = 0;
while do_loop == 1

samples_per_bit = floor(3*min(frequencies) / bps);

t = ceil(min_num_samples * 1.10); % Needs to be 10% larger
since real minimum might be smaller
if samples_per_bit < 26
disp(sprintf('ERROR: samples_per_bit is %d but must be >=
%d', samples_per_bit, t));
disp(sprintf(' : Either increase Fc and/or decrease bps.
Must be (3*Fc) / 13 >= bps.'));
else
do_loop = 0;
end

end

% Symbols to signal
num_samples1 = 50;
t1 = symbols_to_signal(symbols1, frequencies, samples_per_bit, Fs);
t2 = symbols_to_signal(symbols2, frequencies, samples_per_bit, Fs);
% min_num_samples = min(samples_per_bit, num_samples1);
symbols1 = [];
symbols2 = [];

in_signal = [t1 t2];

% Noise
in_signal = awgn(in_signal, 18, 'measured');

% Filter

init_test5_quadrature_receiver
init_quadrature_receiver_per_bit();
init_remove_small_transitions_in_symbols();
init_symbols_to_bits();

len = length(in_signal);
num_bit_per_iter = floor(get_rand_num(20, 2000));
disp(sprintf('bps: %d, samples_per_bit: %d, min_num_samples: %d,
num_bit_per_iter: %d', bps, samples_per_bit, min_num_samples,
num_bit_per_iter));

out_symbols = [];
for i = 1:num_bit_per_iter+1:len - num_bit_per_iter
t = test5_quadrature_receiver(in_signal(i:i+num_bit_per_iter),
frequencies, min_num_samples, Fs);
out_symbols = [out_symbols t];
end

if (i + num_bit_per_iter) < len
t =
test5_quadrature_receiver(in_signal(i+num_bit_per_iter+1:len),
frequencies, min_num_samples, Fs);
out_symbols = [out_symbols t];
end

% BERT - How many patterns found?
out1 = total_num_pattern(out_symbols, pattern1);
out2 = total_num_pattern(out_symbols, pattern2);
out3 = total_num_pattern(out_symbols, pattern3);
disp(sprintf('Found %d/%d, %d/%d, %d/%d', out1, num_patterns1,
out2, num_patterns2, out3, 1));


% Keep
function out_bits = init_test5_quadrature_receiver()
global g1_in_signals g1_decoded_symbols g1_clean_symbols
g1_out_bits

g1_in_signals = []; g1_decoded_symbols = []; g1_clean_symbols =
[]; g1_out_bits = [];


% Keep
function out_bits = test5_quadrature_receiver(in_signal, frequencies,
min_samples_per_bit, Fs)
global g1_in_signals g1_decoded_symbols g1_clean_symbols
g1_out_bits
min_num_data_to_process = 10;
out_bits = [];

% Filters

% Demodulate
g1_in_signals = [g1_in_signals in_signal];
if length(g1_in_signals) < min_num_data_to_process
% disp('d1');
return;
end

decoded_symbols =
signals_to_symbols_via_quadrature_receiver(frequencies, g1_in_signals,
min_samples_per_bit, Fs);
g1_in_signals = [];


% clean signals
g1_decoded_symbols = [g1_decoded_symbols decoded_symbols];
if length(g1_decoded_symbols) < min_num_data_to_process
% disp('d2');
return;
end

clean_symbols =
remove_small_transitions_in_symbols(g1_decoded_symbols, 5);
g1_decoded_symbols = [];

% symbols to bits
g1_clean_symbols = [g1_clean_symbols clean_symbols];
if length(g1_clean_symbols) < min_num_data_to_process
% disp('d3');
return;
end

num_alt_bits = 10;
out_bits = symbols_to_bits(g1_clean_symbols, num_alt_bits);
g1_clean_symbols = [];

% Keep
function result = plot_spectrum(signal, Fs)
result = [];
plot(Fs*(0:1/(length(signal)-1):1), abs(fft(signal)));

% Keep
function result = set_rand_seed()
rand('seed', sum(100*clock()));
result = 0;

% Keep
function result = get_rand_num(min, max)
result = ((max - min) * rand(1)) + min;

%Keep
function result = init_quadrature_receiver_per_bit()
global g_quad_last_bits;

g_quad_last_bits = [];

% Keep
% DESCRIPTION: This function uses Quadrature Receiver techniques to
% determine which of the reference frequencies the signal matches
closest.
% The entire signal is sent which contains multiple symbols. It
handles
% any number of reference frequencies.
% FUNCTION: quadrature_receiver(referencies, signals, Fs)
% where: referencies - All reference frequencies, e.g. [f1 f2 f3
f4].
% signals - Signal data, e.g. sin wave
% Fs - Number of samples per second.
% SYNTAX: quadrature_receiver([100 200 300 400], sin([0:0.02:2*pi]),
5000)
% result = One of the indexes of frequencies corrsponding to closest
% frequency the signal matches.
%
function result =
signals_to_symbols_via_quadrature_receiver(frequencies, signals,
min_samples_per_bit, Fs)
global g_quad_last_bits;
min_samples_per_bit = min_samples_per_bit; % 10
result = [];
signals = [g_quad_last_bits signals];
len_signals = length(signals);
for i = 1:1:(len_signals - min_samples_per_bit + 1)
a = quadrature_receiver_per_bit(frequencies,
signals(i:i+min_samples_per_bit-1), Fs);
result = [result, a];
end

g_quad_last_bits = signals(len_signals - min_samples_per_bit +
2:len_signals);

% Keep
% DESCRIPTION: This function uses Quadrature Receiver techniques to
% determine which of the reference frequencies the signal matches
closest.
% The entire signal is compared to all of the reference frequencies.
It
% handles any number of reference frequencies.
% FUNCTION: quadrature_receiver_per_bit(referencies, signal, Fs)
% where: referencies - All reference frequencies, e.g. [f1 f2 f3
f4].
% signal - Signal data, e.g. sin wave
% Fs - Number of samples per second.
% SYNTAX: quadrature_receiver_per_bit([100 200 300 400],
sin([0:0.02:2*pi]), 5000)
% result = One of the indexes of frequencies corrsponding to closest
% frequency the signal matches.
%
function result = quadrature_receiver_per_bit(frequencies, signal, Fs)
z_values = [];
len = length(signal);
for i = 1:length(frequencies)
ref_cos(i,:) = get_samples_from_freq('cos', frequencies(i),
len, Fs);
ref_sin(i,:) = get_samples_from_freq('sin', frequencies(i),
len, Fs);
z1(i) = sum(sqrt(2/len) * (ref_cos(i, 1:len)) .*
signal(1:len));
z2(i) = sum(sqrt(2/len) * (ref_sin(i, 1:len)) .*
signal(1:len));
z_values = [z_values, z1(i)^2 + z2(i)^2];
end

result = find(z_values == max(z_values));
result = result(1);

% disp(sprintf('min_len1: %d, min_len2: %d, z1: %d, z2: %d, z3: %d,
z4: %d, result: %d', min_len1, min_len2, z1, z2, z3, z4, result));

% Keep
function result = total_num_pattern(symbols, pattern)
len_pattern = length(pattern);
result = 0;
for i = 1:length(symbols) - len_pattern + 1
if symbols(i:i+len_pattern-1) == pattern
result = result + 1;
i = i + len_pattern - 1;
end
end

%Keep
function result = init_remove_small_transitions_in_symbols()
global num_no_transitions last_signal
num_no_transitions = 0;
last_signal = [];

%Keep
function out_signal = remove_small_transitions_in_symbols(in_signal,
min_transition_bit)
global num_no_transitions last_signal;

out_signal = [];
in_signal = [last_signal in_signal];

for i = 2:length(in_signal)
% if no transition, skip
if in_signal(i) == in_signal(i-1)
num_no_transitions = num_no_transitions + 1;
continue;
end

% if time is long enough, then get transition
if num_no_transitions >= min_transition_bit
len = length(out_signal);
out_signal(len+1:len+num_no_transitions+1) = in_signal(i -
1);
num_no_transitions = 0;
end
end

last_signal = in_signal(length(in_signal));



%Keep
function result = get_samples_from_freq(method, freq, num_samples, Fs)
p = freq * ((0.2 / pi) * (100/Fs));
angle = [p*ones(1,num_samples)];

phase = cumsum(angle) - angle(1);
if strcmp(method, 'sin') == 1
result = sin(phase);
elseif strcmp(method, 'cos') == 1
result = cos(phase);
else
disp('Error: method var is undefined in get_1hz_from_freq(),
exiting');
exit;
end

% Keep
function result = symbols_to_signal(symbols, frequencies,
samples_per_symbol, Fs)
% Usage: a = symbols_to_signal([1 2], [10 20], 36000, 150000);
% plot(a);
% Notes:
% - Symbols is a 1-n array with values 1..n

for i = 1:length(symbols)
p = frequencies(symbols(i))* ((0.2 / pi) * (100/Fs));
t = [p*ones(1,samples_per_symbol)];
if i == 1
angle = t;
else
angle = [angle, t];
end
end

phase = cumsum(angle) - angle(1);
result = sin(phase);


% Keep
function init_symbols_to_bits()
global last_bit cur_bit cur_num_alt_bits bit_time first_bit_time
sum_bit_time gindex cur_bit_time last_bit_time hold_out_bits
is_initialized;

is_initialized = 1;
bit_time = 999999;
first_bit_time = 123456;
sum_bit_time = 0;
gindex = 0;
cur_bit_time = 1;
cur_num_alt_bits = 0;
cur_bit = 0;
hold_out_bits = [];

% Keep
function out_bits = symbols_to_bits(in_bits, num_alt_bits)
global last_bit cur_bit cur_num_alt_bits bit_time first_bit_time
sum_bit_time gindex cur_bit_time last_bit_time hold_out_bits
is_initialized;

% Test if init_symbols_to_bits() called. Does not work, but fix
it. Test
% if bit_time was defined and set to 999999.
if is_initialized ~= 1
disp('Need to call init_symbols_to_bits(), exiting');
return;
end

out_bits = [];

for i = 1:length(in_bits)
gindex = gindex + 1;
last_bit = cur_bit;
cur_bit = in_bits(i);

% Sample Bit
t = (gindex - cur_bit_time) / round(bit_time / 2);
if (floor(t) == t) && (floor(t/2) ~= (t/2))
% disp(sprintf('bit sample: %d', cur_bit));
out_bits = [out_bits, cur_bit];
end

% No transitions
if cur_bit == last_bit
continue;
end

% Do not let gindex become too large
if cur_bit_time > 10000
cur_bit_time = cur_bit_time - 8000;
gindex = gindex - 8000;
end

% Update bit times
last_bit_time = cur_bit_time;
cur_bit_time = gindex;

% If transition is same bit time.
t1 = abs(cur_bit_time - last_bit_time - first_bit_time);
t2 = first_bit_time * 0.20;
if t1 <= t2 || (first_bit_time == 123456)
% First bit in alternating bits
if cur_num_alt_bits == 0
first_bit_time = cur_bit_time - last_bit_time;
end

sum_bit_time = sum_bit_time + (cur_bit_time - last_bit_time);
cur_num_alt_bits = cur_num_alt_bits + 1;
% disp(sprintf('t1: %d, t2: %d, cur_bit_time: %d,
last_bit_time: %d, sum_bit_time: %d, first_bit_time: %d,
cur_num_alt_bits: %d', t1, t2, cur_bit_time, last_bit_time,
sum_bit_time, first_bit_time, cur_num_alt_bits));
else
cur_num_alt_bits = 0;
sum_bit_time = 0;
first_bit_time = 123456;
% disp(sprintf('t1: %d, t2: %d, cur_bit_time: %d,
last_bit_time: %d, sum_bit_time: %d, first_bit_time: %d,
cur_num_alt_bits: %d', t1, t2, cur_bit_time, last_bit_time,
sum_bit_time, first_bit_time, cur_num_alt_bits));
end

% if got 10 bit transitions
if cur_num_alt_bits >= num_alt_bits
% disp('************Found 10 alternating bits');
bit_time = round(sum_bit_time / cur_num_alt_bits);
cur_num_alt_bits = 0;
first_bit_time = 123456;
sum_bit_time = 0;
end

end

% disp(sprintf('gindex: %d', gindex));
% disp(sprintf('bit_time: %d', bit_time));

From: Tim Wescott on
GSB wrote:

> I created a Matlab M-file for a FSK demodulator using a Quadrature
> Receiver with 4 matching filters. The code is found below. I need
> someone to verify that this code works or to point out any problems.
> Also, if there is anything I can do to make it stronger and better,
> then I would like to hear about it.
>
> My current problem is that awgn(in_signal, 18, 'measured') of 18 is
> the lowest SNR I can use before I get bit error rates. Is there a way
> to increase this codes ability to remove noise while decoding the
> signal? I have tried lowpass and bandpass filters. But this only
> produces more bit error rates.
>
>
> Also, how can I create an automatic gain control (AGC)?
>
<lots - o - code snipped>

That's a lot of code for someone to wade through for free -- I suspect
it'd take a good half hour to two hours to grok what you have there, and
I couldn't begin to say how long to find any problems. If no one takes
this on I suggest that you reduce the code down to a block diagram or an
algorithmic description, and try those out on us. In the process you
may see your problem.

In general you can increase a detector's performance by using matched
filters, assuming that you have truly orthogonal signals. If the FSK is
phase continuous and the phase changes are well behaved enough you may
be able to treat it as a trellis-coded modulation scheme. If your SNR
is really that bad when you start seeing problems then I would suspect
you have a plain old bug, however.

Have you generated an eye diagram to see what the result looks like?
You should have nice wide open eyes with noiseless data; if you don't
then you have bugs or intersymbol interference. Jaggy or jumpy lines
through the eyes would indicate logic bugs; smooth ones could either be
bugs or intersymbol interference.

You create an automatic gain control by measuring the magnitude of the
signal at some point in the process and applying a varying gain (in the
algorithmic case you just set a multiplier). If you're doing this as a
batch process you just need to normalize your data set to your desired
power level before demodulation. If you are working with a real
receiver that has a hardware gain change then you need to measure some
representative signal in your processing chain and adjust the gain to
keep your desired signal constant.

--

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com
From: Bevan Weiss on
GSB wrote:
> I created a Matlab M-file for a FSK demodulator using a Quadrature
> Receiver with 4 matching filters. The code is found below. I need
> someone to verify that this code works or to point out any problems.
> Also, if there is anything I can do to make it stronger and better,
> then I would like to hear about it.
>
> My current problem is that awgn(in_signal, 18, 'measured') of 18 is
> the lowest SNR I can use before I get bit error rates. Is there a way
> to increase this codes ability to remove noise while decoding the
> signal? I have tried lowpass and bandpass filters. But this only
> produces more bit error rates.
>
>
> Also, how can I create an automatic gain control (AGC)?


I'm definitely going to agree with the others regarding code size... try
and keep it to just the relevant points.
Also, I'm sure you can condense up your [ 1 2 1 2 1 2...] array
declaration heaps by using repeated subarrays.
Creating a linearly increasing/decreasing array is also easy using colon
notation. ie [1:100] creates 100 values from 1 to 100.

You should perhaps use the communications toolbox for these kind of
simulations, much easier if you then want help with them. Not quite so
much code to trawl through. If you don't have access to it, then
blocking it up would probably be a good idea all the same.

You should get bit error rates regardless of the signal to noise ratio.
Just with a lower snr you will get more errors. So you'd need to
provide some quantitative value of errors you're experiencing at 18dB
SNR, might be as expected.

As has already been stated, you'll want to use matched filters. Though
if you're doing non-coherent demodulation then it's a different situation..
From: GSB on
I tried this stuff using Simulink, but was told to use M-file for more
control and accuracy. I had thought asking for help would be a fair
trade since I gave the FSK code out for free in exchange for some
advice. I suspect there are a few people copying the code for their
own use. Essentially, the code works until I add some gaussian noise
(AWGN) above 18 dB or so. The code uses a I/Q Quadrature Receiver with
Matched Filters based on Sylar's "Digital Communications" book. The
stuff works with less noise and at slower speeds. But when I add some
noise and use faster baud speeds, I get some errors. For now, I just
want to verify I implemented the Matched Filters correctly for
non-coherent FM signals. What these matched filters do is sample say
50 bits, at position i, of data and take the highest magnitude and
output a symbol which denotes the frequency being detected. Next, I
repeat the same process but start the 50 samples at i + 1 position.
Some books sample at every 50 bit increments if the samples per bit is
50 bits per symbol. However, my code samples 50 or so bits in
increments of 1. Am I doing things correctly here? I am just trying
to get a better BER while increasing noise and baud speed.

As far as AGC (gain control), how do you get more gain in DSP? I am
thinking of measuring the amplitude of each sample/bit or hertz unit of
signal and multiplying this portion of the signal by 1/amplitude in
order to get the amplitude back to +1 and -1 levels.

Thanks,

From: Bevan Weiss on
GSB wrote:
> I tried this stuff using Simulink, but was told to use M-file for more
> control and accuracy. I had thought asking for help would be a fair
> trade since I gave the FSK code out for free in exchange for some
> advice. I suspect there are a few people copying the code for their
> own use. Essentially, the code works until I add some gaussian noise
> (AWGN) above 18 dB or so. The code uses a I/Q Quadrature Receiver with
> Matched Filters based on Sylar's "Digital Communications" book. The
> stuff works with less noise and at slower speeds. But when I add some
> noise and use faster baud speeds, I get some errors. For now, I just
> want to verify I implemented the Matched Filters correctly for
> non-coherent FM signals. What these matched filters do is sample say
> 50 bits, at position i, of data and take the highest magnitude and
> output a symbol which denotes the frequency being detected. Next, I
> repeat the same process but start the 50 samples at i + 1 position.
> Some books sample at every 50 bit increments if the samples per bit is
> 50 bits per symbol. However, my code samples 50 or so bits in
> increments of 1. Am I doing things correctly here? I am just trying
> to get a better BER while increasing noise and baud speed.
>
> As far as AGC (gain control), how do you get more gain in DSP? I am
> thinking of measuring the amplitude of each sample/bit or hertz unit of
> signal and multiplying this portion of the signal by 1/amplitude in
> order to get the amplitude back to +1 and -1 levels.
>
> Thanks,

Your matched filter should be an integrate and dump rather than the
maximum value (if you're dealing with binary pulse data signals).

You may also be running into some issues with threshold effect with the
FSK signal if you're not extracting all signal power efficiently (such
as not using an integrate and dump matched filter). This occurs when
the SNR becomes low, and hence the receiver can no longer synchronise to
the frequency changes.

Most people on this forum are capable of producing their own FSK
receivers, infact many have probably got some in commercial products at
this time. So the issue is mostly where the problem lies in yours and
exposing just that portion to us so that we don't have to trawl through
the rest of it.
 |  Next  |  Last
Pages: 1 2
Prev: whitening filter
Next: GMSK Simulation