function ask_demod(ebn0_db_range)
%ASK_DEMOD BER simulation for coherent and noncoherent on-off keying

NUM_SYMBOLS = 1000000;

% Sweep over the assigned Eb/N0 range
ber_coh = zeros(size(ebn0_db_range));
ber_abs = zeros(size(ebn0_db_range));
for n = 1:length(ebn0_db_range)
    % Generate the Tx and Rx symbols.
    % Note: Eb is 0.5 on average -> sqrt(0.25) for noise scaling
    %       instead of the usual sqrt(0.5) for real, imaginary parts.
    ebn0_db  = ebn0_db_range(n);
    noise_sc = sqrt(0.25) * 10^(-ebn0_db/20);
    symb_tx  = 2*randint(NUM_SYMBOLS, 1, 2);  % 0 or 1
    symb_rx  = symb_tx + noise_sc*complex(randn(NUM_SYMBOLS, 1), randn(NUM_SYMBOLS, 1));
    
    % Run both slicers.
    slice_coh = logical(real(symb_rx) > 0.5);
    slice_abs = logical(abs(symb_rx) > 0.5);
    
    % Count errors, and store the resulting BER.
    ber_coh(n) = sum(xor(slice_coh, symb_tx)) / NUM_SYMBOLS;
    ber_abs(n) = sum(xor(slice_abs, symb_tx)) / NUM_SYMBOLS;
end

% Calculate ideal curves
ebn0_db_ideal = linspace(min(ebn0_db_range)-2, max(ebn0_db_range)+2, 100);
ebn0_ideal    = 10.^(ebn0_db_ideal/10);
ber_coh_ideal = qfunc(sqrt(ebn0_ideal));
ber_abs_ideal = 0.5*exp(-0.5*ebn0_ideal) + 0.5*qfunc(sqrt(ebn0_ideal));

% Plot the results:
figure;
semilogy(ebn0_db_ideal, ber_coh_ideal, 'r:'); hold on;
semilogy(ebn0_db_ideal, ber_abs_ideal, 'b:');
semilogy(ebn0_db_range, ber_coh, 'r^');
semilogy(ebn0_db_range, ber_abs, 'bv');
xlabel('Eb/N0 (dB)');
ylabel('Bit Error Rate');
legend('Coherent (ideal)', ...
       'Noncoherent (ideal)', ...
       'Coherent (simulation)', ...
       'Noncoherent (simulation)');
