function [samples] = create_burst(sample_rate, frame_configuration, add_turbo_path, temp_path, show_debug_plots) frame_bytes = create_frame_bytes(frame_configuration{:}); %% Turbo encoding and rate matching if (~ isfile(add_turbo_path)) error("Could not find Turbo encoder application at '%s'. Check that the program has been compiled",... add_turbo_path); end % Where to store the files used to talk to the add_turbo binary frame_bin_file = fullfile(temp_path, 'frame.bin'); % Will write payload bytes here turbo_encoded_file = fullfile(temp_path, 'frame.bin.encoded'); % The add_turbo binary will create this % Write out the payload to Turbo encode and rate match file_handle = fopen(frame_bin_file, "w"); assert(file_handle ~= -1, 'Could not open output temp file "%s"', frame_bin_file); try fwrite(file_handle, frame_bytes, 'uint8'); catch error('Could not write to temp file "%s"', frame_bin_file); end fclose(file_handle); % Call the Turbo encoder [retcode, out] = system(sprintf("%s '%s' '%s'", add_turbo_path, frame_bin_file, turbo_encoded_file)); if (retcode ~= 0) warning("Failed to run the Turbo encoder. Details: %s", out); end % Remove the Turbo encoder input temp file delete(frame_bin_file); % Verify that it created the expected output file if (~ isfile(turbo_encoded_file)) error("Turbo encoder did not produce an output file"); end % Read in all bytes from the encoded output file file_handle = fopen(turbo_encoded_file, "r"); assert(file_handle ~= -1, 'Could not open Turbo encoder output file "%s"', turbo_encoded_file); encoded_bits = uint8(fread(file_handle, inf, 'uint8')); fclose(file_handle); % Remove the Turbo encoder output temp file delete(turbo_encoded_file); % Make sure that there are exactly the right number of bytes in the file created by the Turbo encoder required_bytes = 7200; if (length(encoded_bits) ~= required_bytes) error("Expected %d bytes, but got %d", required_bytes, length(encoded_bits)) end %% Scrambler Application % Convert to a matrix of 8 rows so that each symbol has it's own row encoded_bits = reshape(encoded_bits, [], 6).'; % Initial value for the second LFSR in the scrambler scrambler_x2_init = fliplr([0 0 1, 0 0 1 0, 0 0 1 1, 0 1 0 0, 0 1 0 1, 0 1 1 0, 0 1 1 1, 1 0 0 0]); % Create scrambler for all data bits and reshape so that each OFDM symbol has a row scrambler = uint8(reshape(generate_scrambler_seq(7200, scrambler_x2_init), [], 6).'); encoded_bits = [scrambler(1,:); encoded_bits]; % Apply the scrambler to each OFDM symbol's data bits for idx=1:6 encoded_bits(idx+1,:) = bitxor(encoded_bits(idx+1,:), scrambler(idx,:)); end %% OFDM Symbol Creation Setup % Get some required params fft_size = get_fft_size(sample_rate); [long_cp_len, short_cp_len] = get_cyclic_prefix_lengths(sample_rate); % Define the size of each symbols cyclic prefix cyclic_prefix_schedule = [ long_cp_len, ... short_cp_len, ... short_cp_len, ... short_cp_len, ... short_cp_len, ... short_cp_len, ... short_cp_len, ... short_cp_len, ... long_cp_len ... ]; % Number of data carriers per OFDM symbol data_carrier_count = 600; %% Bits to Symbol Mapping % Create the QPSK samples for each OFDM symbol symbol_data = zeros(9, data_carrier_count); encoded_bits_ptr = 1; for symbol_idx=1:9 % There's no work to be done for symbols 4 and 6 as they are ZC sequences if (symbol_idx == 4) elseif (symbol_idx == 6) else % Convert from bits to QPSK constellation symbol_data(symbol_idx,:) = to_qpsk(encoded_bits(encoded_bits_ptr,:)); encoded_bits_ptr = encoded_bits_ptr + 1; end if (show_debug_plots) figure(1); subplot(3, 3, symbol_idx); plot(symbol_data(symbol_idx,:), 'o'); end end %% Frequency Domain Symbol Creation % Create the frequency domain representation of each OFDM symbol freq_domain_symbols = zeros(9, fft_size); % Get the carriers that will contain the QPSK samples data_carrier_indices = get_data_carrier_indices(sample_rate); for symbol_idx=1:9 % Copy the freq domain samples to the buffer freq_domain_symbols(symbol_idx,data_carrier_indices) = symbol_data(symbol_idx,:); if (show_debug_plots) figure(2); subplot(3, 3, symbol_idx); plot(abs(freq_domain_symbols(symbol_idx,:)).^2); figure(3); subplot(3, 3, symbol_idx); plot(freq_domain_symbols(symbol_idx,:), 'o'); end end %% Time Domain Symbol Creation % Create the time domain representation of each OFDM symbol (no cyclic prefix at this point) time_domain_symbols = zeros(9, fft_size); for symbol_idx=1:9 % Move to the time domain samples = ifft(fftshift(freq_domain_symbols(symbol_idx,:))); % Normalize the output of the FFT samples = samples / fft_size; time_domain_symbols(symbol_idx,:) = samples; if (show_debug_plots) figure(4); subplot(3, 3, symbol_idx); plot(10 * log10(abs(time_domain_symbols(symbol_idx,:)).^2)) end end % Replace the contents of symbols 4 and 6 with the correct ZC sequence time_domain_symbols(4,:) = create_zc(fft_size, 4) / fft_size; time_domain_symbols(6,:) = create_zc(fft_size, 6) / fft_size; %% Add Cyclic Prefix samples = zeros(1, sum(cyclic_prefix_schedule) + (fft_size * length(cyclic_prefix_schedule))); samples_ptr = 1; for symbol_idx=1:9 cp_len = cyclic_prefix_schedule(symbol_idx); symbol = time_domain_symbols(symbol_idx,:); cp = symbol(end-cp_len+1:end); symbol_with_prefix = [cp, symbol]; samples(samples_ptr:samples_ptr + length(symbol_with_prefix) - 1) = symbol_with_prefix; samples_ptr = samples_ptr + length(symbol_with_prefix); end if (show_debug_plots) figure(7); plot(10 * log10(abs(time_domain).^2)); filter_out = filter(conj(create_zc(fft_size, 4)), 1, samples); figure(8); plot(abs(filter_out).^2); end end