├── LICENSE
├── README.md
├── acquisition
├── norm_acq.m
├── norm_acq_parcode.m
└── weak_acq_optimized_DBZP.m
├── cfg
├── config_sdr_params.m
└── print_string.m
├── data_in
├── caCode.mat
└── data_file_list.txt
├── file_NTLab_Bands_GPS_GLONASS_L12_ch_1_frame_3_algo_norm_acq_parcode_2021-12-12-17-25-26.mat
├── inc
├── calc_loof_coeff.m
├── check_phase.m
├── ephemeris.m
├── invert.m
├── make_ca_table.m
├── nav_party_chk.m
├── pre_run.m
├── show_channel_status.m
├── sky_plot.m
└── twos_comp_2_dec.m
├── init.m
├── plots
├── figure_scripts
│ ├── List_of_figures_and_instructions.pdf
│ ├── Scurve.m
│ ├── Tri.m
│ ├── boc.m
│ ├── ca_codes.m
│ ├── discr.m
│ ├── env.m
│ ├── fig41.m
│ ├── fig47.m
│ ├── figure_7_dll.m
│ ├── figure_7_pll.m
│ ├── geoid.m
│ ├── gps_sig.m
│ ├── m_discr.m
│ ├── multi_env_boc.m
│ ├── plot1.m
│ ├── plot_parallel_code_search.m
│ ├── plot_parallel_freq_search.m
│ ├── psd_boc.m
│ ├── sincfig.m
│ ├── sw.mp
│ ├── winkel4.m
│ └── winkel8.m
├── plot_acquisition.m
├── plot_acquisition_results.m
├── plot_delay_doppler_map_cpp.m
├── plot_navigation.m
├── plot_tracking.m
├── probe_data.m
└── save_acquisition_results.m
├── post_processing
├── post_process.m
├── post_process_norm_acq_parcode.m
├── post_process_weak_acq_dbzp.m
└── post_processing.m
├── pre_processing
├── calc_pseudo_ranges.m
├── ddm_processing.m
├── ddm_processing_woodbine.m
├── delay_doppler_map.m
├── find_preambles.m
├── gen_ca_code.m
├── post_navigation.m
├── pre_proc_norm_acq_parcode.m
├── pre_proc_weak_acq_dbzp.m
├── pre_process.m
└── read_file_data.m
├── processing
└── process.m
├── tracking
└── tracking.m
└── util
├── calc_sin.m
├── cart_2_geo.m
├── cart_2_utm.m
├── check_t.m
├── clen_sin.m
├── conv_dbzp_form.m
├── create_data_file.m
├── e_r_corr.m
├── find_utm_zone.m
├── geo_2_cart.m
├── least_square_post.m
├── sat_pos.m
├── sizeof.m
├── to_geod.m
├── topocent.m
└── tropo_corr.m
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 JohnBagshaw
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fast_GNSS_ReceiverMATLAB
2 | A fast and highly sensitive GNSS receiver with a significant capability of detecting very weak GNSS signals (reflected signals) [MATLAB version]
3 |
4 | Here are the instructions for a successful run:
5 |
6 | • Create two folders; ‘mat’ and ‘data’
7 |
8 | • In the ‘data’ folder create two new folders; ‘data_in’ and ‘data_out’ (or move the 'data_in' folder to the 'data' folder if already created)
9 |
10 | • Move all downloaded files/folders to the ‘mat’ folder except these three:
11 |
12 | o caCode.mat
13 |
14 | o data_file_list.txt
15 |
16 | o NTLab .bin file or other datasets
17 |
18 | • Move the three exception files mentioned above to the ‘data_in’ folder
19 |
20 | • Check and modify parameter settings in config_sdr_params.m file in the ‘cfg’ folder
21 |
22 | • Check the data_file_list.txt and add the input data files
23 |
24 | • Run the init.m file
25 |
--------------------------------------------------------------------------------
/acquisition/norm_acq.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function acqResults = norm_acq(sdrParams, ppData, rxFrameData)
10 | %%% This function runs acquisition algorithm known as
11 | % 'Parallel Code Search Acquisition'. The minimum processing
12 | % block is for 1ms and this function takes care to give
13 | % results for coherentIntegrationInterval results. Results is a
14 | % Nd x N matrix containing complex correlation matrix for Nd doppler bins
15 | % and N samples per code. It also contains relevant stats used for
16 | % otimizations for examples number of samples averaged etc.
17 | % acqResults.ddMap;
18 | % acqResults.stats;
19 |
20 | optimizeOption = ppData.optimizeOption ;
21 | tic;
22 |
23 | if optimizeOption == 1
24 |
25 | % Parameters
26 | averFactor = ppData.averFactor;
27 | prnList = sdrParams.sysParams.acqSatelliteList;
28 | numPrns = length(prnList);
29 | numBlocks = sdrParams.sysParams.coherentProcessingTimeMS;
30 | currFile = sdrParams.stateParams.numFilesProcessed+1;
31 | numCodeSamples = sdrParams.dataFileParamsList{currFile}.samplingFreqHz * 1e-3;
32 | numDopplerSamples = floor(sdrParams.sysParams.acqDopplerBwKhz * 1e3 / ...
33 | sdrParams.sysParams.acqDopplerResHz) + 1;
34 |
35 | rxDataStartIdx = 1;
36 |
37 | % Define buffer for correlation matrix
38 | delayDopplerCohMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
39 | circCorrOutMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
40 |
41 | % Iterate over each block to do the processing.
42 | for blIdx=1:numBlocks
43 |
44 |
45 | % Multiply carrier signal with block data.
46 | blockData = rxFrameData(rxDataStartIdx:rxDataStartIdx+numCodeSamples-1) .*...
47 | ppData.dopplerFreqExp;
48 |
49 | % Take average of consecutive samples.
50 | blockDataN = zeros(numDopplerSamples, numCodeSamples/averFactor);
51 | for dbin=1:numDopplerSamples
52 | blockVec = blockData(dbin, :);
53 | blockVec = reshape(blockVec, averFactor, numCodeSamples/averFactor);
54 | blockDataN(dbin, :) = mean(blockVec, 1);
55 | end
56 | if 0
57 | blockData = permute(reshape(blockData, numDopplerSamples, averFactor, ...
58 | numCodeSamples/averFactor), [1,3,2]);
59 | blockData = mean(blockData, 3);
60 | end
61 |
62 |
63 | % Do the correaltion for 32 PRn iterations with each
64 | % circular correlation using FFT
65 | for prn=1:length(prnList)
66 | blockDataModFd = fft(blockDataN, [], 2);
67 | circCorrOutMatFd = blockDataModFd .* ppData.caCodesTable(prn,:);
68 | circCorrOutMat(prn,:,:) = ifft(circCorrOutMatFd, [], 2);
69 | end
70 |
71 | % Add result to correlation matrix
72 | delayDopplerCohMat = delayDopplerCohMat + abs(circCorrOutMat).^2;
73 | rxDataStartIdx = rxDataStartIdx + numCodeSamples;
74 |
75 |
76 | end
77 | acqResults.ddMap = delayDopplerCohMat;
78 | acqResults.averFactor = averFactor;
79 | acqResults.dopplerResHz = ppData.dopplerResHz;
80 |
81 | elseif optimizeOption == 2
82 |
83 |
84 | % Parameters
85 |
86 | averFactor = ppData.averFactor;
87 | prnList = sdrParams.sysParams.acqSatelliteList;
88 | numPrns = length(prnList);
89 | numBlocks = sdrParams.sysParams.coherentProcessingTimeMS;
90 | currFile = sdrParams.stateParams.numFilesProcessed+1;
91 | numCodeSamples = sdrParams.dataFileParamsList{currFile}.samplingFreqHz * 1e-3;
92 | numDopplerSamples = ppData.numDopplerSamples;
93 | rxDataStartIdx = 1;
94 |
95 | % Define buffer for correlation matrix
96 | delayDopplerCohMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
97 | circCorrOutMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
98 |
99 | % Iterate over each block to do the processing.
100 | for blIdx=1:numBlocks
101 |
102 | blockData = rxFrameData(rxDataStartIdx:rxDataStartIdx+numCodeSamples-1);
103 |
104 | % Multiply carrier signal with block data.
105 | blockData = blockData .* ppData.dopplerFreqInitExp;
106 | blockData = reshape(blockData, averFactor, numCodeSamples/averFactor);
107 | blockData = mean(blockData, 1);
108 | blockData = fft(blockData);
109 |
110 | blockDataN = zeros(numDopplerSamples, numCodeSamples/averFactor);
111 | if 1
112 | shiftFactor = ppData.shiftFactor;
113 | sh=0;
114 | for dbin=1:numDopplerSamples
115 | blockDataN(dbin, :) = circshift(blockData, sh);
116 | sh = floor(shiftFactor * dbin);
117 | end
118 | else
119 | % r=blockData;
120 | % c=circshift(fliplr(blockData), 1);
121 | % c = c(1:numDopplerSamples);
122 | % blockDataN = toeplitz(c, r);
123 |
124 | numCols = numCodeSamples/averFactor;
125 | blockDataN = repmat(blockData, numDopplerSamples, 1);
126 | blockDataN = ifft(fft(blockDataN,[],2) .* ...
127 | exp(-2i*pi/numCols*(0:numDopplerSamples-1)'*...
128 | (0:numCols-1)) ,[],2);
129 |
130 | end
131 |
132 |
133 | % Do the correaltion for 32 PRn iterations with each
134 | % circular correlation using FFT
135 | for prn=1:length(prnList)
136 | circCorrOutMatFd = blockDataN .* ppData.caCodesTable(prn,:);
137 | circCorrOutMat(prn,:,:) = ifft(circCorrOutMatFd, [], 2);
138 | end
139 | % Add result to correlation matrix
140 | delayDopplerCohMat = delayDopplerCohMat + abs(circCorrOutMat).^2;
141 | rxDataStartIdx = rxDataStartIdx + numCodeSamples;
142 | end
143 |
144 | acqResults.ddMap = delayDopplerCohMat;
145 | acqResults.averFactor = averFactor;
146 | acqResults.numCodeSamples = numCodeSamples;
147 | acqResults.numDopplerBins = numDopplerSamples;
148 | acqResults.dopplerResHz = ppData.dopplerResHz;
149 | end
150 | end
151 |
152 |
--------------------------------------------------------------------------------
/acquisition/norm_acq_parcode.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function acqResults = norm_acq_parcode(sdrParams, ppData, rxFrameData)
10 | %%% This function runs acquisition algorithm known as
11 | % 'Parallel Code Search Acquisition'. The minimum processing
12 | % block is for 1ms and this function takes care to give
13 | % results for coherentIntegrationInterval results. Results is a
14 | % Nd x N matrix containing complex correlation matrix for Nd doppler bins
15 | % and N samples per code. It also contains relevant stats used for
16 | % optimizations for examples number of samples averaged etc.
17 | % acqResults.ddMap;
18 | % acqResults.stats;
19 |
20 | optimizeOption = ppData.optimizeOption ;
21 | tic;
22 |
23 | if optimizeOption == 1
24 |
25 | % Parameters
26 | averFactor = ppData.averFactor;
27 | prnList = sdrParams.sysParams.acqSatelliteList;
28 | numPrns = length(prnList);
29 | numBlocks = sdrParams.sysParams.coherentProcessingTimeMS;
30 | currFile = sdrParams.stateParams.numFilesProcessed+1;
31 | numCodeSamples = sdrParams.dataFileParamsList{currFile}.samplingFreqHz * 1e-3;
32 | numDopplerSamples = floor(sdrParams.sysParams.acqDopplerBwKhz * 1e3 / ...
33 | sdrParams.sysParams.acqDopplerResHz) + 1;
34 |
35 | rxDataStartIdx = 1;
36 |
37 | % Define buffer for correlation matrix
38 | delayDopplerCohMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
39 | circCorrOutMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
40 |
41 | % Iterate over each block to do the processing.
42 | for blIdx=1:numBlocks
43 |
44 |
45 | % Multiply carrier signal with block data.
46 | blockData = rxFrameData(rxDataStartIdx:rxDataStartIdx+numCodeSamples-1) .*...
47 | ppData.dopplerFreqExp;
48 |
49 | % Take average of consecutive samples.
50 | blockDataN = zeros(numDopplerSamples, numCodeSamples/averFactor);
51 | for dbin=1:numDopplerSamples
52 | blockVec = blockData(dbin, :);
53 | blockVec = reshape(blockVec, averFactor, numCodeSamples/averFactor);
54 | blockDataN(dbin, :) = mean(blockVec, 1);
55 | end
56 | if 0
57 | blockData = permute(reshape(blockData, numDopplerSamples, averFactor, ...
58 | numCodeSamples/averFactor), [1,3,2]);
59 | blockData = mean(blockData, 3);
60 | end
61 |
62 |
63 | % Do the correaltion for 32 PRn iterations with each
64 | % circular correlation using FFT
65 | for prn=1:length(prnList)
66 | blockDataModFd = fft(blockDataN, [], 2);
67 | circCorrOutMatFd = blockDataModFd .* ppData.caCodesTable(prn,:);
68 | circCorrOutMat(prn,:,:) = ifft(circCorrOutMatFd, [], 2);
69 | end
70 |
71 | % Add result to correlation matrix
72 | delayDopplerCohMat = delayDopplerCohMat + abs(circCorrOutMat).^2;
73 | rxDataStartIdx = rxDataStartIdx + numCodeSamples;
74 |
75 |
76 | end
77 | acqResults.ddMap = delayDopplerCohMat;
78 | acqResults.averFactor = averFactor;
79 | acqResults.dopplerResHz = ppData.dopplerResHz;
80 |
81 | elseif optimizeOption == 2
82 |
83 |
84 | % Parameters
85 |
86 | averFactor = ppData.averFactor;
87 | prnList = sdrParams.sysParams.acqSatelliteList;
88 | numPrns = length(prnList);
89 | numBlocks = sdrParams.sysParams.coherentProcessingTimeMS;
90 | currFile = sdrParams.stateParams.numFilesProcessed+1;
91 | numCodeSamples = sdrParams.dataFileParamsList{currFile}.samplingFreqHz * 1e-3;
92 | numDopplerSamples = ppData.numDopplerSamples;
93 | rxDataStartIdx = 1;
94 |
95 | % Define buffer for correlation matrix
96 | delayDopplerCohMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
97 | circCorrOutMat = zeros(numPrns, numDopplerSamples, numCodeSamples/averFactor);
98 |
99 | % Iterate over each block to do the processing.
100 | for blIdx=1:numBlocks
101 |
102 | blockData = rxFrameData(rxDataStartIdx:rxDataStartIdx+numCodeSamples-1);
103 |
104 | % Multiply carrier signal with block data.
105 | blockData = blockData .* ppData.dopplerFreqInitExp;
106 | blockData = reshape(blockData, averFactor, numCodeSamples/averFactor);
107 | blockData = mean(blockData, 1);
108 | blockData = fft(blockData);
109 |
110 | blockDataN = zeros(numDopplerSamples, numCodeSamples/averFactor);
111 | if 1
112 | shiftFactor = ppData.shiftFactor;
113 | sh=0;
114 | for dbin=1:numDopplerSamples
115 | blockDataN(dbin, :) = circshift(blockData, sh);
116 | sh = floor(shiftFactor * dbin);
117 | end
118 | else
119 | % r=blockData;
120 | % c=circshift(fliplr(blockData), 1);
121 | % c = c(1:numDopplerSamples);
122 | % blockDataN = toeplitz(c, r);
123 |
124 | numCols = numCodeSamples/averFactor;
125 | blockDataN = repmat(blockData, numDopplerSamples, 1);
126 | blockDataN = ifft(fft(blockDataN,[],2) .* ...
127 | exp(-2i*pi/numCols*(0:numDopplerSamples-1)'*...
128 | (0:numCols-1)) ,[],2);
129 |
130 | end
131 |
132 |
133 | % Do the correaltion for 32 PRn iterations with each
134 | % circular correlation using FFT
135 | for prn=1:length(prnList)
136 | circCorrOutMatFd = blockDataN .* ppData.caCodesTable(prn,:);
137 | circCorrOutMat(prn,:,:) = ifft(circCorrOutMatFd, [], 2);
138 | end
139 | % Add result to correlation matrix
140 | delayDopplerCohMat = delayDopplerCohMat + abs(circCorrOutMat).^2;
141 | rxDataStartIdx = rxDataStartIdx + numCodeSamples;
142 | end
143 |
144 | acqResults.ddMap = delayDopplerCohMat;
145 | acqResults.averFactor = averFactor;
146 | acqResults.numCodeSamples = numCodeSamples;
147 | acqResults.numDopplerBins = numDopplerSamples;
148 | acqResults.dopplerResHz = ppData.dopplerResHz;
149 | end
150 | end
151 |
152 |
--------------------------------------------------------------------------------
/acquisition/weak_acq_optimized_DBZP.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function acqResults = weak_acq_optimized_DBZP(sdrParams, ppData, rxFrameData)
10 | %%% This function runs acquisition algorithm known as
11 | % 'Double block zero padding weak acquisition'. The minimum processing
12 | % block is for 1ms and this function takes care to give
13 | % results for coherentIntegrationInterval results. Results is a
14 | % Nd x N matrix containing complex correlation matrix for Nd doppler bins
15 | % and N samples per coherent processing interval divided by averaging factor.
16 | % It also contains relevant stats used for otimizations for examples number
17 | % of samples averaged etc.
18 | % acqResults.ddMap;
19 | % acqResults.stats;
20 |
21 |
22 | %%% Parameters
23 |
24 | caCodesTable = ppData.caCodesTable;
25 | dopplerFreqExp = ppData.dopplerFreqExp;
26 | numBlocks = ppData.numBlocks;
27 | numSamplesPerBlock = ppData.numSamplesPerBlock;
28 | averFactor = ppData.averFactor;
29 | prnList = sdrParams.sysParams.acqSatelliteList;
30 | currFile = sdrParams.stateParams.numFilesProcessed+1;
31 | samplingFreqHz = sdrParams.dataFileParamsList{currFile}.samplingFreqHz;
32 | numPrns = length(prnList);
33 | numDopplerSamples = numBlocks;
34 | numCohIntMs = sdrParams.sysParams.coherentProcessingTimeMS;
35 |
36 | dopplerDftInterpFactor = 4;
37 | numDopplerFftBins = dopplerDftInterpFactor*numDopplerSamples;
38 |
39 | % Define buffer for correlation matrix
40 | circCorrPartial = zeros(numSamplesPerBlock*numDopplerSamples, numDopplerSamples);
41 | circCorrOutMat = zeros(numPrns, numSamplesPerBlock*numDopplerSamples/numCohIntMs, numDopplerFftBins);
42 |
43 |
44 | %%% Convert signal to baseband.
45 | dataBB = rxFrameData .* dopplerFreqExp;
46 |
47 |
48 | %%% Average the input signal
49 | dataBB = reshape(dataBB, averFactor, length(dataBB)/averFactor);
50 | dataBB = mean(dataBB, 1);
51 |
52 | %%% Convert signal to DBZP format matix.
53 | dataBB = reshape(dataBB, numSamplesPerBlock, numBlocks);
54 | dataBB = [dataBB; circshift(dataBB, -1, 2)];
55 |
56 | % dataBB = repmat(dataBB, 1, numBlocks);
57 | % r=1:numBlocks;
58 | % c=circshift(fliplr(1:numBlocks), 1);
59 | % matIdx = toeplitz(c, r)';
60 | % permIdx = matIdx(:);
61 | % caCodeDbzpPerm = squeeze(caCodesTable(prnIdx, :, permIdx));
62 | % parCorrOutput = ifft(fft(dataBB) .* conj(fft(caCodeDbzpPerm)));
63 | % parCorrOutput = parCorrOutput(1:numSamplesPerBlock, :);
64 | % parCorrOutput = mat2cell(parCorrOutput, [numSamplesPerBlock], [53*ones(1, 53)])';
65 | % parCorrOutput = cell2mat(parCorrOutput);
66 |
67 | %%% Perform search for all listed PRN numbers ..
68 | for prnIdx = 1:numPrns
69 |
70 | %%% Generate local PRN C/A code
71 |
72 | %%% generate code for current PRN
73 | caCode = squeeze(caCodesTable(prnIdx, :, :));
74 |
75 | %%% Iterate over each permuation
76 | for permIdx = 1:numBlocks
77 |
78 | %%% Generate Permuted DBZP matrix
79 | permMap = circshift(1:numBlocks, permIdx-1, 2);
80 | caCodeDbzpedPerm = caCode(:, permMap);
81 |
82 | %%% Partial correlation using FFT
83 | parCorrOutput = ifft(fft(dataBB) .* conj(fft(caCodeDbzpedPerm)));
84 |
85 | %%% Put partial correlation results in the buffer
86 |
87 | circCorrPartial((permIdx-1)*numSamplesPerBlock+1:permIdx*numSamplesPerBlock, :) = ...
88 | parCorrOutput(1:numSamplesPerBlock, :);
89 | end
90 |
91 | %%% FFT across the columsn (doppler bins)
92 |
93 | dftCircCorrPartial = abs(fftshift(fft(circCorrPartial, numDopplerFftBins, 2), 2)).^2;
94 | dftCircCorrPartialCellArr = mat2cell(dftCircCorrPartial, ...
95 | size(dftCircCorrPartial, 1)/numCohIntMs*ones(1, numCohIntMs), size(dftCircCorrPartial, 2));
96 |
97 | dftCircCorrPartial = zeros(size(dftCircCorrPartialCellArr{1}));
98 | for m=1:numCohIntMs
99 | dftCircCorrPartial = dftCircCorrPartial + dftCircCorrPartialCellArr{m};
100 | end
101 | circCorrOutMat(prnIdx, :, :) = dftCircCorrPartial;
102 | end
103 |
104 | % Pack results in the output.
105 | acqResults.ddMap = circCorrOutMat;
106 | acqResults.averFactor = averFactor;
107 | acqResults.numSamplesPerBlock = numSamplesPerBlock;
108 | acqResults.numBlocks = numBlocks/numCohIntMs;
109 | acqResults.numDopplerBins = numDopplerSamples;
110 | acqResults.dopplerResHz = (samplingFreqHz/averFactor/numSamplesPerBlock) / numDopplerFftBins;
111 | acqResults.numDopplerFftBins = numDopplerFftBins;
112 |
113 | end
114 |
115 |
116 |
--------------------------------------------------------------------------------
/cfg/config_sdr_params.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function sdrParams = config_sdr_params()
10 | %%% This function is responsible for creating global
11 | % and per file settings. This is run once per data
12 | % file, stream and
13 |
14 | print_string("Initializing SDR parameters.");
15 |
16 | %%% Receiver system parameters
17 |
18 | % Users can specify most important parameters here.
19 | % TODO: Move these important user settings to settings.txt input file.
20 | sdrParams.sysParams.acqAlgosList = {'norm_acq_parcode', ...
21 | 'weak_acq_dbzp',...
22 | % 'weak_acq_dbzp' ,...
23 | % Add more... e.g.
24 | % 'weak_acquisition_hb',...
25 | };
26 |
27 | sdrParams.sysParams.coherentProcessingTimeMS = 1;
28 | sdrParams.sysParams.incoherentProcessingTimeMS = 2;
29 |
30 | if sdrParams.sysParams.coherentProcessingTimeMS > 10
31 | sdrParams.sysParams.coherentProcessingTimeMS = 10; % Cannot be greater than 10ms.
32 | end
33 |
34 | if sdrParams.sysParams.incoherentProcessingTimeMS < sdrParams.sysParams.coherentProcessingTimeMS
35 | error("Incoherent processing time must be greater than coherent processing time.");
36 | end
37 |
38 | % System parameters
39 | sdrParams.sysParams.c = 299792458; % The speed of light, [m/s]
40 | sdrParams.sysParams.startOffset = 68.025; %[ms] Initial sign. travel time
41 | sdrParams.sysParams.caCodeChipRateHz = 1.023e6; % Code frequency basis [Hz]
42 | sdrParams.sysParams.minSamplingFreqHz = sdrParams.sysParams.caCodeChipRateHz * 2;
43 | sdrParams.sysParams.sampleInterpOrder = 2;
44 |
45 | % Acquisition Parameters
46 | sdrParams.sysParams.numberOfChannels = 8; % Number of channels to be used for signal processing
47 | sdrParams.sysParams.skipNumberOfBytes = 0; % Move the starting point of processing.
48 | sdrParams.sysParams.skipAcquisition = 0; % Skips acquisition in the script postProcessing.m if set to 1
49 | sdrParams.sysParams.acqSatelliteList = 1:32; % List of satellites to look for. Some satellites can be excluded to speed up acquisition [PRN numbers]
50 | sdrParams.sysParams.acqDopplerBwKhz = 50; % Band around IF to search for satellite signal. Depends on max Doppler
51 | sdrParams.sysParams.acqDopplerResHz = 1000; % Doppler resolution
52 | sdrParams.sysParams.acqThreshold = 2.5; % Threshold for the signal presence decision rule
53 | sdrParams.sysParams.numAcqSatellites = 8; % Keep record of strongest 8 satellites.
54 |
55 | % Tracking Parameters
56 | sdrParams.sysParams.msToProcess = 36; % [ms]
57 | sdrParams.sysParams.dllDampingRatio = 0.7; % Code tracking loop parameters
58 | sdrParams.sysParams.dllNoiseBandwidth = 2; %[Hz]
59 | sdrParams.sysParams.dllCorrelatorSpacing = 0.5; %[chips]
60 | sdrParams.sysParams.pllDampingRatio = 0.7; % Carrier tracking loop parameters
61 | sdrParams.sysParams.pllNoiseBandwidth = 25; %[Hz]
62 |
63 | %%% Navigation solution settings
64 | sdrParams.sysParams.navSolPeriod = 500; % Period for calculating pseudoranges and position [ms]
65 | sdrParams.sysParams.elevationMask = 10; % Elevation mask to exclude signals from satellites at low elevation[degrees 0 - 90]
66 | sdrParams.sysParams.useTropCorr = 1; % % Enable/dissable use of tropospheric correction [0 - Off, 1 - On]
67 | sdrParams.sysParams.truePosition.E = nan; % True position of the antenna in UTM system (if known). Otherwise enter
68 | sdrParams.sysParams.truePosition.N = nan; % all NaN's and mean position will be used as a reference .
69 | sdrParams.sysParams.truePosition.U = nan;
70 |
71 | %%% Data parameters
72 | sdrParams.stateParams.dataPathIn = '..\data\data_in\';
73 | sdrParams.stateParams.dataPathOut = '..\data\data_out\';
74 | dataInfoFileName = 'data_file_list.txt';
75 | if ~(exist([sdrParams.stateParams.dataPathIn, ...
76 | dataInfoFileName], 'file') == 2)
77 | error(['Data list file is not present. Please define a ',...
78 | 'data_file_list.txt file in ~\..\data folder']);
79 | end
80 |
81 | fileNameStr = fileread([sdrParams.stateParams.dataPathIn, ...
82 | dataInfoFileName]); % Read data file names form data list file.
83 | sdrParams.stateParams.fileNames = regexp(fileNameStr, '\r\n|\r|\n', 'split');
84 |
85 | for fileName=sdrParams.stateParams.fileNames
86 |
87 | % Check if file exists in the path.
88 | if exist([sdrParams.stateParams.dataPathIn, fileName{1}], 'file') == 2
89 |
90 | %sdrParams.dataParams.fileDataParams;
91 | dataParams = [];
92 | % TODO: Convert formats to JSON.
93 | switch fileName{1}
94 | case 'Woodbine_47a'
95 | dataParams.intermFreqHz = 10e6; % Intermediate frequency
96 | dataParams.samplingFreqHz = 40e6; % Sampling frequency
97 | dataParams.dataType = 'int16'; % Data type used to store one sample
98 | dataParams.isBasebandSignal = 1;
99 | dataParams.totalChannels = 1;
100 | dataParams.selectedChannel = 1;
101 |
102 | case 'GPS_and_GIOVE_A-NN-fs16_3676-if4_1304.bin'
103 | dataParams.intermFreqHz = 4.1304e6; % Intermediate frequency
104 | dataParams.samplingFreqHz = 16.367e6; % Sampling frequency
105 | dataParams.dataType = 'int8'; % Data type used to store one sample
106 | dataParams.isBasebandSignal = 0;
107 | dataParams.totalChannels = 1;
108 | dataParams.selectedChannel = 1;
109 |
110 | case 'GPSdata-DiscreteComponents-fs38_192-if9_55.bin'
111 | dataParams.intermFreqHz = 9.548e6; % Intermediate frequency
112 | dataParams.samplingFreqHz = 38.192e6; % Sampling frequency
113 | dataParams.dataType = 'int8'; % Data type used to store one sample
114 | dataParams.isBasebandSignal = 0;
115 | dataParams.totalChannels = 1;
116 | dataParams.selectedChannel = 1;
117 |
118 | case 'NTLab_Bands_GPS_GLONASS_L12.bin'
119 | dataParams.intermFreqHz = (1590-1575.42)*1e6; % Intermediate frequency
120 | dataParams.samplingFreqHz = 53e6; % Sampling frequency
121 | dataParams.dataType = 'ubit2'; % Data type used to store one sample
122 | dataParams.isBasebandSignal = 0;
123 | dataParams.totalChannels = 4;
124 | dataParams.selectedChannel = 4; % set to -1 for all channels
125 |
126 | case 'Woodbine_47a_1.bin'
127 | dataParams.intermFreqHz = 9.548e6; % Intermediate frequency
128 | dataParams.samplingFreqHz = 38.192e6; % Sampling frequency
129 | dataParams.dataType = 'int8'; % Data type used to store one sample
130 | dataParams.isBasebandSignal = 0;
131 | dataParams.totalChannels = 1;
132 | dataParams.selectedChannel = 1;
133 |
134 | case 'Woodbine_47a_2.bin'
135 | dataParams.intermFreqHz = 9.548e6; % Intermediate frequency
136 | dataParams.samplingFreqHz = 38.192e6; % Sampling frequency
137 | dataParams.dataType = 'int8'; % Data type used to store one sample
138 | dataParams.isBasebandSignal = 0;
139 | dataParams.totalChannels = 1;
140 | dataParams.selectedChannel = 1;
141 |
142 | otherwise
143 | error("Listed file is not recognized by SDR. If newer, please add to init_settings or json format.");
144 | end
145 |
146 | if isfield(sdrParams, 'dataFileParamsList')
147 | sdrParams.dataFileParamsList{end+1, :} = dataParams;
148 | else
149 | sdrParams.dataFileParamsList = {dataParams};
150 | end
151 |
152 | else
153 | error([fileName, ' is not present in ', ...
154 | sdrParams.sysParams.dataPathIn, '.']);
155 | end
156 | end
157 |
158 | %%% State Params
159 | sdrParams.stateParams.numFilesProcessed = 0; % Set processed files to zero
160 | sdrParams.stateParams.numFilesToProcess = length(sdrParams.stateParams.fileNames); % number of total data sets to process
161 |
162 | sdrParams.stateParams.currFrameNum = 0;
163 | sdrParams.stateParams.numTotalFrames = sdrParams.sysParams.incoherentProcessingTimeMS / ...
164 | sdrParams.sysParams.coherentProcessingTimeMS;
165 |
166 | if floor(sdrParams.stateParams.numTotalFrames) ~= sdrParams.stateParams.numTotalFrames
167 | error('Number of incoherent frames of data not integer');
168 | end
169 |
170 |
171 |
172 |
173 | %%% end.
174 |
--------------------------------------------------------------------------------
/cfg/print_string.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function print_string(str)
10 | %%% Script to print string on console given the module ID
11 |
12 | global printDebugInfo;
13 | global swName;
14 |
15 | if printDebugInfo
16 | % https://www.mathworks.com/matlabcentral/answers/9907-
17 | % is-there-a-function-that-retrieves-the-filename-of-the-current-script#answer_13613
18 | S = dbstack();
19 | callerPath = which(S(2).name);
20 | callerLineNum = S(2).line;
21 |
22 | callerPathSpltd = regexp(callerPath, '\', 'split');
23 | sD = 1;
24 | while ~isequal(callerPathSpltd{sD}, 'mat')
25 | sD = sD + 1;
26 | end
27 |
28 | callerName = callerPathSpltd{end};
29 |
30 | callerRelPath = '~\';
31 | while sD < length(callerPathSpltd)
32 | callerRelPath = [callerRelPath, callerPathSpltd{sD}, '\'];
33 | sD = sD + 1;
34 | end
35 |
36 | callerInfo = ['path: ', callerRelPath, ', file: ', callerName, ', line: ', num2str(callerLineNum)];
37 | fprintf("%s : %-20s :> %s (%s)\n", swName, getAllFuncNames(S), str, callerInfo);
38 | else
39 | S = dbstack();
40 | fprintf("%s : %-20s :> %s \n", swName, getAllFuncNames(S), str);
41 |
42 | end
43 | end
44 |
45 | function recurScrptName = getAllFuncNames(S)
46 |
47 | sD = length(S);
48 | recurScrptName = S(sD).name;
49 | sD = sD - 1;
50 | while sD > 1
51 | recurScrptName = [recurScrptName, '->', S(sD).name];
52 | sD = sD - 1;
53 | end
54 | end
55 |
56 |
--------------------------------------------------------------------------------
/data_in/caCode.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JohnBagshaw/Fast_GNSS_ReceiverMATLAB/55882581c43cea1f3a4546d3c6ab70840da5c6e4/data_in/caCode.mat
--------------------------------------------------------------------------------
/data_in/data_file_list.txt:
--------------------------------------------------------------------------------
1 | NTLab_Bands_GPS_GLONASS_L12.bin
2 |
--------------------------------------------------------------------------------
/file_NTLab_Bands_GPS_GLONASS_L12_ch_1_frame_3_algo_norm_acq_parcode_2021-12-12-17-25-26.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JohnBagshaw/Fast_GNSS_ReceiverMATLAB/55882581c43cea1f3a4546d3c6ab70840da5c6e4/file_NTLab_Bands_GPS_GLONASS_L12_ch_1_frame_3_algo_norm_acq_parcode_2021-12-12-17-25-26.mat
--------------------------------------------------------------------------------
/inc/calc_loof_coeff.m:
--------------------------------------------------------------------------------
1 | function [tau1, tau2] = calc_loof_coeff(LBW, zeta, k)
2 | %Function finds loop coefficients. The coefficients are used then in PLL-s
3 | %and DLL-s.
4 | %
5 | %[tau1, tau2] = calcLoopCoef(LBW, zeta, k)
6 | %
7 | % Inputs:
8 | % LBW - Loop noise bandwidth
9 | % zeta - Damping ratio
10 | % k - Loop gain
11 | %
12 | % Outputs:
13 | % tau1, tau2 - Loop filter coefficients
14 |
15 | %--------------------------------------------------------------------------
16 | % SoftGNSS v3.0
17 | %
18 | % Copyright (C) Darius Plausinaitis and Dennis M. Akos
19 | % Written by Darius Plausinaitis and Dennis M. Akos
20 | %--------------------------------------------------------------------------
21 | %This program is free software; you can redistribute it and/or
22 | %modify it under the terms of the GNU General Public License
23 | %as published by the Free Software Foundation; either version 2
24 | %of the License, or (at your option) any later version.
25 | %
26 | %This program is distributed in the hope that it will be useful,
27 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
28 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 | %GNU General Public License for more details.
30 | %
31 | %You should have received a copy of the GNU General Public License
32 | %along with this program; if not, write to the Free Software
33 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
34 | %USA.
35 | %--------------------------------------------------------------------------
36 |
37 | %CVS record:
38 | %$Id: calcLoopCoef.m,v 1.1.2.2 2006/08/14 11:38:22 dpl Exp $
39 |
40 | % Solve natural frequency
41 | Wn = LBW*8*zeta / (4*zeta.^2 + 1);
42 |
43 | % solve for t1 & t2
44 | tau1 = k / (Wn * Wn);
45 | tau2 = 2.0 * zeta / Wn;
46 |
--------------------------------------------------------------------------------
/inc/check_phase.m:
--------------------------------------------------------------------------------
1 | function word = check_phase(word, D30Star)
2 | %Checks the parity of the supplied 30bit word.
3 | %The last parity bit of the previous word is used for the calculation.
4 | %A note on the procedure is supplied by the GPS standard positioning
5 | %service signal specification.
6 | %
7 | %word = checkPhase(word, D30Star)
8 | %
9 | % Inputs:
10 | % word - an array with 30 bit long word from the navigation
11 | % message (a character array, must contain only '0' or
12 | % '1').
13 | % D30Star - the last bit of the previous word (char type).
14 | %
15 | % Outputs:
16 | % word - word with corrected polarity of the data bits
17 | % (character array).
18 |
19 | %--------------------------------------------------------------------------
20 | % SoftGNSS v3.0
21 | %
22 | % Written by Darius Plausinaitis and Dennis M. Akos
23 | %--------------------------------------------------------------------------
24 | %This program is free software; you can redistribute it and/or
25 | %modify it under the terms of the GNU General Public License
26 | %as published by the Free Software Foundation; either version 2
27 | %of the License, or (at your option) any later version.
28 | %
29 | %This program is distributed in the hope that it will be useful,
30 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
31 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 | %GNU General Public License for more details.
33 | %
34 | %You should have received a copy of the GNU General Public License
35 | %along with this program; if not, write to the Free Software
36 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
37 | %USA.
38 | %--------------------------------------------------------------------------
39 |
40 | % CVS record:
41 | % $Id: checkPhase.m,v 1.1.2.4 2006/08/14 11:38:22 dpl Exp $
42 |
43 | if D30Star == '1'
44 | % Data bits must be inverted
45 | word(1:24) = invert(word(1:24));
46 | end
47 |
--------------------------------------------------------------------------------
/inc/ephemeris.m:
--------------------------------------------------------------------------------
1 | function [eph, TOW] = ephemeris(bits, D30Star)
2 | %Function decodes ephemerides and TOW from the given bit stream. The stream
3 | %(array) in the parameter BITS must contain 1500 bits. The first element in
4 | %the array must be the first bit of a subframe. The subframe ID of the
5 | %first subframe in the array is not important.
6 | %
7 | %Function does not check parity!
8 | %
9 | %[eph, TOW] = ephemeris(bits, D30Star)
10 | %
11 | % Inputs:
12 | % bits - bits of the navigation messages (5 subframes).
13 | % Type is character array and it must contain only
14 | % characters '0' or '1'.
15 | % D30Star - The last bit of the previous nav-word. Refer to the
16 | % GPS interface control document ICD (IS-GPS-200D) for
17 | % more details on the parity checking. Parameter type is
18 | % char. It must contain only characters '0' or '1'.
19 | % Outputs:
20 | % TOW - Time Of Week (TOW) of the first sub-frame in the bit
21 | % stream (in seconds)
22 | % eph - SV ephemeris
23 |
24 | %--------------------------------------------------------------------------
25 | % SoftGNSS v3.0
26 | %
27 | % Copyright (C) Darius Plausinaitis and Kristin Larson
28 | % Written by Darius Plausinaitis and Kristin Larson
29 | %--------------------------------------------------------------------------
30 | %This program is free software; you can redistribute it and/or
31 | %modify it under the terms of the GNU General Public License
32 | %as published by the Free Software Foundation; either version 2
33 | %of the License, or (at your option) any later version.
34 | %
35 | %This program is distributed in the hope that it will be useful,
36 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
37 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 | %GNU General Public License for more details.
39 | %
40 | %You should have received a copy of the GNU General Public License
41 | %along with this program; if not, write to the Free Software
42 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
43 | %USA.
44 | %--------------------------------------------------------------------------
45 |
46 | %CVS record:
47 | %$Id: ephemeris.m,v 1.1.2.7 2006/08/14 11:38:22 dpl Exp $
48 |
49 |
50 | %% Check if there is enough data ==========================================
51 | if length(bits) < 1500
52 | error('The parameter BITS must contain 1500 bits!');
53 | end
54 |
55 | %% Check if the parameters are strings ====================================
56 | if ~ischar(bits)
57 | error('The parameter BITS must be a character array!');
58 | end
59 |
60 | if ~ischar(D30Star)
61 | error('The parameter D30Star must be a char!');
62 | end
63 |
64 | % Pi used in the GPS coordinate system
65 | gpsPi = 3.1415926535898;
66 |
67 | %% Decode all 5 sub-frames ================================================
68 | for i = 1:5
69 |
70 | %--- "Cut" one sub-frame's bits ---------------------------------------
71 | subframe = bits(300*(i-1)+1 : 300*i);
72 |
73 | %--- Correct polarity of the data bits in all 10 words ----------------
74 | for j = 1:10
75 | [subframe(30*(j-1)+1 : 30*j)] = ...
76 | checkPhase(subframe(30*(j-1)+1 : 30*j), D30Star);
77 |
78 | D30Star = subframe(30*j);
79 | end
80 |
81 | %--- Decode the sub-frame id ------------------------------------------
82 | % For more details on sub-frame contents please refer to GPS IS.
83 | subframeID = bin2dec(subframe(50:52));
84 |
85 | %--- Decode sub-frame based on the sub-frames id ----------------------
86 | % The task is to select the necessary bits and convert them to decimal
87 | % numbers. For more details on sub-frame contents please refer to GPS
88 | % ICD (IS-GPS-200D).
89 | switch subframeID
90 | case 1 %--- It is subframe 1 -------------------------------------
91 | % It contains WN, SV clock corrections, health and accuracy
92 | eph.weekNumber = bin2dec(subframe(61:70)) + 1024;
93 | eph.accuracy = bin2dec(subframe(73:76));
94 | eph.health = bin2dec(subframe(77:82));
95 | eph.T_GD = twosComp2dec(subframe(197:204)) * 2^(-31);
96 | eph.IODC = bin2dec([subframe(83:84) subframe(197:204)]);
97 | eph.t_oc = bin2dec(subframe(219:234)) * 2^4;
98 | eph.a_f2 = twosComp2dec(subframe(241:248)) * 2^(-55);
99 | eph.a_f1 = twosComp2dec(subframe(249:264)) * 2^(-43);
100 | eph.a_f0 = twosComp2dec(subframe(271:292)) * 2^(-31);
101 |
102 | case 2 %--- It is subframe 2 -------------------------------------
103 | % It contains first part of ephemeris parameters
104 | eph.IODE_sf2 = bin2dec(subframe(61:68));
105 | eph.C_rs = twosComp2dec(subframe(69: 84)) * 2^(-5);
106 | eph.deltan = ...
107 | twosComp2dec(subframe(91:106)) * 2^(-43) * gpsPi;
108 | eph.M_0 = ...
109 | twosComp2dec([subframe(107:114) subframe(121:144)]) ...
110 | * 2^(-31) * gpsPi;
111 | eph.C_uc = twosComp2dec(subframe(151:166)) * 2^(-29);
112 | eph.e = ...
113 | bin2dec([subframe(167:174) subframe(181:204)]) ...
114 | * 2^(-33);
115 | eph.C_us = twosComp2dec(subframe(211:226)) * 2^(-29);
116 | eph.sqrtA = ...
117 | bin2dec([subframe(227:234) subframe(241:264)]) ...
118 | * 2^(-19);
119 | eph.t_oe = bin2dec(subframe(271:286)) * 2^4;
120 |
121 | case 3 %--- It is subframe 3 -------------------------------------
122 | % It contains second part of ephemeris parameters
123 | eph.C_ic = twosComp2dec(subframe(61:76)) * 2^(-29);
124 | eph.omega_0 = ...
125 | twosComp2dec([subframe(77:84) subframe(91:114)]) ...
126 | * 2^(-31) * gpsPi;
127 | eph.C_is = twosComp2dec(subframe(121:136)) * 2^(-29);
128 | eph.i_0 = ...
129 | twosComp2dec([subframe(137:144) subframe(151:174)]) ...
130 | * 2^(-31) * gpsPi;
131 | eph.C_rc = twosComp2dec(subframe(181:196)) * 2^(-5);
132 | eph.omega = ...
133 | twosComp2dec([subframe(197:204) subframe(211:234)]) ...
134 | * 2^(-31) * gpsPi;
135 | eph.omegaDot = twosComp2dec(subframe(241:264)) * 2^(-43) * gpsPi;
136 | eph.IODE_sf3 = bin2dec(subframe(271:278));
137 | eph.iDot = twosComp2dec(subframe(279:292)) * 2^(-43) * gpsPi;
138 |
139 | case 4 %--- It is subframe 4 -------------------------------------
140 | % Almanac, ionospheric model, UTC parameters.
141 | % SV health (PRN: 25-32).
142 | % Not decoded at the moment.
143 |
144 | case 5 %--- It is subframe 5 -------------------------------------
145 | % SV almanac and health (PRN: 1-24).
146 | % Almanac reference week number and time.
147 | % Not decoded at the moment.
148 |
149 | end % switch subframeID ...
150 |
151 | end % for all 5 sub-frames ...
152 |
153 | %% Compute the time of week (TOW) of the first sub-frames in the array ====
154 | % Also correct the TOW. The transmitted TOW is actual TOW of the next
155 | % subframe and we need the TOW of the first subframe in this data block
156 | % (the variable subframe at this point contains bits of the last subframe).
157 | TOW = bin2dec(subframe(31:47)) * 6 - 30;
158 |
--------------------------------------------------------------------------------
/inc/invert.m:
--------------------------------------------------------------------------------
1 | function result = invert(data)
2 | % Inverts the binary input-string so that 0 becomes 1 and 1 becomes 0.
3 | %
4 | %result = invert(data)
5 |
6 | %--------------------------------------------------------------------------
7 | % SoftGNSS v3.0
8 | %
9 | % Written by Darius Plausinaitis, Kristin Larson and Dennis M. Akos
10 | %--------------------------------------------------------------------------
11 | %This program is free software; you can redistribute it and/or
12 | %modify it under the terms of the GNU General Public License
13 | %as published by the Free Software Foundation; either version 2
14 | %of the License, or (at your option) any later version.
15 | %
16 | %This program is distributed in the hope that it will be useful,
17 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | %GNU General Public License for more details.
20 | %
21 | %You should have received a copy of the GNU General Public License
22 | %along with this program; if not, write to the Free Software
23 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
24 | %USA.
25 | %--------------------------------------------------------------------------
26 |
27 | % CVS record:
28 | % $Id: invert.m,v 1.1.2.4 2006/08/14 11:38:22 dpl Exp $
29 |
30 | dataLength = length(data);
31 | temp(1:dataLength) = '1';
32 |
33 | invertMask = bin2dec(char(temp));
34 |
35 | result = dec2bin(bitxor(bin2dec(data), invertMask), dataLength);
--------------------------------------------------------------------------------
/inc/make_ca_table.m:
--------------------------------------------------------------------------------
1 | function caCodesTable = make_ca_table(settings, seqLen)
2 | %Function generates CA codes for all 32 satellites based on the settings
3 | %provided in the structure "settings". The codes are digitized at the
4 | %sampling frequency specified in the settings structure.
5 | %One row in the "caCodesTable" is one C/A code. The row number is the PRN
6 | %number of the C/A code.
7 | %
8 | %caCodesTable = makeCaTable(settings)
9 | %
10 | % Inputs:
11 | % settings - receiver settings
12 | % Outputs:
13 | % caCodesTable - an array of arrays (matrix) containing C/A codes
14 | % for all satellite PRN-s
15 |
16 | %--------------------------------------------------------------------------
17 | % SoftGNSS v3.0
18 | %
19 | % Copyright (C) Darius Plausinaitis
20 | % Written by Darius Plausinaitis
21 | % Based on Peter Rinder and Nicolaj Bertelsen
22 | %--------------------------------------------------------------------------
23 | %This program is free software; you can redistribute it and/or
24 | %modify it under the terms of the GNU General Public License
25 | %as published by the Free Software Foundation; either version 2
26 | %of the License, or (at your option) any later version.
27 | %
28 | %This program is distributed in the hope that it will be useful,
29 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
30 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 | %GNU General Public License for more details.
32 | %
33 | %You should have received a copy of the GNU General Public License
34 | %along with this program; if not, write to the Free Software
35 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
36 | %USA.
37 | %--------------------------------------------------------------------------
38 |
39 | %CVS record:
40 | %$Id: makeCaTable.m,v 1.1.2.6 2006/08/14 11:38:22 dpl Exp $
41 |
42 | %--- Find number of samples per spreading code ----------------------------
43 | samplesPerCode = settings.dataParams.samplesPerCode;
44 |
45 | %--- Prepare the output matrix to speed up function -----------------------
46 | caCodesTable = zeros(32, samplesPerCode);
47 |
48 | %--- Find time constants --------------------------------------------------
49 | ts = 1/settings.samplingFreq; % Sampling period in sec
50 | tc = 1/settings.codeFreqBasis; % C/A chip period in sec
51 |
52 | %=== For all satellite PRN-s ...
53 | for PRN = 1:32
54 | %--- Generate CA code for given PRN -----------------------------------
55 | caCode = gen_ca_code(PRN);
56 |
57 | %=== Digitizing =======================================================
58 |
59 | %--- Make index array to read C/A code values -------------------------
60 | % The length of the index array depends on the sampling frequency -
61 | % number of samples per millisecond (because one C/A code period is one
62 | % millisecond).
63 | codeValueIndex = ceil((ts * (1:samplesPerCode)) / tc);
64 |
65 | %--- Correct the last index (due to number rounding issues) -----------
66 | codeValueIndex(end) = 1023;
67 |
68 | %--- Make the digitized version of the C/A code -----------------------
69 | % The "upsampled" code is made by selecting values form the CA code
70 | % chip array (caCode) for the time instances of each sample.
71 | seqInd = mod(0:seqLen-1, samplesPerCode) + 1;
72 | caCodesTable(PRN, :) = caCode(codeValueIndex(seqInd));
73 |
74 | end % for PRN = 1:32
75 |
--------------------------------------------------------------------------------
/inc/nav_party_chk.m:
--------------------------------------------------------------------------------
1 | function status = nav_party_chk(ndat)
2 | % This function is called to compute and status the parity bits on GPS word.
3 | % Based on the flowchart in Figure 2-10 in the 2nd Edition of the GPS-SPS
4 | % Signal Spec.
5 | %
6 | %status = navPartyChk(ndat)
7 | %
8 | % Inputs:
9 | % ndat - an array (1x32) of 32 bits represent a GPS navigation
10 | % word which is 30 bits plus two previous bits used in
11 | % the parity calculation (-2 -1 0 1 2 ... 28 29)
12 | %
13 | % Outputs:
14 | % status - the test value which equals EITHER +1 or -1 if parity
15 | % PASSED or 0 if parity fails. The +1 means bits #1-24
16 | % of the current word have the correct polarity, while -1
17 | % means the bits #1-24 of the current word must be
18 | % inverted.
19 |
20 | %--------------------------------------------------------------------------
21 | % SoftGNSS v3.0
22 | %
23 | % Written by Darius Plausinaitis, Kristin Larson
24 | %--------------------------------------------------------------------------
25 | %This program is free software; you can redistribute it and/or
26 | %modify it under the terms of the GNU General Public License
27 | %as published by the Free Software Foundation; either version 2
28 | %of the License, or (at your option) any later version.
29 | %
30 | %This program is distributed in the hope that it will be useful,
31 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | %GNU General Public License for more details.
34 | %
35 | %You should have received a copy of the GNU General Public License
36 | %along with this program; if not, write to the Free Software
37 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
38 | %USA.
39 | %--------------------------------------------------------------------------
40 |
41 | % CVS record:
42 | % $Id: navPartyChk.m,v 1.1.2.5 2006/08/14 11:38:22 dpl Exp $
43 |
44 | % In order to accomplish the exclusive or operation using multiplication
45 | % this program represents a '0' with a '-1' and a '1' with a '1' so that
46 | % the exclusive or table holds true for common data operations
47 | %
48 | % a b xor a b product
49 | % -------------- -----------------
50 | % 0 0 1 -1 -1 1
51 | % 0 1 0 -1 1 -1
52 | % 1 0 0 1 -1 -1
53 | % 1 1 1 1 1 1
54 |
55 | %--- Check if the data bits must be inverted ------------------------------
56 | if (ndat(2) ~= 1)
57 | ndat(3:26)= -1 .* ndat(3:26); % Also could just negate
58 | end
59 |
60 | %--- Calculate 6 parity bits ----------------------------------------------
61 | % The elements of the ndat array correspond to the bits showed in the table
62 | % 20-XIV (ICD-200C document) in the following way:
63 | % The first element in the ndat is the D29* bit and the second - D30*.
64 | % The elements 3 - 26 are bits d1-d24 in the table.
65 | % The elements 27 - 32 in the ndat array are the received bits D25-D30.
66 | % The array "parity" contains the computed D25-D30 (parity) bits.
67 |
68 | parity(1) = ndat(1) * ndat(3) * ndat(4) * ndat(5) * ndat(7) * ...
69 | ndat(8) * ndat(12) * ndat(13) * ndat(14) * ndat(15) * ...
70 | ndat(16) * ndat(19) * ndat(20) * ndat(22) * ndat(25);
71 |
72 | parity(2) = ndat(2) * ndat(4) * ndat(5) * ndat(6) * ndat(8) * ...
73 | ndat(9) * ndat(13) * ndat(14) * ndat(15) * ndat(16) * ...
74 | ndat(17) * ndat(20) * ndat(21) * ndat(23) * ndat(26);
75 |
76 | parity(3) = ndat(1) * ndat(3) * ndat(5) * ndat(6) * ndat(7) * ...
77 | ndat(9) * ndat(10) * ndat(14) * ndat(15) * ndat(16) * ...
78 | ndat(17) * ndat(18) * ndat(21) * ndat(22) * ndat(24);
79 |
80 | parity(4) = ndat(2) * ndat(4) * ndat(6) * ndat(7) * ndat(8) * ...
81 | ndat(10) * ndat(11) * ndat(15) * ndat(16) * ndat(17) * ...
82 | ndat(18) * ndat(19) * ndat(22) * ndat(23) * ndat(25);
83 |
84 | parity(5) = ndat(2) * ndat(3) * ndat(5) * ndat(7) * ndat(8) * ...
85 | ndat(9) * ndat(11) * ndat(12) * ndat(16) * ndat(17) * ...
86 | ndat(18) * ndat(19) * ndat(20) * ndat(23) * ndat(24) * ...
87 | ndat(26);
88 |
89 | parity(6) = ndat(1) * ndat(5) * ndat(7) * ndat(8) * ndat(10) * ...
90 | ndat(11) * ndat(12) * ndat(13) * ndat(15) * ndat(17) * ...
91 | ndat(21) * ndat(24) * ndat(25) * ndat(26);
92 |
93 | %--- Compare if the received parity is equal the calculated parity --------
94 | if ((sum(parity == ndat(27:32))) == 6)
95 |
96 | % Parity is OK. Function output is -1 or 1 depending if the data bits
97 | % must be inverted or not. The "ndat(2)" is D30* bit - the last bit of
98 | % previous subframe.
99 | status = -1 * ndat(2);
100 | else
101 | % Parity failure
102 | status = 0;
103 | end
104 |
--------------------------------------------------------------------------------
/inc/pre_run.m:
--------------------------------------------------------------------------------
1 | function [channel] = pre_run(acqResults, settings)
2 | %Function initializes tracking channels from acquisition data. The acquired
3 | %signals are sorted according to the signal strength. This function can be
4 | %modified to use other satellite selection algorithms or to introduce
5 | %acquired signal properties offsets for testing purposes.
6 | %
7 | %[channel] = preRun(acqResults, settings)
8 | %
9 | % Inputs:
10 | % acqResults - results from acquisition.
11 | % settings - receiver settings
12 | %
13 | % Outputs:
14 | % channel - structure contains information for each channel (like
15 | % properties of the tracked signal, channel status etc.).
16 |
17 | %--------------------------------------------------------------------------
18 | % SoftGNSS v3.0
19 | %
20 | % Copyright (C) Darius Plausinaitis
21 | % Written by Darius Plausinaitis
22 | % Based on Peter Rinder and Nicolaj Bertelsen
23 | %--------------------------------------------------------------------------
24 | %This program is free software; you can redistribute it and/or
25 | %modify it under the terms of the GNU General Public License
26 | %as published by the Free Software Foundation; either version 2
27 | %of the License, or (at your option) any later version.
28 | %
29 | %This program is distributed in the hope that it will be useful,
30 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
31 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 | %GNU General Public License for more details.
33 | %
34 | %You should have received a copy of the GNU General Public License
35 | %along with this program; if not, write to the Free Software
36 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
37 | %USA.
38 | %--------------------------------------------------------------------------
39 |
40 | %CVS record:
41 | %$Id: preRun.m,v 1.8.2.20 2006/08/14 11:38:22 dpl Exp $
42 |
43 | %% Initialize all channels ================================================
44 | channel = []; % Clear, create the structure
45 |
46 | channel.PRN = 0; % PRN number of the tracked satellite
47 | channel.acquiredFreq = 0; % Used as the center frequency of the NCO
48 | channel.codePhase = 0; % Position of the C/A start
49 |
50 | channel.status = '-'; % Mode/status of the tracking channel
51 | % "-" - "off" - no signal to track
52 | % "T" - Tracking state
53 |
54 | %--- Copy initial data to all channels ------------------------------------
55 | channel = repmat(channel, 1, settings.numberOfChannels);
56 |
57 | %% Copy acquisition results ===============================================
58 |
59 | %--- Sort peaks to find strongest signals, keep the peak index information
60 | [junk, PRNindexes] = sort(acqResults.peakMetric, 2, 'descend');
61 |
62 | %--- Load information about each satellite --------------------------------
63 | % Maximum number of initialized channels is number of detected signals, but
64 | % not more as the number of channels specified in the settings.
65 | for ii = 1:min([settings.numberOfChannels, sum(acqResults.carrFreq > 0)])
66 | channel(ii).PRN = PRNindexes(ii);
67 | channel(ii).acquiredFreq = acqResults.carrFreq(PRNindexes(ii));
68 | channel(ii).codePhase = acqResults.codePhase(PRNindexes(ii));
69 |
70 | % Set tracking into mode (there can be more modes if needed e.g. pull-in)
71 | channel(ii).status = 'T';
72 | end
73 |
--------------------------------------------------------------------------------
/inc/show_channel_status.m:
--------------------------------------------------------------------------------
1 | function show_channel_status(channel, settings)
2 | %Prints the status of all channels in a table.
3 | %
4 | %show_channel_status(channel, settings)
5 | %
6 | % Inputs:
7 | % channel - data for each channel. It is used to initialize and
8 | % at the processing of the signal (tracking part).
9 | % settings - receiver settings
10 |
11 | %--------------------------------------------------------------------------
12 | % SoftGNSS v3.0
13 | %
14 | % Copyright (C) Peter Rinder and Nicolaj Bertelsen
15 | % Written by Peter Rinder Nicolaj Bertelsen and Darius Plausinaitis
16 | % Based on Peter Rinder and Nicolaj Bertelsen
17 | %--------------------------------------------------------------------------
18 | %This program is free software; you can redistribute it and/or
19 | %modify it under the terms of the GNU General Public License
20 | %as published by the Free Software Foundation; either version 2
21 | %of the License, or (at your option) any later version.
22 | %
23 | %This program is distributed in the hope that it will be useful,
24 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
25 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 | %GNU General Public License for more details.
27 | %
28 | %You should have received a copy of the GNU General Public License
29 | %along with this program; if not, write to the Free Software
30 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
31 | %USA.
32 | %--------------------------------------------------------------------------
33 |
34 | %CVS record:
35 | %$Id: showChannelStatus.m,v 1.4.2.8 2006/08/14 11:38:22 dpl Exp $
36 |
37 | fprintf('\n*=========*=====*===============*===========*=============*========*\n');
38 | fprintf( '| Channel | PRN | Frequency | Doppler | Code Offset | Status |\n');
39 | fprintf( '*=========*=====*===============*===========*=============*========*\n');
40 |
41 | for channelNr = 1 : settings.numberOfChannels
42 | if (channel(channelNr).status ~= '-')
43 | fprintf('| %2d | %3d | %2.5e | %5.0f | %6d | %1s |\n', ...
44 | channelNr, ...
45 | channel(channelNr).PRN, ...
46 | channel(channelNr).acquiredFreq, ...
47 | channel(channelNr).acquiredFreq - settings.IF, ...
48 | channel(channelNr).codePhase, ...
49 | channel(channelNr).status);
50 | else
51 | fprintf('| %2d | --- | ------------ | ----- | ------ | Off |\n', ...
52 | channelNr);
53 | end
54 | end
55 |
56 | fprintf('*=========*=====*===============*===========*=============*========*\n\n');
57 |
--------------------------------------------------------------------------------
/inc/sky_plot.m:
--------------------------------------------------------------------------------
1 | function hpol = sky_plot(varargin)
2 | %Function plots "sky view" from the receiver perspective.
3 | %
4 | %h = skyPlot(AZ, EL, PRN, line_style)
5 | %
6 | % Inputs:
7 | % AZ - contains satellite azimuth angles. It is a 2D
8 | % matrix. One line contains data of one satellite.
9 | % The columns are the calculated azimuth values.
10 | % EL - contains satellite elevation angles. It is a 2D
11 | % matrix. One line contains data of one satellite.
12 | % The columns are the calculated elevations.
13 | % PRN - a row vector containing PRN numbers of the
14 | % satellites.
15 | % line_style - line style of the plot. The same style will be
16 | % used to plot all satellite positions (including
17 | % color).
18 | % Outputs:
19 | % h - handle to the plot
20 |
21 | %--------------------------------------------------------------------------
22 | % SoftGNSS v3.0
23 | %
24 | % Copyright (C) Darius Plausinaitis and Kristin Larson
25 | % Written by Darius Plausinaitis and Kristin Larson
26 | %--------------------------------------------------------------------------
27 | %This program is free software; you can redistribute it and/or
28 | %modify it under the terms of the GNU General Public License
29 | %as published by the Free Software Foundation; either version 2
30 | %of the License, or (at your option) any later version.
31 | %
32 | %This program is distributed in the hope that it will be useful,
33 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
34 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 | %GNU General Public License for more details.
36 | %
37 | %You should have received a copy of the GNU General Public License
38 | %along with this program; if not, write to the Free Software
39 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
40 | %USA.
41 | %--------------------------------------------------------------------------
42 |
43 | %CVS record:
44 | %$Id: skyPlot.m,v 1.1.2.5 2006/08/18 11:41:57 dpl Exp $
45 |
46 | %% Check arguments and sort them ==========================================
47 | [hAxis, args, nargs] = axescheck(varargin{:});
48 |
49 | if nargs < 3 || nargs > 4
50 | error('Requires 3 or 4 data arguments.')
51 | elseif nargs == 3
52 | [az, el, prn] = deal(args{1:3});
53 | line_style = 'auto';
54 | else
55 | [az, el, prn, line_style] = deal(args{1:4});
56 | end
57 |
58 | if ischar(az) || ischar(el) || ischar(prn)
59 | error('AZ and EL must be numeric.');
60 | end
61 |
62 | if ~isequal(size(az), size(el))
63 | error('AZ and EL must be same size.');
64 | end
65 |
66 | %% Prepare axis ===========================================================
67 | hAxis = newplot(hAxis);
68 |
69 | %--- Get x-axis text color so grid is in same color -----------------------
70 | tc = get(hAxis, 'xcolor');
71 |
72 | hold(hAxis, 'on');
73 |
74 | %--- Plot white background ------------------------------------------------
75 | rectangle('position', [-90, -90, 180, 180], ...
76 | 'Curvature', [1 1], ...
77 | 'facecolor', 'white', ...
78 | 'edgecolor', tc);
79 |
80 | %% Plot spokes ============================================================
81 |
82 | %--- Find spoke angles ----------------------------------------------------
83 | % Only 6 lines are needed to divide circle into 12 parts
84 | th = (1:6) * 2*pi / 12;
85 |
86 | %--- Convert spoke end point coordinate to Cartesian system ---------------
87 | cst = cos(th); snt = sin(th);
88 | cs = [cst; -cst];
89 | sn = [snt; -snt];
90 |
91 | %--- Plot the spoke lines -------------------------------------------------
92 | line(90*sn, 90*cs, 'linestyle', ':', 'color', tc, 'linewidth', 0.5, ...
93 | 'handlevisibility', 'off');
94 |
95 | %% Annotate spokes in degrees =============================================
96 | rt = 1.1 * 90;
97 |
98 | for i = 1:max(size(th))
99 |
100 | %--- Write text in the first half of the plot -------------------------
101 | text(rt*snt(i), rt*cst(i), int2str(i*30), ...
102 | 'horizontalalignment', 'center', 'handlevisibility', 'off');
103 |
104 | if i == max(size(th))
105 | loc = int2str(0);
106 | else
107 | loc = int2str(180 + i*30);
108 | end
109 |
110 | %--- Write text in the opposite half of the plot ----------------------
111 | text(-rt*snt(i), -rt*cst(i), loc, ...
112 | 'handlevisibility', 'off', 'horizontalalignment', 'center');
113 | end
114 |
115 | %% Plot elevation grid ====================================================
116 |
117 | %--- Define a "unit" radius circle ----------------------------------------
118 | th = 0 : pi/50 : 2*pi;
119 | xunit = cos(th);
120 | yunit = sin(th);
121 |
122 | %--- Plot elevation grid lines and tick text ------------------------------
123 | for elevation = 0 : 15 : 90
124 | elevationSpherical = 90*cos((pi/180) * elevation);
125 |
126 | line(yunit * elevationSpherical, xunit * elevationSpherical, ...
127 | 'lineStyle', ':', 'color', tc, 'linewidth', 0.5, ...
128 | 'handlevisibility', 'off');
129 |
130 | text(0, elevationSpherical, num2str(elevation), ...
131 | 'BackgroundColor', 'white', 'horizontalalignment','center', ...
132 | 'handlevisibility', 'off');
133 | end
134 |
135 | %--- Set view to 2-D ------------------------------------------------------
136 | view(0, 90);
137 |
138 | %--- Set axis limits ------------------------------------------------------
139 | %save some space for the title
140 | axis([-95 95 -90 101]);
141 |
142 | %% Transform elevation angle to a distance to the center of the plot ------
143 | elSpherical = 90*cos(el * pi/180);
144 |
145 | %--- Transform data to Cartesian coordinates ------------------------------
146 | yy = elSpherical .* cos(az * pi/180);
147 | xx = elSpherical .* sin(az * pi/180);
148 |
149 | %% Plot data on top of the grid ===========================================
150 |
151 | if strcmp(line_style, 'auto')
152 | %--- Plot with "default" line style -----------------------------------
153 | hpol = plot(hAxis, xx', yy', '.-');
154 | else
155 | %--- Plot with user specified line style ------------------------------
156 | % The same line style and color will be used for all satellites
157 | hpol = plot(hAxis, xx', yy', line_style);
158 | end
159 |
160 | %--- Mark the last position of the satellite ------------------------------
161 | plot(hAxis, xx(:,end)', yy(:,end)', 'o', 'MarkerSize', 7);
162 |
163 | %--- Place satellite PRN numbers at the latest position -------------------
164 | for i = 1:length(prn)
165 | if(prn(i) ~= 0)
166 | % The empthy space is used to place the text a side of the last
167 | % point. This solution results in constant offset even if a zoom
168 | % is used.
169 | text(xx(i, end), yy(i, end), [' ', int2str(prn(i))], 'color', 'b');
170 | end
171 | end
172 |
173 | %--- Make sure both axis have the same data aspect ratio ------------------
174 | axis(hAxis, 'equal');
175 |
176 | %--- Switch off the standard Cartesian axis -------------------------------
177 | axis(hAxis, 'off');
178 |
--------------------------------------------------------------------------------
/inc/twos_comp_2_dec.m:
--------------------------------------------------------------------------------
1 | function intNumber = twos_comp_2_dec(binaryNumber)
2 | % TWOSCOMP2DEC(binaryNumber) Converts a two's-complement binary number
3 | % BINNUMBER (in Matlab it is a string type), represented as a row vector of
4 | % zeros and ones, to an integer.
5 | %
6 | %intNumber = twosComp2dec(binaryNumber)
7 |
8 | %--------------------------------------------------------------------------
9 | % SoftGNSS v3.0
10 | %
11 | % Copyright (C) Darius Plausinaitis
12 | % Written by Darius Plausinaitis
13 | %--------------------------------------------------------------------------
14 | %This program is free software; you can redistribute it and/or
15 | %modify it under the terms of the GNU General Public License
16 | %as published by the Free Software Foundation; either version 2
17 | %of the License, or (at your option) any later version.
18 | %
19 | %This program is distributed in the hope that it will be useful,
20 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | %GNU General Public License for more details.
23 | %
24 | %You should have received a copy of the GNU General Public License
25 | %along with this program; if not, write to the Free Software
26 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
27 | %USA.
28 | %--------------------------------------------------------------------------
29 |
30 | % CVS record:
31 | % $Id: twosComp2dec.m,v 1.1.2.4 2006/08/14 11:38:22 dpl Exp $
32 |
33 | %--- Check if the input is string -----------------------------------------
34 | if ~isstr(binaryNumber)
35 | error('Input must be a string.')
36 | end
37 |
38 | %--- Convert from binary form to a decimal number -------------------------
39 | intNumber = bin2dec(binaryNumber);
40 |
41 | %--- If the number was negative, then correct the result ------------------
42 | if binaryNumber(1) == '1'
43 | intNumber = intNumber - 2^size(binaryNumber, 2);
44 | end
45 |
--------------------------------------------------------------------------------
/init.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | %%%================== GNSS SDR ===========================%%%
10 | %
11 | % @brief: Software Defined GNSS Receiver Software Model
12 | % @date: 11-19-2021
13 | %%%=======================================================%%%
14 |
15 | %%% Clean up the environment first
16 | clear; close all; clc; clear init_settings;
17 |
18 | %%% Formats
19 | format ('compact');
20 | format ('long', 'g');
21 |
22 | %%% Global variables
23 | global printDebugInfo;
24 | global swName;
25 | swName = 'JohnBagshawGNSS_SDR_v0.1';
26 | printDebugInfo = 0;
27 |
28 | %%% Add all folders and sub folders in current path.
29 | addpath(genpath('.'));
30 |
31 | %%% Print startup
32 | print_string("===============================================================");
33 | print_string(['Welcome! MATLAB Reference Software-Defined Radio: ', swName]);
34 | print_string("===============================================================");
35 |
36 | % Do parameter configuration.
37 | sdrParams = config_sdr_params();
38 |
39 |
40 | % Do multiple data stream processing (offline)
41 | % TODO: support real-time.
42 |
43 | while sdrParams.stateParams.numFilesProcessed < ...
44 | sdrParams.stateParams.numFilesToProcess
45 |
46 | print_string('-----------------------------------------------------------------');
47 | print_string(['Data processing started for file: ',...
48 | sdrParams.stateParams.fileNames{sdrParams.stateParams.numFilesProcessed+1}]);
49 | print_string('-----------------------------------------------------------------');
50 |
51 |
52 | % Reset frame counter
53 | sdrParams.stateParams.currFrameNum = 0;
54 |
55 | %%% pre-processing per input data file.
56 | [ppData, rxData] = pre_process(sdrParams);
57 |
58 | %%% Data frame processing
59 | while sdrParams.stateParams.currFrameNum < ...
60 | sdrParams.stateParams.numTotalFrames
61 |
62 | %%% Processing
63 | % Process function is based on processing of data frames per
64 | % currently processing file.
65 | processResults = process(sdrParams, ppData, rxData);
66 |
67 | %%% post-processing
68 | % Post processing is done for data frames with one time final
69 | % global post processing managed internally.
70 | postProcessResults = post_process(sdrParams, rxData, processResults);
71 |
72 | sdrParams.stateParams.currFrameNum = ...
73 | sdrParams.stateParams.currFrameNum + 1;
74 | end
75 |
76 |
77 | %%% Plotting the results.
78 | plot_acquisition_results(sdrParams, postProcessResults);
79 |
80 |
81 | %%% Save results to configured file format.
82 | save_acquisition_resutls(sdrParams, postProcessResults);
83 |
84 |
85 | print_string('-----------------------------------------------------------------');
86 | print_string(['Data processing completed for file: ',...
87 | sdrParams.stateParams.fileNames{sdrParams.stateParams.numFilesProcessed+1}]);
88 | print_string('-----------------------------------------------------------------');
89 |
90 | % Next file.
91 | sdrParams.stateParams.numFilesProcessed = ...
92 | sdrParams.stateParams.numFilesProcessed + 1;
93 |
94 | end
95 | print_string("============================");
96 | print_string("Program Completed. Good Bye!");
97 | print_string("============================");
98 |
99 |
--------------------------------------------------------------------------------
/plots/figure_scripts/List_of_figures_and_instructions.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JohnBagshaw/Fast_GNSS_ReceiverMATLAB/55882581c43cea1f3a4546d3c6ab70840da5c6e4/plots/figure_scripts/List_of_figures_and_instructions.pdf
--------------------------------------------------------------------------------
/plots/figure_scripts/Scurve.m:
--------------------------------------------------------------------------------
1 | function s_curve()
2 | % SCURVE.M, Henrik Have Lindberg, 2006.03.16
3 |
4 | %CVS record:
5 | %$Id: Scurve.m,v 1.1.2.2 2006/08/18 12:05:02 dpl Exp $
6 |
7 | cp = -2:0.01:2;
8 |
9 | % CA code
10 |
11 | corr = fxcorr(cp);
12 |
13 | figure(1)
14 | plot(cp,corr);
15 | hold on
16 |
17 | spacing = 0.5;
18 |
19 | EmL = fxcorr(cp+spacing/2)-fxcorr(cp-spacing/2);
20 |
21 | plot(cp,EmL);
22 | hold off
23 | axis([-2,2,-1.55, 1.55])
24 | xlabel('Code Offset [chips]');
25 | ylabel('Discriminator output/correlation');
26 | legend ('Correlation','Discriminator\newline output');
27 | %postPlot(get(gca,'children'), 1.5);
28 |
29 |
30 | % BOC(1,1) code
31 |
32 | corrBOC11 = fxcorrBOC11(cp);
33 |
34 | figure(2)
35 | plot(cp,corrBOC11)
36 | hold on
37 |
38 | EmLBOC11 = fxcorrBOC11(cp+spacing/2)-fxcorrBOC11(cp-spacing/2);
39 |
40 | plot(cp,EmLBOC11);
41 | hold off
42 | axis([-2,2,-1.55, 1.55])
43 | xlabel('Code Offset [chips]');
44 | ylabel('Discriminator output/correlation');
45 | legend ('Correlation','Discriminator\newline output');
46 | %postPlot(get(gca,'children'), 1.5);
47 |
48 | % fxcorr.m, HHL, 2006.03.16
49 | %
50 | % just CA code for now...
51 |
52 | function correlation = fxcorr(codephase)
53 |
54 | abs_codephase = abs(codephase);
55 |
56 | for i=1:length(codephase)
57 | if abs_codephase(i)<1,
58 | correlation(i) = abs(1-abs_codephase(i));
59 | else
60 | correlation(i) = 0;
61 | end
62 | end
63 |
64 |
65 | % fxcorrBOC11.m, HHL, 2006.03.16
66 | %
67 | % just BOC(1,1) code for now...
68 |
69 | function correlation = fxcorrBOC11(codephase)
70 |
71 | abs_codephase = abs(codephase);
72 |
73 | for i=1:length(codephase)
74 | if abs_codephase(i)<1,
75 | k = ceil(2*1*abs_codephase(i));
76 | correlation(i) = ((-1)^(k+1))*(-k^2+3*k-1-(5-2*k)*abs_codephase(i));
77 | else
78 | correlation(i) = 0;
79 | end
80 | end
81 |
--------------------------------------------------------------------------------
/plots/figure_scripts/Tri.m:
--------------------------------------------------------------------------------
1 | function tri = Tri(x)
2 | %--------------------------------------------------------------------------
3 | % Written by Darius Plausinaitis
4 | %--------------------------------------------------------------------------
5 |
6 | %CVS record:
7 | %$Id: Tri.m,v 1.1.2.2 2006/08/18 12:05:02 dpl Exp $
8 | tri = (1 - abs(x)) .* ((1 - abs(x)) > 0);
9 |
--------------------------------------------------------------------------------
/plots/figure_scripts/boc.m:
--------------------------------------------------------------------------------
1 | % Demonstration of BOC modulation principle
2 |
3 | % February 13, 2006
4 |
5 | % Written by Kai Borre and Darius Plasinaitis
6 | phi = linspace(0,12,600);
7 |
8 | figure(1);
9 | %Spreading Code
10 | chips = [ones(1, 400), -1 * ones(1, 200)];
11 | % plot(phi, data +7)
12 | plot(phi, chips +10)
13 | hold on
14 |
15 | %Sub-carrier
16 | subCarrier = square(phi*pi);
17 | % plot(phi, subCarrier+4)
18 | plot(phi, subCarrier +7)
19 |
20 | %BOC signal, no carrier
21 | plot(phi, (subCarrier.*chips) +4)
22 |
23 | %Carrier wave
24 | carrier = sin(phi*4*pi);
25 | plot(phi, carrier+1)
26 |
27 | %Modulated Carrier Phase
28 | signal = carrier.* subCarrier .* chips;
29 | plot(phi, signal - 2)
30 | axis([-1 13 -4 11])
31 | axis off
32 | hold off
33 |
34 | print -deps boc
35 | %%%%%%%%%%%%%% boc.m %%%%%%%%%%%%%%%%%%%%
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/plots/figure_scripts/ca_codes.m:
--------------------------------------------------------------------------------
1 | clear all
2 |
3 | % ***** Generates C/A codes *****
4 | PRN_1 = PRNgen(1); % SVN 1
5 | PRN_2 = PRNgen(2); % SVN 2
6 |
7 | PRN1 = [PRN_1';PRN_1'];
8 | PRN2 = [PRN_2';PRN_2'];
9 |
10 | % ***** Calculate auto- and cross-correlation *****
11 | for n=1:1023
12 | Corr11(n) = PRN1(1:1023)'*PRN1(n:1022+n);
13 | Corr12(n) = PRN1(1:1023)'*PRN2(n:1022+n);
14 | end
15 |
16 | figure(1)
17 | subplot(121)
18 | plot(Corr11);
19 | axis([-50 1100 -100 1100]);
20 | %title('Autocorrelation of a PRN sequence');
21 | set(gca,'Fontsize',16)
22 | ylabel('\itr_{kk}','Fontsize',16)
23 | xlabel('Lag','Fontsize',16)
24 | box off
25 |
26 |
27 | subplot(122)
28 | plot(Corr12);
29 | axis([-50 1100 -100 1100]);
30 | %title('Cross-correlation between two PRN sequences');
31 | set(gca,'Fontsize',16)
32 | ylabel('\itr_{ik}','Fontsize',16)
33 | xlabel('Lag','Fontsize',16)
34 | box off
35 |
36 | print -deps2 ca-code-correlation
37 | %%%%%%%%%%%%%%%% end ca_codes.m %%%%%%%%%%%%%%%
38 |
--------------------------------------------------------------------------------
/plots/figure_scripts/discr.m:
--------------------------------------------------------------------------------
1 | %Correlation and Discriminator functions
2 |
3 | % Kai Borre, February 12, 2006
4 |
5 | syms t
6 |
7 | T = 1;
8 | d = 1;
9 |
10 | delta = 1;
11 | figure(1);
12 | hold on
13 | t1 = ezplot(R(-1+t+d/2,T));
14 | t2 = ezplot(R(-1+t+delta+d/2,T));
15 | t3 = ezplot(-R(-1+t+d/2,T)+R(-1+t+delta+d/2,T));
16 | line([-1.6 1.6], [0 0])
17 | xlabel('Time Delay [chip]','FontSize',24)
18 | ylabel('Correlation','FontSize',24)
19 | set(t3,'color','k','linewidth',1.5)
20 | axis([-1.6 1.6 -.5 1.5])
21 | axis equal
22 | set(gca,'FontSize',24)
23 | title('')
24 | hold off
25 | print -deps2 corrd1
26 |
27 | delta = .5;
28 | figure(2);
29 | hold on
30 | ezplot(R(-.75+t+d/2,T));
31 | ezplot(R(-.75+t+delta+d/2,T));
32 | t32 = ezplot(-R(-.75+t+d/2,T)+R(-.75+t+delta+d/2,T));
33 | line([-1.5 1.5], [0 0])
34 | xlabel('Time Delay [chip]','Fontsize',24)
35 | ylabel('Correlation','Fontsize',24)
36 | set(t32,'color','k','linewidth',1.5)
37 | axis([-1.5 1.5 -.5 1.5])
38 | axis equal
39 | set(gca,'FontSize',24);
40 | title('')
41 | hold off
42 | print -deps2 corrd2
43 |
44 | figure(3);
45 | hold on
46 | h1 = ezplot(R(t+d/2,T) - R(t-d/2,T)); % coherent discriminator
47 | set(h1,'color','k','linewidth',1)
48 | h2 = ezplot((R(t+d/2,T))^2 - (R(t-d/2,T))^2); % non-coherent product discriminato
49 | set(h2,'color','k','linewidth',1,'linestyle','--')
50 | xlabel('Time Delay [chip]','FontSize',18)
51 | title('')
52 | axis equal
53 | set(gca,'FontSize',18);
54 | grid on
55 | print -deps2 discr
56 |
57 | %%%%%%%%%%%%%%%% discr.m %%%%%%%%%%%%%%%%%%
58 |
--------------------------------------------------------------------------------
/plots/figure_scripts/env.m:
--------------------------------------------------------------------------------
1 | %Multipath envelope,
2 | % delta is geometric multipath and t is multipath error
3 | % Implementation of equation (180) and (18) in
4 | % Bernd Eissfeller (1997): Ein dynamisches Fehlermodell
5 | % f\"ur GPS Autokorrelationsempf\"anger. Universit\"at der
6 | % Bundeswehr M\"unchen, Heft 55
7 |
8 | % Kai Borre, February 27, 2005
9 |
10 | syms delta t
11 |
12 | T = 300; %1; % chip length
13 | alpha = .5; % signal-to-multipath ratio (SMR)
14 |
15 | d = 300; %1; % correlator spacing
16 | h1 = ezplot( R(t-d/2,T) - R(t+d/2,T) + alpha*( R(t-delta-d/2,T)- R(t-delta+d/2,T) ), [0,500,-80,80]);
17 | hold on
18 | h2 = ezplot( R(t-d/2,T) - R(t+d/2,T) - alpha*( R(t-delta-d/2,T)- R(t-delta+d/2,T) ), [0,500,-80,80]);
19 | set([h1, h2],'linewidth',1.8')
20 |
21 | d = 150; %.5; % changed correlator spacing
22 | h3 = ezplot( R(t-d/2,T) - R(t+d/2,T) + alpha*( R(t-delta-d/2,T)- R(t-delta+d/2,T) ), [0,500,-80,80]);
23 | h4 = ezplot( R(t-d/2,T) - R(t+d/2,T) - alpha*( R(t-delta-d/2,T)- R(t-delta+d/2,T) ), [0,500,-80,80]);
24 | set([h3,h4], 'linewidth',1.3)
25 |
26 |
27 | d = 30; %.1; % changed correlator spacing
28 | h5 = ezplot( R(t-d/2,T) - R(t+d/2,T) + alpha*( R(t-delta-d/2,T)- R(t-delta+d/2,T) ), [0,500,-80,80]);
29 | h6 = ezplot( R(t-d/2,T) - R(t+d/2,T) - alpha*( R(t-delta-d/2,T)- R(t-delta+d/2,T) ), [0,500,-80,80]);
30 | set([h5,h6], 'linewidth',.8)
31 |
32 | title('')
33 | ylabel('Ranging error {\it\tau} [m]','fontsize',18)
34 | xlabel('Multipath delay {\it\delta} [m]','fontsize',18)
35 | hold off
36 | legend([h1, h3, h5],'{\itd} =1.0','{\itd} = 0.5','{\itd} = 0.1')
37 | set(gca,'Fontsize',18)
38 | box off
39 | legend('boxoff')
40 |
41 | print -deps2 env
42 | %%%%%%%%%%%%%%%%%%% env.m %%%%%%%%%%%%%%%
43 |
--------------------------------------------------------------------------------
/plots/figure_scripts/fig41.m:
--------------------------------------------------------------------------------
1 | % Frequency domain depiction of the GPS signal and thermal noise
2 | % power
3 |
4 | %Written by Kai Borre, October 1, 2005
5 |
6 | f0 = 1.023e6;
7 | delta_f = linspace(-15e6, 15e6, 999); % difference with respect to f0
8 | noise_floor = 2*randn(1,length(delta_f))+db(2*1e-6);
9 |
10 | figure(1);
11 | h1 = plot(delta_f.*pi/2, db( (sinc(pi*delta_f/(2*f0))).^2./f0),...
12 | 'linewidth', 1.5,'linestyle','-');
13 | hold on
14 | h2 = plot(delta_f.*pi/2, noise_floor,'linewidth',1.5,'linestyle','--');
15 | hleg = legend('GPS C/A','Noise floor, 2 MHz BW');
16 | set(gca,'XTick',[-5*1e6 -1e6 0 1e6 5*1e6])
17 | set(gca,'XTickLabel',{'-5','-1','0','1','5'})
18 | axis([-5*f0 5*f0 -190 -80]);
19 | set(gca,'FontSize',16)
20 | hold off
21 | ylabel('Power [dBm]')
22 | xlabel('Frequency [MHz]')
23 | box off
24 | legend('boxoff')
25 | %title('Center Frequency 1575.42 MHz')
26 |
27 | print -deps2 fig4_1
28 | %%%%%%%%%%%%%%%%%%%%%% end fig41.m %%%%%%%%%%%%%%%
29 |
30 |
31 |
--------------------------------------------------------------------------------
/plots/figure_scripts/fig47.m:
--------------------------------------------------------------------------------
1 | % Frequency domain depiction of the GPS signal and thermal noise
2 | % power
3 |
4 | %Written by Kai Borre, October 1, 2005
5 |
6 | f0 = 1.023e6;
7 | delta_f = linspace(-15e6, 15e6, 999); % difference with respect to f0
8 | noise_floor = 2*randn(1,length(delta_f))+db(2*1e-6);
9 |
10 | % Interpolation for graph for RF filter
11 | x = [-3*f0 0 3*f0];
12 | y = [-140 -115 -140];
13 | xi = f0*(-3:.5:3);
14 | yi = interp1(x,y,xi,'cubic');
15 |
16 | figure(1);
17 | h1 = plot(delta_f.*pi/2, db( (sinc(pi*delta_f/(2*f0))).^2./f0),...
18 | 'linewidth',1.5,'linestyle','-');
19 | hold on
20 | h2 = plot(delta_f.*pi/2, noise_floor,'linewidth',...
21 | 1.5,'linestyle','--');
22 | h3 = plot(xi,yi,':','linewidth',1);
23 | legend('GPS C/A','Noise floor, 2 MHz BW','RF filter')
24 | plot([0 3*f0], [-120 -120],'linewidth',1,'linestyle',':');
25 | text(3.1*f0,-120,'{\it\approx -n} dBm');
26 | text(3.1*f0,-126,'(> -120 dBm)');
27 | set(gca,'XTick',[-5*1e6 -1e6 0 1e6 5*1e6])
28 | set(gca,'XTickLabel',{'-5','-1','0','1','5'})
29 | axis([-5*f0 5*f0 -190 -70]);
30 | set(gca,'FontSize',16)
31 | hold off
32 | ylabel('Power [dBm]')
33 | xlabel('Frequency [MHz]')
34 | %title('Center Frequency 1575.42 MHz')
35 | box off
36 | legend('boxoff')
37 |
38 | print -deps2 fig4_7
39 | %%%%%%%%%%%%%%%%%%%%%% end fig47.m %%%%%%%%%%%%%%%
40 |
41 |
42 |
--------------------------------------------------------------------------------
/plots/figure_scripts/figure_7_dll.m:
--------------------------------------------------------------------------------
1 | %--------------------------------------------------------------------------
2 | % Copyright (C) Darius Plausinaitis
3 | % Written by Darius Plausinaitis
4 | %--------------------------------------------------------------------------
5 |
6 | % CVS record:
7 | % $Id: figure_7_dll.m,v 1.1.2.2 2006/08/18 12:05:02 dpl Exp $
8 |
9 |
10 | t = linspace(-1.5, 1.5, 400);
11 |
12 | delay = 0.5;
13 |
14 | coherent = Tri(t-delay) - Tri(t+delay);
15 | power = Tri(t-delay).^2 - Tri(t+delay).^2;
16 | normPower = (Tri(t-delay).^2 - Tri(t+delay).^2) ./ (Tri(t-delay).^2 + Tri(t+delay).^2);
17 | dotProduct = Tri(t) .* (Tri(t-delay) - Tri(t+delay));
18 |
19 | %Plot results. The sign of results is inverted to have a "mirrored version"
20 | %of the results. This is because in the code negative t values mean advance
21 | %in time, while negative values in x axis mean delay of the code.
22 | plot(t, -dotProduct);
23 | hold on
24 | plot(t, -normPower);
25 | plot(t, -power);
26 | plot(t, -coherent);
27 | hold off
28 |
29 | legend('Dot product', 'Normalized power', 'Power', 'Coherent');
30 | xlabel('True offset of the two codes [chips]');
31 | ylabel('DLL discriminator output');
32 |
33 | postPlot(get(gca, 'children'), 1);
34 |
35 | axis ([-1.5, 1.5, -1.1, 1.1]);
--------------------------------------------------------------------------------
/plots/figure_scripts/figure_7_pll.m:
--------------------------------------------------------------------------------
1 | %--------------------------------------------------------------------------
2 | % Copyright (C) Darius Plausinaitis
3 | % Written by Darius Plausinaitis
4 | %--------------------------------------------------------------------------
5 |
6 | % CVS record:
7 | % $Id: figure_7_pll.m,v 1.1.2.2 2006/08/18 12:05:02 dpl Exp $
8 |
9 | t = linspace(-180, 180, 400);
10 | phi = linspace(-pi, pi, 400);
11 |
12 | delay = 0.5;
13 |
14 | arctan=atan(sin(phi)./cos(phi));
15 | dotProduct = sin(phi).*cos(phi);
16 | signProduct = sin(phi).*sign(cos(phi));
17 | % arctan2=atan2(sin(phi),cos(phi));
18 |
19 | plot(t, arctan * (180/pi));
20 | hold on
21 | plot(t, signProduct * (180/pi));
22 | plot(t, dotProduct * (180/pi));
23 | % plot(t, arctan2 * (180/pi));
24 | hold off
25 |
26 | legend('arctan({\itQ}/{\itI})', 'sign({\itI})*{\itQ}', '{\itI}*{\itQ}');
27 | xlabel('True phase error [\circ]');
28 | ylabel('Discriminator output [\circ]')
29 | postPlot(get(gca, 'children'), 1);
30 | axis ([-180, 180, -100, 100]);
31 |
--------------------------------------------------------------------------------
/plots/figure_scripts/geoid.m:
--------------------------------------------------------------------------------
1 | % Script for Figure 14.6: The WGS84 geoid
2 | % The data in heights can be found in Table 6.1 in
3 | % Department of Defense World Geodetic System 1984
4 | % Its Definition and Relationships with Local Geodetic Systems.
5 | % DMA Technical Report, Second Edition, 1 September 1991
6 |
7 | % We have changed sign of heights(12,8) to get a contour map
8 | % similar to that officially published.
9 |
10 | %Kai Borre 06-22-97
11 | %Copyright (c) by kai Borre
12 | %$Revision: 1.0 $ $Date: 1997/09/22 $
13 |
14 | heights = [ ...
15 | 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13,...
16 | 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13;
17 | 33 34 28 23 17 13 9 4 4 1 -2 -2 0 2 3 2 1 1,...
18 | 3 1 -2 -3 -3 -3 -1 3 1 5 9 11 19 27 31 34 33 34;
19 | 51 43 29 20 12 5 -2 -10 -14 -12 -10 -14 -12 -6 -2 3 6 4,...
20 | 2 2 1 -1 -3 -7 -14 -24 -27 -25 -19 3 24 37 47 60 61 58;
21 | 47 41 21 18 14 7 -3 -22 -29 -32 -32 -26 -15 -2 13 17 19 6,...
22 | 2 9 17 10 13 1 -14 -30 -39 -46 -42 -21 6 29 49 65 60 57;
23 | 47 48 42 28 12 -10 -19 -33 -43 -42 -43 -29 -2 17 23 22 6 2,...
24 | -8 8 8 1 -11 -19 -16 -18 -22 -35 -40 -26 -12 24 45 63 62 59;
25 | 52 48 35 40 33 -9 -28 -39 -48 -59 -50 -28 3 23 37 18 -1 -11,...
26 | -12 -10 -13 -20 -31 -34 -21 -16 -26 -34 -33 -35 -26 2 33 59 52 51;
27 | 36 28 29 17 12 -20 -15 -40 -33 -34 -34 -28 7 29 43 20 4 -6,...
28 | -7 -5 -8 -15 -28 -40 -42 -29 -22 -26 -32 -51 -40 -17 17 31 34 44;
29 | 31 26 15 6 1 -29 -44 -61 -67 -59 -36 -11 21 39 49 39 22 10,...
30 | 5 10 7 -7 -23 -39 -47 -34 -9 -10 -20 -45 -48 -32 -9 17 25 31;
31 | 22 23 2 -3 -7 -36 -59 -90 -95 -63 -24 12 53 60 58 46 36 26,...
32 | 13 12 11 2 -11 -28 -38 -29 -10 3 1 -11 -41 -42 -16 3 17 33;
33 | 18 12 -13 -9 -28 -49 -62 -89 -102 -63 -9 33 58 73 74 63 50 32,...
34 | 22 16 17 13 1 -12 -23 -20 -14 -3 14 10 -15 -27 -18 3 12 20;
35 | 12 13 -2 -14 -25 -32 -38 -60 -75 -63 -26 0 35 52 68 76 64 52,...
36 | 36 22 11 6 -1 -8 -10 -8 -11 -9 1 32 4 -18 -13 -9 4 14;
37 | 17 23 21 8 -9 -10 -11 -20 -40 -47 -45 -25 5 23 45 58 57 63,...
38 | 51 27 10 0 -9 -11 -5 -2 -3 -1 9 35 20 -5 -6 -5 0 13;
39 | 22 27 34 29 14 15 15 7 -9 -25 -37 -39 -23 -14 15 33 34 45,...
40 | 46 22 5 -2 -8 -13 -10 -7 -4 1 9 32 16 4 -8 4 12 15;
41 | 18 26 31 33 39 41 30 24 13 -2 -20 -32 -33 -27 -14 -2 5 20,...
42 | 21 6 1 -7 -12 -12 -12 -10 -7 -1 8 23 15 -2 -6 6 21 24;
43 | 25 26 34 39 45 45 38 39 28 13 -1 -15 -22 -22 -18 -15 -14 -10,...
44 | -15 -18 -18 -16 -17 -15 -10 -10 -8 -2 6 14 13 3 3 10 20 27;
45 | 16 19 25 30 35 35 33 30 27 10 -2 -14 -23 -30 -33 -29 -35 -43,...
46 | -45 -43 -37 -32 -30 -26 -23 -22 -16 -10 -2 10 20 20 21 24 22 17;
47 | 16 16 17 21 20 26 26 22 16 10 -1 -16 -29 -36 -46 -55 -54 -59,...
48 | -61 -60 -61 -55 -49 -44 -38 -31 -25 -16 -6 1 4 5 4 2 6 12;
49 | -4 -1 1 4 4 6 5 4 2 -6 -15 -24 -33 -40 -48 -50 -53 -52,...
50 | -53 -54 -55 -52 -48 -42 -38 -38 -29 -26 -26 -24 -23 -21 -19 -16 -12 -8;
51 | -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30,...
52 | -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30 -30];
53 |
54 | e = exist('geoid.eps');
55 | if e ~= 0, delete('geoid.eps'), end
56 |
57 | heights = [heights heights(:,1)];
58 | height = flipud(heights);
59 | [X,Y] = meshgrid(0:10:360,0:10:180);
60 | Z = height;
61 | [XI,YI]= meshgrid(0:360,0:180);
62 | ZI = interp2(X,Y,Z,XI,YI,'cubic');
63 |
64 | % contour of continents
65 | set(gca,'visible','off','nextplot','add',...
66 | 'plotboxaspectratio',[1 .5 1]);
67 | load topo
68 | to = ones(size(topo)); % all sea
69 | to(find(topo > 0)) = 2; % sea to land
70 | colormap([1 1 1; .8 .8 .8]); % white for sea, and gray for land
71 | image(to);
72 | axis xy
73 | axis image
74 | %[c,ht] = contour(topo,[0 0]);
75 | % set(ht,'linewidth',1.5);
76 |
77 | % contour of geoid
78 | [c,hand]= contour(ZI);
79 | clabel(c,hand);
80 |
81 | print geoid -deps
82 | %%%%%%%%%%%%% end geoid.m %%%%%%%%%%%%%%%%%%%%%%
83 |
--------------------------------------------------------------------------------
/plots/figure_scripts/gps_sig.m:
--------------------------------------------------------------------------------
1 | % Demonstration of BPSK modulation
2 | % and demodulation
3 |
4 | % Kai Borre February 26, 2005
5 | % Edited March 11, 2006; June 3, 2006
6 |
7 | PRN_1 = PRNgen(1); % SVN 1
8 | len = 25;
9 | code = PRN_1(1:len); % first 25 chips for PRN1
10 |
11 | x = zeros(1,len); % creating a rectangular graph
12 | y = x;
13 | t = 1:len;
14 | x(1) = .5;
15 | y(1) = code(1);
16 | s = 2;
17 | for i = 2:len
18 | if code(i) ~= code(i-1)
19 | x(s) = t(i)+.5;
20 | x(s+1) = x(s);
21 | y(s) = code(i-1);
22 | y(s+1) = code(i);
23 | s = s+2;
24 | end
25 | end
26 |
27 | x2 = [.5 18.5 18.5 len-.5]; % navigation data
28 | y2 = [1 1 -1 -1];
29 |
30 | navy = y; % Chip times nav
31 | ch = find(x>=18.5);
32 | navy(ch) = -navy(ch);
33 |
34 | x3 = x;
35 | x3(16:17) = []; % crude corrections
36 | navy3 = navy;
37 | navy3(16:17) = [];
38 |
39 | phi = linspace(0,len,10*len); % carrier wave
40 | ycar = sin(phi*2*pi);
41 | code1 = [ 1 code(1:end-1)];
42 | code1(19:25) = -code1(19:25); % crude correction
43 | phim = ycar.*kron(code1,ones(1,10)); %phimod; %modulated carrier phase
44 |
45 | figure(1);
46 | plot(x,y+4, x2, y2+1, x3,-navy3-2,...
47 | phi+0.5,ycar-5, phi+0.5,phim-8,'linewidth',1)
48 | axis([-5 len+5 -9.5 5.5])
49 | axis off
50 |
51 | print -deps2 gps_sig
52 |
53 | figure(2);
54 | plot(phi+0.5,phim-2, x3,navy3-5, phi+0.5,ycar-8,'linewidth',1);
55 | axis([-5 len+5 -9.5 5.5])
56 | axis off
57 |
58 | print -deps2 gps_demod
59 |
60 | %%%%%%%%%%%%%%%%%% gps_sig.m %%%%%%%%%%%%%
61 |
62 |
63 |
--------------------------------------------------------------------------------
/plots/figure_scripts/m_discr.m:
--------------------------------------------------------------------------------
1 | % Constructive and destructive multipath interference
2 |
3 | % Kai Borre, March 27, 2006
4 |
5 | syms delta t
6 |
7 | T = 1; % chip length
8 | d = 1; % correlator spacing
9 | alpha = .3; % amplitude of multipath signal
10 |
11 | figure(1); % constructive interference
12 | hold on
13 | h1 = ezplot( R(t-d/2,T));
14 | h2 = ezplot(alpha*R(-.6+t-d/2,T));
15 | h3 = ezplot(R(t-d/2,T)+alpha*R(-.6+t-d/2,T)); %-
16 | line([-1 2.5], [ 0 0]);
17 | set(h2,'linestyle', '--');
18 | set(h3,'linewidth', 1.5);
19 | xlabel('Time delay [chip]','FontSize',24)
20 | set(gca,'FontSize',24)
21 | title('');
22 | axis([-1 2.5 -.3 1.3])
23 | hold off
24 | print -deps2 m_discr1
25 |
26 | figure(2); % destructive interference
27 | hold on
28 | h1 = ezplot( R(t-d/2,T));
29 | h2 = ezplot(-alpha*R(-.6+t-d/2,T));
30 | h3 = ezplot(R(t-d/2,T)-alpha*R(-.6+t-d/2,T)); %+
31 | line([-1 2.5], [ 0 0]);
32 | set(h2,'linestyle', '--');
33 | set(h3,'linewidth', 1.5);
34 | xlabel('Time delay [chip]','FontSize',24)
35 | set(gca,'FontSize',24)
36 | title('');
37 | axis([-1 2.5 -1 1.3])
38 | hold off
39 | print -deps2 m_discr2
40 |
41 | %%%%%%%%%%%%%%%%%%%%% end m_discr.m %%%%%%%%%%%%
42 |
--------------------------------------------------------------------------------
/plots/figure_scripts/multi_env_boc.m:
--------------------------------------------------------------------------------
1 | function multi_env_boc()
2 | %--------------------------------------------------------------------------
3 | % Copyright (C) Darius Plausinaitis and Kai Borre
4 | % Written by Darius Plausinaitis and Kai Borre
5 | %--------------------------------------------------------------------------
6 |
7 | % CVS record:
8 | % $Id: multEnvBOC.m,v 1.1.2.2 2006/08/18 12:05:02 dpl Exp $
9 |
10 | maxDelay = 500; %[m]
11 | maxOffset = 80; %[m]
12 |
13 | lcode = 299.792458; %code length in meters
14 |
15 | alpha = 0.5;
16 |
17 | d = 1; %chip spacing
18 |
19 | h(1) = ezplot(@(delay, offset)multipathBOC(offset/lcode, delay/lcode, -alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
20 |
21 | hold on
22 |
23 | h(2) = ezplot(@(delay, offset)multipathBOC(offset/lcode, delay/lcode, alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
24 |
25 | d = 0.5; %chip spacing
26 |
27 | h(3) = ezplot(@(delay, offset)multipathBOC(offset/lcode, delay/lcode, -alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
28 | h(4) = ezplot(@(delay, offset)multipathBOC(offset/lcode, delay/lcode, alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
29 |
30 | d = 0.1; %chip spacing
31 |
32 | h(5) = ezplot(@(delay, offset)multipathBOC(offset/lcode, delay/lcode, -alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
33 | h(6) = ezplot(@(delay, offset)multipathBOC(offset/lcode, delay/lcode, alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
34 |
35 |
36 | h(7) = ezplot(@(delay, offset)multipathRec(offset/lcode, delay/lcode, -alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
37 | % hold on
38 | h(8) = ezplot(@(delay, offset)multipathRec(offset/lcode, delay/lcode, alpha, d), [0, maxDelay, -maxOffset, maxOffset]);
39 |
40 | hold off
41 |
42 | set(h(1:2), 'LineStyle', '-')
43 | set(h(3:4), 'LineStyle', '--')
44 | set(h(5:6), 'LineStyle', '-.')
45 | set(h(7:8), 'LineStyle', ':')
46 | set(h, 'LineWidth', 1)
47 |
48 | xlabel('Multipath delay \delta [m]')
49 | ylabel('Ranging error \tau [m]')
50 | title('')
51 | box off
52 | legend(h([1,3,5, 7]),'{\itd} = 1','{\itd} = 0.5', '{\itd} = 0.1', '{\itd} = 0.1 (C/A)')
53 | legend boxoff
54 |
55 | function correlation = multipathRec(offset, delay, alpha, d)
56 |
57 | d = d/2;
58 |
59 | earlyCorrelator = (Tri(offset - d) + alpha * Tri(offset - d - delay));
60 | lateCorrelator = (Tri(offset + d) + alpha * Tri(offset + d - delay));
61 |
62 | correlation = earlyCorrelator - lateCorrelator;
63 |
64 | function correlation = multipathBOC(offset, delay, alpha, d)
65 |
66 | n=2;
67 |
68 | d = d/2;
69 |
70 | earlyCorrelator = (acf_boc(offset - d, n, 1) + alpha * acf_boc(offset - d - delay, n, 1));
71 | lateCorrelator = (acf_boc(offset + d, n, 1) + alpha * acf_boc(offset + d - delay, n, 1));
72 |
73 | correlation = earlyCorrelator - lateCorrelator;
74 |
75 | function result = acf_boc(x, n, sin_type)
76 |
77 | result = 0;
78 |
79 | sum = 0;
80 | sign = -1;
81 | r = -1;
82 |
83 | x = x * n * 2.0;
84 |
85 | if (sin_type) r = 1.0; end;
86 | if (mod(n, 2)) sign = 1; end
87 |
88 | for k=1:n-1
89 | sum = sum + sign * (2.0*k*Tri(x-2.0*(n-k)) + r * Tri(x-2.0*(n-k)-1.0) + 2.0 * k * Tri(x+2.0*(n-k)) + r*Tri(x+2.0*(n-k)+1.0));
90 | sign= -sign;
91 | end
92 |
93 | sum = sum + sign * (2.0*n*Tri(x) + r * Tri(x-1.0) + r * Tri(x +1.0));
94 |
95 | result = sum/(2*n);
96 |
--------------------------------------------------------------------------------
/plots/figure_scripts/plot1.m:
--------------------------------------------------------------------------------
1 | % Generates a stem plot showing the ACF
2 | % for a Gold sequnce
3 |
4 | % Kai Borre, February 12, 2006
5 |
6 | ca_codes
7 | close all
8 |
9 | figure(1)
10 | pl = stem(0:51,[0 Corr11(1:50) 0],'.');
11 | axis off
12 | set(get(pl,'Baseline'),'linestyle','-')
13 | set(pl,'Markersize',4,'linewidth',1.5)
14 | axis tight
15 |
16 | print -deps2 prn50
17 | %%%%%%%%%%%%%%%%%%%%
18 |
19 |
20 |
--------------------------------------------------------------------------------
/plots/figure_scripts/plot_parallel_code_search.m:
--------------------------------------------------------------------------------
1 | %function plotParalCodeSearch(results, frqBins, PRN)
2 |
3 | % The variable "results" is taken from the function "acquisition.m". The
4 | % function is stopped at the point where script has to decide if there is
5 | % the GNSS signal or not (if statement).
6 | %
7 | % This script can be used to plot results of serial search algorithm. The
8 | % serial search source code is not included.
9 |
10 | %--------------------------------------------------------------------------
11 | % Copyright (C) Darius Plausinaitis
12 | % Written by Darius Plausinaitis
13 | % Based on Peter Rinder and Nicolaj Bertelsen
14 | %--------------------------------------------------------------------------
15 |
16 | %CVS record:
17 | %$Id: plotParalCodeSearch.m,v 1.1.2.2 2006/08/18 12:05:02 dpl Exp $
18 |
19 | [xsize, ysize] = size(results);
20 |
21 | s=surf(1:ysize, frqBins(1:xsize)/1e6, results);
22 | set(s,'EdgeColor','none','Facecolor','interp');
23 | %xlabel('Code phase\newline [chips]');
24 | xlabel('Code phase\newline [samples]');
25 | ylabel('Frequency\newline [MHz]');
26 | zlabel('Magnitude');
27 | text=sprintf('PRN %i', PRN);
28 | title(text);
29 | axis tight;
30 |
31 | % view(az, el);
32 | % colormap(fig69colormap);
33 |
34 | % fig69colormap = colormap;
35 | % [az, el] = view;
--------------------------------------------------------------------------------
/plots/figure_scripts/plot_parallel_freq_search.m:
--------------------------------------------------------------------------------
1 | % This script plots results of parallel frequency search. The source code
2 | % is not included. The search algorithm requires a lot of computational
3 | % resources and produces a great amount of data, therefore only a smaller
4 | % portion of total results is plotted:
5 | % - the frequency region 5-15 MHz is a subset of the full region 0-19 MHz
6 | % - the code search region is 1-500 chips instead of 1-1023.
7 |
8 | %--------------------------------------------------------------------------
9 | % Copyright (C) Darius Plausinaitis
10 | % Written by Darius Plausinaitis
11 | % Based on Peter Rinder and Nicolaj Bertelsen
12 | %--------------------------------------------------------------------------
13 |
14 | %CVS record:
15 | %$Id: plotParalFreqSearch.m,v 1.1.2.2 2006/08/18 12:05:02 dpl Exp $
16 |
17 | s=surf(5.001:0.001:15.000, 1:500, result);
18 | set(s,'EdgeColor','none');
19 | ylabel('Code phase\newline [chips]');
20 | xlabel('Frequency\newline [MHz]');
21 | zlabel('Magnitude');
22 | text=sprintf('PRN %i',svnum);
23 | title(text);
24 | ha = gca();
25 | zlim(ha, myZlim);
26 | axis tight
27 | view(-49,25);
28 | set(ha, 'zminortick', 'on');
29 | % caxis(ha, myCaxis)
30 | % colormap(ha, myColormap);
31 |
32 | % This is a trick to replace the data inside of the plot. It does not
33 | % update any of the plot properties (axes, limits, view angle etc.).
34 | %
35 | % set(get(gca,'children'),'zdata',result2)
36 |
--------------------------------------------------------------------------------
/plots/figure_scripts/psd_boc.m:
--------------------------------------------------------------------------------
1 | % Power PSpectral Density for Galileo BOC(1,1) and GPS C/A
2 |
3 | %Written by Kai Borre, February 14, 2005
4 |
5 | f0 = 1.023e6;
6 | alpha = 1;
7 | beta = 1;
8 | if rem(alpha/beta,2) == 0,
9 | even = 'true';
10 | else
11 | even = 'false';
12 | end
13 |
14 | delta_f = linspace(-15e6,15e6,999); % difference with respect to L1
15 | fs = alpha*f0;
16 | fc = beta*f0;
17 | n = 2*fs/fc;
18 | r = rem(n,2);
19 | if r == 0, even = 'true'; end
20 | if even
21 | G = fc* ( tan(pi*delta_f/(2*fs)).*sin(pi*delta_f/fc)./(pi*delta_f+eps) ).^2;
22 | else
23 | G = fc* ( tan(pi*delta_f/(2*fs)).*cos(pi*delta_f/fc)./(pi*delta_f+eps) ).^2;
24 | end
25 |
26 | figure(1);
27 | h1 = semilogy(delta_f,G, 'linewidth',1); % BOC
28 | hold on
29 | h2 = semilogy(delta_f.*pi/2, (sinc(pi*delta_f/(2*fc))).^2./fc,...
30 | 'linewidth', 1,'linestyle','-.'); % GPS
31 | set(gca,'XTick',[-6*1e6 -4*1e6 -2*1e6 0 2*1e6 4*1e6 6*1e6])
32 | set(gca,'XTickLabel',{'-6','-4','-2','0','2','4','6'})
33 |
34 | legend('Galileo BOC(1,1)','GPS C/A')
35 | xlabel('Frequency [MHz]','FontSize',18)
36 | ylabel('Power','Fontsize',18)
37 | %title('Center Frequency 1575.42 MHz','FontSize',18)
38 | axis([-6e6 6e6 1e-10 1e-5]);
39 | box off
40 | legend('boxoff')
41 | hold off
42 | set(gca,'FontSize',18)
43 |
44 | print -deps2 psd_boc
45 | %%%%%%%%%%%%%%%%%%%%%% end psd_boc.m %%%%%%%%%%%%%%%
46 |
47 |
48 |
--------------------------------------------------------------------------------
/plots/figure_scripts/sincfig.m:
--------------------------------------------------------------------------------
1 | %plot of sinc
2 | % For Figure 1.3 in S/W book
3 |
4 |
5 | t = linspace(-8,8,500);
6 | figure(1);
7 | plot(abs(sinc(t)),'linewidth',2)
8 | hold on
9 | plot([0 500],[0 0]);
10 | axis off
11 | print -deps swsinc1
12 |
13 | figure(2);
14 | plot((sinc(t)).^2,'linewidth',2)
15 | hold on
16 | plot([0 500],[0 0]);
17 | axis off
18 | print -deps swsinc2
19 |
20 | %%%%%%%%%%%%%%%%%
21 |
--------------------------------------------------------------------------------
/plots/figure_scripts/winkel4.m:
--------------------------------------------------------------------------------
1 | % The ACF for the BOC signal as function of delay.
2 | % Eq. (2.68) and Figure 2.27 in Jon Winkel (2002).
3 | % The infinite bandwidth and bandlimited cases
4 |
5 | % Written by Kai Borre, February 26, 2005
6 |
7 | no = 300;
8 | t = linspace(-5,5,no);
9 | Tc = 1;
10 | Y = zeros(3,no);
11 | n = 1;
12 | k = 0;
13 |
14 | % infinite bandwidth, b = infty
15 | s = zeros(1,no);
16 | s = ( 2*R(t./Tc-2*k,1) - R(t./Tc-2*k-1,1) -R(t./Tc-2*k+1,1));
17 | Y(n,:) = s/2;
18 |
19 | % bandlimited cases, b = 1 and 0.5
20 | for i = 1:2
21 | if i == 1, b =1; else b = 0.5; end;
22 | s = ( 2.*R_BL(t./Tc-2.*k,b) - R_BL(t./Tc-2.*k-1,b) -R_BL(t./Tc-2.*k+1,b));
23 | Y(i+1,:) = s/2;
24 | end
25 |
26 | h1 = plot(t/2,Y(1,:)');
27 | hold on
28 | h2 = plot(t/2,Y(2,:)');
29 | h3 = plot(t/2,Y(3,:)');
30 | axis([-2.2 2.2 -.7 1.1])
31 | set(h1,'linestyle','-');
32 | set(h2,'linestyle','--');
33 | set(h3,'linestyle','-.');
34 | xlabel('Delay [chip]','fontsize',18)
35 | ylabel('Normalized amplitude','fontsize',18)
36 | legend('{\itb} = \infty', '{\itb} = 1', '{\itb} = 0.5')
37 | hold off
38 | box off
39 | legend('boxoff')
40 | set(gca,'FontSize',18)
41 |
42 | print -deps2 acf_bocl
43 | %%%%%%%%%%%% winkel4.m %%%%%%%%%%%%%%
44 |
45 |
--------------------------------------------------------------------------------
/plots/figure_scripts/winkel8.m:
--------------------------------------------------------------------------------
1 | % R_X(tau) as given by Nunes & Sousa & Leitao (2004).
2 |
3 | %Written by Kai Borre
4 | % February 26, 2005
5 |
6 | Tc = 1;
7 | t = linspace(-1,1,1000);
8 |
9 | for p = [1,2,4]
10 | k = ceil(2*p.*abs(t)/Tc);
11 | f = (-1).^(k+1);
12 | R(p,:) = f.*((-k.^2+2*k.*p+k-p)/p - (4*p-2.*k+1).*(abs(t)./Tc));
13 | end
14 |
15 | h1 = plot(t,R(1,:));
16 | hold on
17 | h2 = plot(t,R(2,:));
18 | h4 = plot(t,R(4,:));
19 | set(h1,'linestyle','-','linewidth',1)
20 | set(h2,'linestyle','--','linewidth',1)
21 | set(h4,'linestyle','-.','linewidth',1)
22 | xlabel( 'Delay [chip]','fontsize',18)
23 | ylabel('Correlation','fontsize',18)
24 | legend('{\itp} = 1', '{\itp} = 2','{\itp} = 4')
25 | set(gca,'FontSize',18)
26 | axis([-1.2 1.2 -0.9 1.1])
27 | box off
28 | legend('boxoff')
29 | hold off
30 |
31 | print -deps fig3-3
32 | %%%%%%%%%%%% end winkel8.m %%%%%%%%
33 |
--------------------------------------------------------------------------------
/plots/plot_acquisition.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function plot_acquisition(acqResults)
10 |
11 | figure(101);
12 |
13 | hAxes = newplot();
14 |
15 | bar(hAxes, acqResults.peakMetric);
16 |
17 | title (hAxes, 'Acquisition results');
18 | xlabel(hAxes, 'PRN number (no bar - SV is not in the acquisition list)');
19 | ylabel(hAxes, 'Acquisition Metric');
20 |
21 | oldAxis = axis(hAxes);
22 | axis (hAxes, [0, 33, 0, oldAxis(4)]);
23 | set (hAxes, 'XMinorTick', 'on');
24 | set (hAxes, 'YGrid', 'on');
25 |
26 | %% Mark acquired signals ==================================================
27 |
28 | acquiredSignals = acqResults.peakMetric .* (acqResults.carrFreq > 0);
29 |
30 | hold(hAxes, 'on');
31 | bar (hAxes, acquiredSignals, 'FaceColor', [0 0.8 0]);
32 | hold(hAxes, 'off');
33 |
34 | legend(hAxes, 'Not acquired signals', 'Acquired signals');
35 |
--------------------------------------------------------------------------------
/plots/plot_acquisition_results.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function plot_acquisition_results(sdrParams, postProcessResults)
10 | % SUMMAR for plotting different plots for comparison
11 | % of performance, code profiling and accuracy of results.
12 |
13 |
14 | %%% Extract coherent frame data.
15 | currFileNum = sdrParams.stateParams.numFilesProcessed + 1;
16 | dataParams = sdrParams.dataFileParamsList{currFileNum};
17 |
18 | channelId = 1;
19 | if dataParams.selectedChannel ~= -1
20 | numChannels = 1;
21 | channelId = dataParams.selectedChannel;
22 | else
23 | numChannels = dataParams.totalChannels;
24 | channelId = 1:dataParams.totalChannels;
25 | end
26 |
27 | acqAlgoList = sdrParams.sysParams.acqAlgosList;
28 | numAcqAlgos = length(acqAlgoList);
29 |
30 | for chIdx=1:numChannels
31 | for acqAlgoIdx=1:numAcqAlgos
32 |
33 | acqResults = postProcessResults.acqResults{chIdx, acqAlgoIdx}.acqResults;
34 | if ~isempty(acqResults)
35 |
36 | print_string(['Plotting bar graph fpr ', num2str(chIdx),...
37 | '/', num2str(numChannels), ' for algorithm ', acqAlgoList{acqAlgoIdx}]);
38 |
39 | % Bar plot for peak metric bar graph of acquired satellites
40 | plot_acq_peak_metric_bars(sdrParams, postProcessResults, chIdx, channelId, acqAlgoIdx);
41 |
42 | % DDM plots
43 | plot_acq_ddm_map(sdrParams, postProcessResults, chIdx, channelId, acqAlgoIdx);
44 |
45 | end
46 | end
47 | end
48 | end
49 |
50 | function plot_acq_peak_metric_bars(sdrParams, postProcessResults, chIdx, channelId, algoIdx)
51 |
52 | acqResults = postProcessResults.acqResults{chIdx, algoIdx}.acqResults.chAlgoAcqResults;
53 | nacqPrnPeakMetric = postProcessResults.acqResults{chIdx, algoIdx}.acqResults.nacqStats.nacqPrnPeakMetric;
54 | nacqPrnList = postProcessResults.acqResults{chIdx, algoIdx}.acqResults.nacqStats.nacqPrnList;
55 | numAcqSatellites = length(acqResults);
56 | currFileNum = sdrParams.stateParams.numFilesProcessed + 1;
57 | currFrameNum = sdrParams.stateParams.currFrameNum;
58 | numTotalFrames = sdrParams.stateParams.numTotalFrames;
59 | acqAlgoList = sdrParams.sysParams.acqAlgosList;
60 |
61 |
62 | % prepare fields
63 | titleStr = sprintf('Acquisition Results. Total Frames %d\n', numTotalFrames);
64 | channelStr = sprintf('Data channel: %d\n', channelId(chIdx));
65 | acqAlgoStr = sprintf('Acquisition Algorithm: %s', acqAlgoList{algoIdx});
66 |
67 | acqPeakMetric = [];
68 | acqPeakMetricLoc = [];
69 | for aprnIdx=1:numAcqSatellites
70 | acqPeakMetric = [acqPeakMetric, acqResults{aprnIdx}.peakMetric];
71 | acqPeakMetricLoc = [acqPeakMetricLoc, acqResults{aprnIdx}.satellitePrn];
72 | end
73 | peakMetric = [acqPeakMetric, nacqPrnPeakMetric];
74 | peakMetricLoc = [acqPeakMetricLoc, nacqPrnList];
75 |
76 | figWindowTitle = sprintf('Acquisition Bar Graph. File#%d, Data_channel#%d, Algo#%d, Frame#%d', ...
77 | currFileNum, chIdx, algoIdx, currFrameNum);
78 | figure('NumberTitle', 'off', 'Name', figWindowTitle);
79 |
80 | ylimit = max(acqPeakMetric)*1.5;
81 | hAxes = newplot();
82 | hAxes.NextPlot = 'replaceall';
83 | bar(hAxes, peakMetricLoc, peakMetric);
84 | title (hAxes, [titleStr, channelStr, acqAlgoStr], 'Interpreter', 'none');
85 | xlabel(hAxes, 'PRN number (no bar - SV is not in the acquisition list)');
86 | ylabel(hAxes, 'Acquisition Metric');
87 | hAxes.YLim = [0, ylimit]; % Set ylimit to 20 for easier eyeball comparison of plots.
88 |
89 | oldAxis = axis(hAxes);
90 | axis (hAxes, [0, 33, 0, oldAxis(4)]);
91 | set (hAxes, 'XMinorTick', 'on');
92 | set (hAxes, 'YGrid', 'on');
93 |
94 | % Mark acquired signals
95 | qualifiedSignals = peakMetric .* (peakMetric > sdrParams.sysParams.acqThreshold);
96 | hold(hAxes, 'on');
97 | bar (hAxes, peakMetricLoc, qualifiedSignals, 'FaceColor', [0 0.8 0]);
98 |
99 | acquiredSignals = peakMetric .* ismember(peakMetric, acqPeakMetric);
100 | bar (hAxes, peakMetricLoc, acquiredSignals, ...
101 | 'FaceColor',[0 0.8 0],'EdgeColor',[0 .9 .9],'LineWidth',1.5);
102 | legend(hAxes, ...
103 | 'Not acquired signals', ...
104 | 'Acquired signals', ...
105 | 'Selected signals', ...
106 | 'AutoUpdate', 'off');
107 |
108 | axisPos = hAxes.Position;
109 | leftBottomPointX = axisPos(1);
110 | leftBottomPointY = axisPos(2);
111 | rightTopX = axisPos(3)+axisPos(1);
112 | rightTopY = axisPos(4)+axisPos(2);
113 | plotWidth = rightTopX;
114 | plotHeight = rightTopY;
115 |
116 | x = [leftBottomPointX + plotWidth * 0.8, leftBottomPointX + plotWidth * 0.8 ];
117 | y = [leftBottomPointY + plotHeight * 0.6, leftBottomPointY + ...
118 | (sdrParams.sysParams.acqThreshold/ylimit)*axisPos(4)];
119 | annotation('textarrow',x,y,'String','Threshold ', 'Units','normalized', 'Color', 'r');
120 | plot(0:33, sdrParams.sysParams.acqThreshold*ones(1, 34), 'r--');
121 | hold(hAxes, 'off');
122 | end
123 |
124 |
125 | function plot_acq_ddm_map(sdrParams, postProcessResults, chIdx, channelId, algoIdx)
126 |
127 | acqResults = postProcessResults.acqResults{chIdx, algoIdx}.acqResults.chAlgoAcqResults;
128 | numAcqSatellites = length(acqResults);
129 | currFileNum = sdrParams.stateParams.numFilesProcessed + 1;
130 | numTotalFrames = sdrParams.stateParams.numTotalFrames;
131 | acqAlgoList = sdrParams.sysParams.acqAlgosList;
132 |
133 |
134 | % prepare fields
135 |
136 | for aprnIdx=1:numAcqSatellites
137 |
138 | figWindowTitle = sprintf('Acquisition Delay Doppler Map. File#%d, Data_channel#%d, Algo#%d, Frames#%d', ...
139 | currFileNum, chIdx, algoIdx, numTotalFrames);
140 |
141 | figure('NumberTitle', 'off', 'Name', figWindowTitle);
142 |
143 | dopplerShiftAxis = acqResults{aprnIdx}.dopplerShiftAxis;
144 | codeDelayAxis = acqResults{aprnIdx}.codeDelayAxis;
145 |
146 |
147 | mesh(codeDelayAxis, dopplerShiftAxis, acqResults{aprnIdx}.ddm);
148 |
149 |
150 | titleStr = sprintf('Acquisition Delay Doppler Map\n ');
151 | channelStr = sprintf('Data channel: %d\n', channelId(chIdx));
152 | acqAlgoStr = sprintf('Acquisition Algorithm: %s\n', acqAlgoList{algoIdx});
153 | prnStr = sprintf('PRN : %d', acqResults{aprnIdx}.satellitePrn);
154 |
155 |
156 | title ([titleStr, channelStr, acqAlgoStr, prnStr], 'Interpreter', 'none');
157 | zlabel('Correlation Magnitude');
158 | ylabel('Doppler Shift (Hz)');
159 | xlabel('Code Phase (samples)');
160 |
161 | end
162 |
163 | end
164 |
--------------------------------------------------------------------------------
/plots/plot_delay_doppler_map_cpp.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | clear; %close all;
10 | % For C++
11 | fileName = ['NTLab_Bands_GPS_GLONASS_L12'];
12 | load(['../GNSS_SDR_C++/',fileName,'_ddm_mat.mat']);
13 | load(['../GNSS_SDR_C++/',fileName,'_cpp.mat']);
14 |
15 | %For matlab
16 | % load('results_sim0_18.mat');
17 | % load('acqResults_sim0.mat');
18 |
19 | PRN = 8;
20 | frequencyBinIndex = frequencyBinIndex + 1;
21 | codePhaseLast = codePhaseLast + 1;
22 | results = reshape(results, samplesPerCode, numberOfFrqBins)';
23 |
24 | ts = 1 / samplingFreq;
25 | figure(1025)
26 | subplot(2,1,1)
27 | mesh(results)
28 | xlabel('Code phase [chips]')
29 | ylabel('Frequency [MHz]')
30 | title('correlation Map')
31 |
32 | subplot(2,1,2)
33 | imagesc(results)
34 | colorbar
35 |
36 | figddm = figure(1026);
37 | subplot(2,1,1)
38 |
39 | dopplerAxis = frequencyBinIndex-20:frequencyBinIndex+20;
40 | dopplerAxis(find(dopplerAxis < 1)) = [];
41 | dopplerAxis(find(dopplerAxis > numberOfFrqBins)) = [];
42 |
43 | delayAxis = codePhaseLast-50:codePhaseLast+100;
44 | delayAxis(find(delayAxis < 1)) = [];
45 | delayAxis(find(delayAxis > samplesPerCode)) = [];
46 |
47 | DopplerY = frqBins(dopplerAxis)-carrFreq(PRN);
48 | TotalDelaysec = ((1:samplesPerCode)-codePhaseLast)*ts*1e9;
49 | DelayX = TotalDelaysec(delayAxis);
50 | [Xax,Yax]=meshgrid(DelayX,DopplerY);
51 | DDM = results(dopplerAxis,delayAxis);
52 |
53 |
54 | mesh(Xax,Yax,DDM)
55 | xlabel('Delay axis [ns]')
56 | ylabel('Doppler axis [Hz]')
57 | title('Delay Doppler Map')
58 | box on
59 |
60 | subplot(2,1,2)
61 | imagesc(DelayX,DopplerY,DDM)
62 | colorbar
63 | xlabel('Delay axis [ns]')
64 | ylabel('Doppler axis [Hz]')
65 | title('Delay Doppler Map');
66 |
--------------------------------------------------------------------------------
/plots/plot_navigation.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function plot_navigation(navSolutions, settings)
10 | %Functions plots variations of coordinates over time and a 3D position
11 | %plot. It plots receiver coordinates in UTM system or coordinate offsets if
12 | %the true UTM receiver coordinates are provided.
13 | %
14 | %plotNavigation(navSolutions, settings)
15 | %
16 | % Inputs:
17 | % navSolutions - Results from navigation solution function. It
18 | % contains measured pseudoranges and receiver
19 | % coordinates.
20 | % settings - Receiver settings. The true receiver coordinates
21 | % are contained in this structure.
22 |
23 |
24 |
25 | %% Plot results in the necessary data exists ==============================
26 | if (~isempty(navSolutions))
27 |
28 | %% If reference position is not provided, then set reference position
29 | %% to the average postion
30 | if isnan(settings.truePosition.E) || isnan(settings.truePosition.N) ...
31 | || isnan(settings.truePosition.U)
32 |
33 | %=== Compute mean values ==========================================
34 | % Remove NaN-s or the output of the function MEAN will be NaN.
35 | refCoord.E = mean(navSolutions.E(~isnan(navSolutions.E)));
36 | refCoord.N = mean(navSolutions.N(~isnan(navSolutions.N)));
37 | refCoord.U = mean(navSolutions.U(~isnan(navSolutions.U)));
38 |
39 | %Also convert geodetic coordinates to deg:min:sec vector format
40 | meanLongitude = dms2mat(deg2dms(...
41 | mean(navSolutions.longitude(~isnan(navSolutions.longitude)))), -5);
42 | meanLatitude = dms2mat(deg2dms(...
43 | mean(navSolutions.latitude(~isnan(navSolutions.latitude)))), -5);
44 |
45 | refPointLgText = ['Mean Position\newline Lat: ', ...
46 | num2str(meanLatitude(1)), '{\circ}', ...
47 | num2str(meanLatitude(2)), '{\prime}', ...
48 | num2str(meanLatitude(3)), '{\prime}{\prime}', ...
49 | '\newline Lng: ', ...
50 | num2str(meanLongitude(1)), '{\circ}', ...
51 | num2str(meanLongitude(2)), '{\prime}', ...
52 | num2str(meanLongitude(3)), '{\prime}{\prime}', ...
53 | '\newline Hgt: ', ...
54 | num2str(mean(navSolutions.height(~isnan(navSolutions.height))), '%+6.1f')];
55 | else
56 | refPointLgText = 'Reference Position';
57 | refCoord.E = settings.truePosition.E;
58 | refCoord.N = settings.truePosition.N;
59 | refCoord.U = settings.truePosition.U;
60 | end
61 |
62 | figureNumber = 300;
63 | % The 300 is chosen for more convenient handling of the open
64 | % figure windows, when many figures are closed and reopened. Figures
65 | % drawn or opened by the user, will not be "overwritten" by this
66 | % function if the auto numbering is not used.
67 |
68 | %=== Select (or create) and clear the figure ==========================
69 | figure(figureNumber);
70 | clf (figureNumber);
71 | set (figureNumber, 'Name', 'Navigation solutions');
72 |
73 | %--- Draw axes --------------------------------------------------------
74 | handles(1, 1) = subplot(4, 2, 1 : 4);
75 | handles(3, 1) = subplot(4, 2, [5, 7]);
76 | handles(3, 2) = subplot(4, 2, [6, 8]);
77 |
78 | %% Plot all figures =======================================================
79 |
80 | %--- Coordinate differences in UTM system -----------------------------
81 | plot(handles(1, 1), [(navSolutions.E - refCoord.E)', ...
82 | (navSolutions.N - refCoord.N)',...
83 | (navSolutions.U - refCoord.U)']);
84 |
85 | title (handles(1, 1), 'Coordinates variations in UTM system');
86 | legend(handles(1, 1), 'E', 'N', 'U');
87 | xlabel(handles(1, 1), ['Measurement period: ', ...
88 | num2str(settings.navSolPeriod), 'ms']);
89 | ylabel(handles(1, 1), 'Variations (m)');
90 | grid (handles(1, 1));
91 | axis (handles(1, 1), 'tight');
92 |
93 | %--- Position plot in UTM system --------------------------------------
94 | plot3 (handles(3, 1), navSolutions.E - refCoord.E, ...
95 | navSolutions.N - refCoord.N, ...
96 | navSolutions.U - refCoord.U, '+');
97 | hold (handles(3, 1), 'on');
98 | %Plot the reference point
99 | plot3 (handles(3, 1), 0, 0, 0, 'r+', 'LineWidth', 1.5, 'MarkerSize', 10);
100 | hold (handles(3, 1), 'off');
101 |
102 | view (handles(3, 1), 0, 90);
103 | axis (handles(3, 1), 'equal');
104 | grid (handles(3, 1), 'minor');
105 |
106 | legend(handles(3, 1), 'Measurements', refPointLgText);
107 |
108 | title (handles(3, 1), 'Positions in UTM system (3D plot)');
109 | xlabel(handles(3, 1), 'East (m)');
110 | ylabel(handles(3, 1), 'North (m)');
111 | zlabel(handles(3, 1), 'Upping (m)');
112 |
113 | %--- Satellite sky plot -----------------------------------------------
114 | skyPlot(handles(3, 2), ...
115 | navSolutions.channel.az, ...
116 | navSolutions.channel.el, ...
117 | navSolutions.channel.PRN(:, 1));
118 |
119 | title (handles(3, 2), ['Sky plot (mean PDOP: ', ...
120 | num2str(mean(navSolutions.DOP(2,:))), ')']);
121 |
122 | else
123 | disp('plotNavigation: No navigation data to plot.');
124 | end % if (~isempty(navSolutions))
125 |
--------------------------------------------------------------------------------
/plots/plot_tracking.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function plot_tracking(channelList, trackResults, settings)
10 | %This function plots the tracking results for the given channel list.
11 | %
12 | %plotTracking(channelList, trackResults, settings)
13 | %
14 | % Inputs:
15 | % channelList - list of channels to be plotted.
16 | % trackResults - tracking results from the tracking function.
17 | % settings - receiver settings.
18 |
19 |
20 | % Protection - if the list contains incorrect channel numbers
21 | channelList = intersect(channelList, 1:settings.numberOfChannels);
22 |
23 | %=== For all listed channels ==============================================
24 | for channelNr = channelList
25 |
26 | %% Select (or create) and clear the figure ================================
27 | % The number 200 is added just for more convenient handling of the open
28 | % figure windows, when many figures are closed and reopened.
29 | % Figures drawn or opened by the user, will not be "overwritten" by
30 | % this function.
31 |
32 | figure(channelNr +200);
33 | clf(channelNr +200);
34 | set(channelNr +200, 'Name', ['Channel ', num2str(channelNr), ...
35 | ' (PRN ', ...
36 | num2str(trackResults(channelNr).PRN), ...
37 | ') results']);
38 |
39 | %% Draw axes ==============================================================
40 | % Row 1
41 | handles(1, 1) = subplot(3, 3, 1);
42 | handles(1, 2) = subplot(3, 3, [2 3]);
43 | % Row 2
44 | handles(2, 1) = subplot(3, 3, 4);
45 | handles(2, 2) = subplot(3, 3, [5 6]);
46 | % Row 3
47 | handles(3, 1) = subplot(3, 3, 7);
48 | handles(3, 2) = subplot(3, 3, 8);
49 | handles(3, 3) = subplot(3, 3, 9);
50 |
51 | %% Plot all figures =======================================================
52 |
53 | timeAxisInSeconds = (1:settings.msToProcess)/1000;
54 |
55 | %----- Discrete-Time Scatter Plot ---------------------------------
56 | plot(handles(1, 1), trackResults(channelNr).I_P,...
57 | trackResults(channelNr).Q_P, ...
58 | '.');
59 |
60 | grid (handles(1, 1));
61 | axis (handles(1, 1), 'equal');
62 | title (handles(1, 1), 'Discrete-Time Scatter Plot');
63 | xlabel(handles(1, 1), 'I prompt');
64 | ylabel(handles(1, 1), 'Q prompt');
65 |
66 | %----- Nav bits ---------------------------------------------------
67 | plot (handles(1, 2), timeAxisInSeconds, ...
68 | trackResults(channelNr).I_P);
69 |
70 | grid (handles(1, 2));
71 | title (handles(1, 2), 'Bits of the navigation message');
72 | xlabel(handles(1, 2), 'Time (s)');
73 | axis (handles(1, 2), 'tight');
74 |
75 | %----- PLL discriminator unfiltered--------------------------------
76 | plot (handles(2, 1), timeAxisInSeconds, ...
77 | trackResults(channelNr).pllDiscr, 'r');
78 |
79 | grid (handles(2, 1));
80 | axis (handles(2, 1), 'tight');
81 | xlabel(handles(2, 1), 'Time (s)');
82 | ylabel(handles(2, 1), 'Amplitude');
83 | title (handles(2, 1), 'Raw PLL discriminator');
84 |
85 | %----- Correlation ------------------------------------------------
86 | plot(handles(2, 2), timeAxisInSeconds, ...
87 | [sqrt(trackResults(channelNr).I_E.^2 + ...
88 | trackResults(channelNr).Q_E.^2)', ...
89 | sqrt(trackResults(channelNr).I_P.^2 + ...
90 | trackResults(channelNr).Q_P.^2)', ...
91 | sqrt(trackResults(channelNr).I_L.^2 + ...
92 | trackResults(channelNr).Q_L.^2)'], ...
93 | '-*');
94 |
95 | grid (handles(2, 2));
96 | title (handles(2, 2), 'Correlation results');
97 | xlabel(handles(2, 2), 'Time (s)');
98 | axis (handles(2, 2), 'tight');
99 |
100 | hLegend = legend(handles(2, 2), '$\sqrt{I_{E}^2 + Q_{E}^2}$', ...
101 | '$\sqrt{I_{P}^2 + Q_{P}^2}$', ...
102 | '$\sqrt{I_{L}^2 + Q_{L}^2}$');
103 |
104 | %set interpreter from tex to latex. This will draw \sqrt correctly
105 | set(hLegend, 'Interpreter', 'Latex');
106 |
107 | %----- PLL discriminator filtered----------------------------------
108 | plot (handles(3, 1), timeAxisInSeconds, ...
109 | trackResults(channelNr).pllDiscrFilt, 'b');
110 |
111 | grid (handles(3, 1));
112 | axis (handles(3, 1), 'tight');
113 | xlabel(handles(3, 1), 'Time (s)');
114 | ylabel(handles(3, 1), 'Amplitude');
115 | title (handles(3, 1), 'Filtered PLL discriminator');
116 |
117 | %----- DLL discriminator unfiltered--------------------------------
118 | plot (handles(3, 2), timeAxisInSeconds, ...
119 | trackResults(channelNr).dllDiscr, 'r');
120 |
121 | grid (handles(3, 2));
122 | axis (handles(3, 2), 'tight');
123 | xlabel(handles(3, 2), 'Time (s)');
124 | ylabel(handles(3, 2), 'Amplitude');
125 | title (handles(3, 2), 'Raw DLL discriminator');
126 |
127 | %----- DLL discriminator filtered----------------------------------
128 | plot (handles(3, 3), timeAxisInSeconds, ...
129 | trackResults(channelNr).dllDiscrFilt, 'b');
130 |
131 | grid (handles(3, 3));
132 | axis (handles(3, 3), 'tight');
133 | xlabel(handles(3, 3), 'Time (s)');
134 | ylabel(handles(3, 3), 'Amplitude');
135 | title (handles(3, 3), 'Filtered DLL discriminator');
136 |
137 | end % for channelNr = channelList
138 |
--------------------------------------------------------------------------------
/plots/probe_data.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function probe_data(varargin)
10 |
11 |
12 | %%% Check the number of arguments
13 | if (nargin == 1)
14 | settings = deal(varargin{1});
15 | fileNameStr = settings.fileName;
16 | elseif (nargin == 2)
17 | [fileNameStr, settings] = deal(varargin{1:2});
18 | if ~ischar(fileNameStr)
19 | error('File name must be a string');
20 | end
21 | else
22 | error('Incorect number of arguments');
23 | end
24 |
25 | %%% Generate plot of raw data
26 | [fid, message] = fopen(fileNameStr, 'rb');
27 | settings.fileID = fid;
28 | if (fid > 0)
29 | % Move the starting point of processing. Can be used to start the
30 | % signal processing at any point in the data record (e.g. for long
31 | % records).
32 | %fseek(fid, settings.skipNumberOfBytes, 'bof');
33 | fseek(fid,0, 'bof');
34 |
35 | % Read 10ms of signal
36 | [tmpdata, count] = fread(fid, [1, 10*settings.samplesPerCode], settings.dataType);
37 | fclose(fid);
38 |
39 | % convert the signal to symbols from bits
40 | % TODO: this moves to pre-processing for
41 |
42 | channelNum = 4;
43 | numChannels = 4;
44 | tmpdata = int32(tmpdata(channelNum:numChannels:end));
45 | data = double(1 + 2 * idivide(tmpdata, 2) .* (1 - 2 * mod(tmpdata, 2)));
46 |
47 | if (count < 10*settings.samplesPerCode)
48 | % The file is to short
49 | error('Could not read enough data from the data file.');
50 | end
51 |
52 | %%% Initialization
53 | figure(100);
54 | clf(100);
55 | timeScale = 0 : 1/settings.samplingFreq : 5e-3;
56 |
57 | %%% Time domain plot
58 | subplot(2, 2, 1); plot(1000 * timeScale(1:round(settings.samplesPerCode/50)), ...
59 | data(1:round(settings.samplesPerCode/50)));
60 | axis tight; grid on;
61 | title ('Time domain plot');
62 | xlabel('Time (ms)');
63 | ylabel('Amplitude');
64 | ylim([-5 5])
65 |
66 | %%% Frequency domain plot
67 | subplot(2,2,2); pwelch(data-mean(data), 16384, ...
68 | 1024, 2048, settings.samplingFreq/1e6,'centered');
69 |
70 | axis tight; grid on;
71 | title ('Frequency domain plot');
72 | xlabel('Frequency (MHz)'); ylabel('Magnitude');
73 |
74 | %%% Histogram
75 | subplot(2, 2, 3.5); hist(data, -128:128)
76 | dmax = max(abs(data)) + 1;
77 | axis tight;
78 | adata = axis;
79 | axis([-dmax dmax adata(3) adata(4)]);
80 | grid on;
81 | title ('Histogram');
82 | xlabel('Bin'); ylabel('Number in bin');
83 | else
84 | %%% Error while opening the data file
85 | error('Unable to read file %s: %s.', fileNameStr, message);
86 | end % if (fid > 0)
87 |
--------------------------------------------------------------------------------
/plots/save_acquisition_results.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function save_acquisition_results(sdrParams, postProcessResults)
10 | %%%
11 |
12 | %%% Extract coherent frame data.
13 | currFileNum = sdrParams.stateParams.numFilesProcessed + 1;
14 | fileName = sdrParams.stateParams.fileNames{currFileNum};
15 | dataParams = sdrParams.dataFileParamsList{currFileNum};
16 |
17 | channelId = 1;
18 | if dataParams.selectedChannel ~= -1
19 | numChannels = 1;
20 | channelId = dataParams.selectedChannel;
21 | else
22 | numChannels = dataParams.totalChannels;
23 | channelId = 1:dataParams.totalChannels;
24 | end
25 |
26 | acqAlgoList = sdrParams.sysParams.acqAlgosList;
27 | numAcqAlgos = length(acqAlgoList);
28 |
29 | print_string('====Displaying Acquisition Results: Start====');
30 | for chIdx=1:numChannels
31 | for acqAlgoIdx=1:numAcqAlgos
32 | print_string(sprintf('(File: %s, Channel: %d, Algorithm: %s)', ...
33 | fileName, chIdx, acqAlgoList{acqAlgoIdx}));
34 |
35 | acqResults = postProcessResults.acqResults{chIdx, acqAlgoIdx}.acqResults;
36 | if ~isempty(acqResults)
37 |
38 | chAlgoAcqResults = acqResults.chAlgoAcqResults;
39 |
40 | %%% Save
41 | sFileName = sprintf('file_%s_ch_%d_frame_%d_algo_%s_%s.mat', ...
42 | fileName(1:end-4),...
43 | chIdx,...
44 | sdrParams.stateParams.currFrameNum+1, ...
45 | acqAlgoList{acqAlgoIdx},...
46 | datestr(now, 'yyyy-mm-dd-HH-MM-SS'));
47 |
48 | % clean dir
49 |
50 | if currFileNum == 1 && ...
51 | chIdx == 1 && ...
52 | sdrParams.stateParams.currFrameNum == 0 &&...
53 | acqAlgoIdx == 1
54 |
55 |
56 | % Check to make sure that folder actually exists. Warn user if it doesn't.
57 | if ~isdir(sdrParams.stateParams.dataPathOut)
58 | errorMessage = sprintf('Error: The following folder does not exist:\n%s', ...
59 | sdrParams.stateParams.dataPathOut);
60 | uiwait(warndlg(errorMessage));
61 | return;
62 | end
63 | % Get a list of all files in the folder with the desired file name pattern.
64 | filePattern = fullfile(sdrParams.stateParams.dataPathOut, '*.*');
65 | theFiles = dir(filePattern);
66 | for k = 3 : length(theFiles)
67 | baseFileName = theFiles(k).name;
68 | fullFileName = fullfile(sdrParams.stateParams.dataPathOut, baseFileName);
69 | print_string(sprintf('Now deleting %s', fullFileName));
70 | delete(fullFileName);
71 | end
72 | end
73 | % save
74 | save([sdrParams.stateParams.dataPathOut, sFileName], 'acqResults');
75 |
76 |
77 |
78 | %%% Dump to console
79 | for prn=1:length(chAlgoAcqResults)
80 | print_string(sprintf('(PRN: %3d, Acq_Metric: %8s, Code: %5d, Frequency: %s)', ...
81 | chAlgoAcqResults{prn}.satellitePrn,...
82 | num2str(chAlgoAcqResults{prn}.peakMetric),...
83 | chAlgoAcqResults{prn}.codeDelay,...
84 | num2str(chAlgoAcqResults{prn}.dopplerShiftHz)));
85 | end
86 | else
87 | print_string('No satellites found.');
88 | end
89 | end
90 | end
91 | print_string('====Displaying Acquisition Results: End====');
92 | end
93 |
--------------------------------------------------------------------------------
/post_processing/post_process.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function [ postProcessResuts ] = post_process(sdrParams, rxData, ...
10 | processing_results...
11 | )
12 | % SUMMARY Post processes correlation for 1 frame of coherent processing interval.
13 | % This function receives processing results for configured number of
14 | % satellites for 1 coherent processing interval and converts correlation
15 | % delay doppler profile to code delay and doppler shift parameters as well
16 | % as refines them through advanced signal processing techniques. It stores
17 | % results for one incoheren processing interval frame and then outputs them
18 | % either to plotting functions or dumps to files.
19 |
20 | postProcessResuts = struct();
21 |
22 | currFileNum = sdrParams.stateParams.numFilesProcessed+1;
23 | dataFileParams = sdrParams.dataFileParamsList{currFileNum};
24 | numChannels = dataFileParams.totalChannels;
25 | selectedChannel = dataFileParams.selectedChannel;
26 | acqAlgos = sdrParams.sysParams.acqAlgosList;
27 | numAcqAlgos = length(acqAlgos);
28 |
29 | if selectedChannel ~= -1
30 | numChannels = 1;
31 | end
32 |
33 | %%% Define buffer for incoherent integration for all data channels
34 | % and all acquisition algorithms types.
35 |
36 | persistent ddMapBuffer;
37 | if isempty(ddMapBuffer)
38 | ddMapBuffer = cell(numChannels, numAcqAlgos);
39 | end
40 |
41 | % Define data buffer here that are static
42 | acqResults = cell(numChannels, numAcqAlgos);
43 |
44 |
45 | for chIdx = 1:numChannels
46 | for algoIdx = 1:numAcqAlgos
47 |
48 | %%% Add the delay doppler map for multiple incoherent integration
49 | % intervals.
50 |
51 | if isempty(ddMapBuffer) || ...
52 | sdrParams.stateParams.currFrameNum == 0
53 | ddMapBuffer{chIdx, algoIdx}.ddMapBuffer = processing_results{chIdx, algoIdx}.ddMap;
54 | else
55 | ddMapBuffer{chIdx, algoIdx}.ddMapBuffer = ddMapBuffer{chIdx, algoIdx}.ddMapBuffer + ...
56 | processing_results{chIdx, algoIdx}.ddMap;
57 | end
58 |
59 |
60 | print_string(sprintf('Post processing for frame: %d/%d, channel: %d/%d, algorithm: %s', ...
61 | sdrParams.stateParams.currFrameNum+1, ...
62 | sdrParams.stateParams.numTotalFrames, ...
63 | chIdx, ...
64 | numChannels, ...
65 | acqAlgos{algoIdx}...
66 | ));
67 |
68 |
69 | %%% Do post-processing for each algorithm.
70 | switch(acqAlgos{algoIdx})
71 | case 'norm_acq_parcode'
72 | chAlgoAcqResults = post_process_norm_acq_parcode(...
73 | sdrParams, ...
74 | dataFileParams, ...
75 | processing_results{chIdx, algoIdx}, ...
76 | rxData{chIdx}, ...
77 | ddMapBuffer{chIdx, algoIdx}.ddMapBuffer...
78 | );
79 | case 'weak_acq_dbzp'
80 | chAlgoAcqResults = post_process_weak_acq_dbzp( ...
81 | sdrParams, ...
82 | dataFileParams, ...
83 | processing_results{chIdx, algoIdx}, ...
84 | rxData{chIdx}, ...
85 | ddMapBuffer{chIdx, algoIdx}.ddMapBuffer...
86 | );
87 | otherwise
88 | error('Acquisition algorithm not identified.');
89 | end
90 |
91 | acqResults{chIdx, algoIdx}.acqResults = chAlgoAcqResults;
92 | end
93 |
94 | % Save results as well as spit out.
95 |
96 | end
97 |
98 |
99 | %%% visualizations of different algorithms
100 | % plot_acquisition(acqResults);
101 | postProcessResuts.acqResults = acqResults;
102 |
103 | end
104 |
--------------------------------------------------------------------------------
/post_processing/post_process_norm_acq_parcode.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function acqResults = post_process_norm_acq_parcode(...
10 | sdrParams, ...
11 | dataFileParams, ...
12 | processing_results, ...
13 | rxData, ...
14 | delayDopplerMapAcq...
15 | )
16 |
17 | %%% Get Parameters from results.
18 | averFactor = processing_results.averFactor;
19 | numCodeSamples = processing_results.numCodeSamples;
20 | numDopplerSamples = processing_results.numDopplerBins;
21 | dopplerResHz = processing_results.dopplerResHz;
22 |
23 | satelliteList = sdrParams.sysParams.acqSatelliteList;
24 | maxNumAcqSatellites = sdrParams.sysParams.numAcqSatellites;
25 | numPrns = length(satelliteList);
26 |
27 | chipRateHz = sdrParams.sysParams.caCodeChipRateHz;
28 | numChipsPerMs = floor(chipRateHz * 1e-3);
29 |
30 | if size(delayDopplerMapAcq, 1) ~= length(satelliteList)
31 | error('The number of returned correlation maps does not equal number of satellites.');
32 | end
33 |
34 | %%% Find coarse results
35 |
36 | peakValueList = zeros(1, numPrns);
37 | peakMetricList = zeros(1, numPrns);
38 | peakLocList = zeros(1, numPrns);
39 |
40 | excludeBinRangePeakAtZero = [10:floor(numCodeSamples/averFactor)-10];
41 |
42 | % Check if a satellite should be acquired
43 | % if its peak metric is greater than threshold.
44 |
45 | for prnIdx = 1:numPrns
46 | delayDopplerMapAcqPrn = squeeze(delayDopplerMapAcq(prnIdx, :, :));
47 | [peakValue, peakLoc] = max(delayDopplerMapAcqPrn(:));
48 |
49 | if length(peakValue) > 1
50 | peakValue = peakValue(1);
51 | peakLoc = peakLoc(1);
52 | end
53 |
54 | % Calculate peak metric for all satellite signals
55 | dopplerShiftInt = mod(peakLoc-1, numDopplerSamples)+1;
56 | codeDelay = floor(peakLoc/numDopplerSamples);
57 | excludeBinRange = mod(excludeBinRangePeakAtZero + codeDelay+1,...
58 | numCodeSamples/averFactor)+1;
59 | nonPeakCorrProfile = delayDopplerMapAcqPrn(dopplerShiftInt, excludeBinRange);
60 | secondMaxPeak = max(nonPeakCorrProfile);
61 | peakMetric = peakValue/secondMaxPeak;
62 |
63 | % Fill in the list of peak Metric, peak value and locations.
64 | peakLocList(:, prnIdx) = peakLoc;
65 | peakValueList(:, prnIdx) = peakValue;
66 | peakMetricList(:, prnIdx) = peakMetric;
67 | end
68 |
69 | % Identify acquired and non-acquired satellites.
70 | acqPrnIdx = (peakMetricList>sdrParams.sysParams.acqThreshold);
71 | nacqPrnIdx = ~acqPrnIdx;
72 |
73 | aPrnList = satelliteList(acqPrnIdx);
74 | aprnLocList = peakLocList(acqPrnIdx);
75 | aprnPeakMetricList = peakMetricList(acqPrnIdx);
76 |
77 | nonAcqPeakMetricList = peakMetricList(nacqPrnIdx);
78 | naprnList = satelliteList(nacqPrnIdx);
79 |
80 | acqPrnCount = length(aPrnList);
81 |
82 | %%% Refine results for acquired PRNs
83 | acqResults = struct([]);
84 |
85 | if acqPrnCount
86 |
87 | % if acquired satellites are greater than required, choose strongest.
88 | if acqPrnCount > maxNumAcqSatellites
89 |
90 | % Sort the acquired satellite signals according to peak strength
91 | [sortedAprnPeakMetricList, ~] = ...
92 | sort(aprnPeakMetricList, 'descend');
93 |
94 | acqPrnIdx = ismember(aprnPeakMetricList, ...
95 | sortedAprnPeakMetricList(1:maxNumAcqSatellites));
96 | nacqPrnIdx = ~acqPrnIdx;
97 |
98 | % Choose maxNumAcqSatellites
99 |
100 | nonAcqPeakMetricList = [nonAcqPeakMetricList, aprnPeakMetricList(nacqPrnIdx)];
101 | naprnList = [naprnList, aPrnList(nacqPrnIdx)];
102 |
103 | aPrnList = aPrnList(acqPrnIdx);
104 | aprnLocList = aprnLocList(acqPrnIdx);
105 | aprnPeakMetricList = aprnPeakMetricList(acqPrnIdx);
106 |
107 |
108 | acqPrnCount = maxNumAcqSatellites;
109 | end
110 |
111 | print_string([num2str(acqPrnCount), ' satellites acquired for ', ...
112 | num2str(sdrParams.stateParams.currFrameNum+1),...
113 | '/', num2str(sdrParams.stateParams.numTotalFrames), '.']);
114 |
115 | % Resize if size is not ok.
116 | chAlgoAcqResults = cell(1, acqPrnCount);
117 | for aprnIdx = 1:acqPrnCount
118 |
119 | prnIdx = aPrnList(aprnIdx);
120 | location = aprnLocList(aprnIdx);
121 |
122 | % Coarse code and doppler delay.
123 |
124 | dopplerShiftInt = mod(location-1, numDopplerSamples)+1;
125 | codeDelay = floor(location/numDopplerSamples);
126 | dopplerSpectrum = squeeze(delayDopplerMapAcq(prnIdx, 1:numDopplerSamples, codeDelay+1));
127 |
128 |
129 | % First perform fine frequency estimation using quadratic
130 | % interpolation
131 |
132 | maxValArrIdx = mod(dopplerShiftInt-2:dopplerShiftInt, numDopplerSamples) + 1;
133 | maxValArr = sqrt(dopplerSpectrum(maxValArrIdx));
134 | doppleShiftError = 0.5*(maxValArr(1) - maxValArr(3)) / ...
135 | (maxValArr(1) - 2*maxValArr(2)+maxValArr(3));
136 | dopplerShiftInt = dopplerShiftInt - floor(numDopplerSamples/2)-1;
137 | dopplerShiftHz = (dopplerShiftInt + doppleShiftError) * dopplerResHz;
138 | dopplerShiftAxis = ((0:numDopplerSamples-1) - floor(numDopplerSamples/2))* dopplerResHz;
139 |
140 | % Refine code delay results.
141 | ifFreqEst = dataFileParams.intermFreqHz + dopplerShiftHz;
142 |
143 | dopplerShiftHz = 0;
144 | codeDelayError = 0;
145 | dataIdx = (codeDelay*averFactor+1):(codeDelay*averFactor+1)+numCodeSamples-1;
146 |
147 | if dataIdx(end) <= length(rxData)
148 |
149 | dopplerFreqExp = exp(2i * pi * ifFreqEst * ...
150 | (0:numCodeSamples-1)/(dataFileParams.samplingFreqHz));
151 |
152 | rxDataMs = rxData(dataIdx) .* dopplerFreqExp;
153 |
154 | caCodeMappingInd = floor((0:numCodeSamples-1)*(chipRateHz / dataFileParams.samplingFreqHz)) + 1;
155 | caCodeMappingInd(caCodeMappingInd == 0) = 1;
156 | caCodeMappingInd(caCodeMappingInd > numChipsPerMs) = numChipsPerMs;
157 | caCode = gen_ca_code(sdrParams.stateParams.dataPathIn, prnIdx);
158 | caCode = caCode(caCodeMappingInd);
159 |
160 | [corrOut, lags] = xcorr(rxDataMs, caCode, ceil(averFactor/2));
161 | [~, maxIdx] = max(abs(corrOut));
162 | if length(maxIdx) > 1
163 | maxIdx = maxIdx(1);
164 | end
165 | codeDelayError = lags(maxIdx);
166 |
167 | % Refine doppler frequency agains.
168 |
169 | rxDataMs = rxData(dataIdx) .* caCode;
170 | rxDataMs = rxDataMs .* dopplerFreqExp;
171 |
172 | acqDopplerBW = sdrParams.sysParams.acqDopplerBwKhz * 1e3;
173 | fftNumPts = 8*2^(nextpow2(length(rxDataMs)));
174 | deltaF = dataFileParams.samplingFreqHz/fftNumPts;
175 | pbins = ceil(0.5 * acqDopplerBW / deltaF);
176 | faxis = 0.5*fftNumPts-pbins:pbins+0.5*fftNumPts;
177 | fftFreqBins = (faxis - floor(0.5*fftNumPts)-1) * deltaF;
178 |
179 | fftxc = abs(fftshift(fft(rxDataMs, fftNumPts)));
180 | fftxc = fftxc(faxis);
181 | [~, fftMaxIndex] = max(fftxc);
182 |
183 | maxValArrIdx = fftMaxIndex-1:fftMaxIndex+1;
184 | maxValArr = sqrt(fftxc(maxValArrIdx));
185 |
186 | % Apply quadratic interpolation again.
187 |
188 | doppleShiftError1 = 0.5*(maxValArr(1) - maxValArr(3)) / ...
189 | (maxValArr(1) - 2*maxValArr(2)+maxValArr(3));
190 | dopplerShiftHz = fftFreqBins(fftMaxIndex) + doppleShiftError1*deltaF;
191 |
192 | end
193 |
194 | codeDelay = codeDelayError + codeDelay * averFactor + 1;
195 | ifFreqEst = ifFreqEst - dopplerShiftHz;
196 |
197 | % Save results per PRN
198 | chAlgoAcqResults{aprnIdx}.dopplerShiftHz = dopplerShiftHz;
199 | chAlgoAcqResults{aprnIdx}.codeDelay = codeDelay;
200 | chAlgoAcqResults{aprnIdx}.peakMetric = aprnPeakMetricList(aprnIdx);
201 | chAlgoAcqResults{aprnIdx}.dopplerShiftHz = ifFreqEst;
202 | chAlgoAcqResults{aprnIdx}.satellitePrn = prnIdx;
203 | chAlgoAcqResults{aprnIdx}.ddm = squeeze(delayDopplerMapAcq(prnIdx, :, :));
204 | chAlgoAcqResults{aprnIdx}.dopplerShiftAxis=dopplerShiftAxis;
205 | chAlgoAcqResults{aprnIdx}.codeDelayAxis = 0:averFactor:numCodeSamples-1;
206 |
207 | end
208 |
209 | acqResults(1).chAlgoAcqResults = chAlgoAcqResults;
210 | acqResults(1).nacqStats.nacqPrnList = naprnList;
211 | acqResults(1).nacqStats.nacqPrnPeakMetric = nonAcqPeakMetricList;
212 | end
213 | end
214 |
--------------------------------------------------------------------------------
/post_processing/post_processing.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | % Script postProcessing.m processes the raw signal from the specified data
10 | % file (in settings) operating on blocks of 37 seconds of data.
11 | %
12 | % First it runs acquisition code identifying the satellites in the file,
13 | % then the code and carrier for each of the satellites are tracked, storing
14 | % the 1msec accumulations. After processing all satellites in the 37 sec
15 | % data block, then postNavigation is called. It calculates pseudoranges
16 | % and attempts a position solutions. At the end plots are made for that
17 | % block of data.
18 |
19 | % THE SCRIPT "RECIPE"
20 | %
21 | % The purpose of this script is to combine all parts of the software
22 | % receiver.
23 | %
24 | % 1.1) Open the data file for the processing and seek to desired point.
25 | %
26 | % 2.1) Acquire satellites
27 | %
28 | % 3.1) Initialize channels (preRun.m).
29 | % 3.2) Pass the channel structure and the file identifier to the tracking
30 | % function. It will read and process the data. The tracking results are
31 | % stored in the trackResults structure. The results can be accessed this
32 | % way (the results are stored each millisecond):
33 | % trackResults(channelNumber).XXX(fromMillisecond : toMillisecond), where
34 | % XXX is a field name of the result (e.g. I_P, codePhase etc.)
35 | %
36 | % 4) Pass tracking results to the navigation solution function. It will
37 | % decode navigation messages, find satellite positions, measure
38 | % pseudoranges and find receiver position.
39 | %
40 | % 5) Plot the results.
41 | %% Initialization =========================================================
42 | disp ('Starting processing...');
43 |
44 | [fid, message] = fopen(settings.fileName, 'rb', 'ieee-le');
45 |
46 | %If success, then process the data
47 | if (fid > 0)
48 |
49 | % Move the starting point of processing. Can be used to start the
50 | % signal processing at any point in the data record (e.g. good for long
51 | % records or for signal processing in blocks).
52 | fseek(fid, settings.skipNumberOfBytes, 'bof');
53 | % Do acquisition if it is not disabled in settings or if the variable
54 | % acqResults does not exist.
55 |
56 | if ((settings.skipAcquisition == 0) || ~exist('acqResults', 'var'))
57 |
58 | % Read data for acquisition.
59 | fseek(fid, settings.skipNumberOfBytes, 'bof');
60 | tmpdata = fread(fid, settings.dataExtractLen, settings.dataType)';
61 |
62 | tmpdata(tmpdata==1) = -1;
63 | tmpdata(tmpdata==3) = -3;
64 | tmpdata(tmpdata==0) = 1;
65 | tmpdata(tmpdata==2) = 3;
66 |
67 | L = floor((length(tmpdata)/4));
68 |
69 | Data4I = double(tmpdata(1:4:4*(L)));
70 | Data3I = double(tmpdata(2:4:4*(L)));
71 | Data2I = double(tmpdata(3:4:4*(L)));
72 | Data1I = double(tmpdata(4:4:4*(L)));
73 |
74 | data = Data1I;
75 |
76 | if settings.modulationRequired
77 | dataLen = settings.dataExtractLen / 2;
78 | phasePoints = 2 * pi * settings.IF / settings.samplingFreq * (0 : dataLen-1);
79 | data = data(1:2:end) .* cos(phasePoints) - data(2:2:end) .* sin(phasePoints);
80 | elseif settings.demodulationRequired
81 | phasePoints = (0 : settings.dataExtractLen/4-1) * 2 * pi * settings.IF / settings.samplingFreq;
82 | data = data .* cos(phasePoints) + 1i * data .* sin(phasePoints);
83 | end
84 |
85 | disp (' Acquiring satellites...');
86 |
87 | if isequal(settings.acquisitionType, 'normalAcquisition')
88 | acqResults = acquisition(data, settings);
89 | elseif isequal(settings.acquisitionType, 'weakAcquisition')
90 | acqResults = weak_acquisition(data, settings);
91 | elseif isequal(settings.acquisitionType, 'halfBitAcquisition')
92 | acqResults = half_bit_acquisition(data, settings, settings.dataExtractLen);
93 | end
94 |
95 | end
96 | plotAcquisition(acqResults);
97 |
98 | %% Initialize channels and prepare for the run ============================
99 |
100 | % Start further processing only if a GNSS signal was acquired (the
101 | % field FREQUENCY will be set to 0 for all not acquired signals)
102 | if (any(acqResults.carrFreq))
103 | channel = preRun(acqResults, settings);
104 | showChannelStatus(channel, settings);
105 | else
106 | % No satellites to track, exit
107 | disp('No GNSS signals detected, signal processing finished.');
108 | trackResults = [];
109 | return;
110 | end
111 |
112 | %% Track the signal =======================================================
113 | startTime = now;
114 | disp ([' Tracking started at ', datestr(startTime)]);
115 |
116 | % Process all channels for given data block
117 | % [trackResults, channel] = tracking(fid, channel, settings);
118 |
119 | % Close the data file
120 | % fclose(fid);
121 | disp([' Tracking is over (elapsed time ', datestr(now - startTime, 13), ')'])
122 |
123 | % Auto save the acquisition & tracking results to a file to allow
124 | % running the positioning solution afterwards.
125 | % disp(' Saving Acq & Tracking results to file "trackingResults.mat"')
126 | % [filepath, name, ext]=fileparts(settings.fileName);
127 | % save(fullfile('.','..','..', [name, '_mat.mat']), 'trackResults', 'settings', 'acqResults', 'channel');
128 |
129 | %% Calculate navigation solutions =========================================
130 | % disp(' Calculating navigation solutions...');
131 | % navSolutions = postNavigation(trackResults, settings);
132 | %
133 | % disp(' Processing is complete for this data block');
134 | %
135 | % %% Plot all results ===================================================
136 | % disp (' Ploting results...');
137 | % if settings.plotTracking
138 | % plotTracking(1:settings.numberOfChannels, trackResults, settings);
139 | % end
140 |
141 | % plotNavigation(navSolutions, settings);
142 |
143 | disp('Post processing of the signal is over.');
144 |
145 | else
146 | % Error while opening the data file.
147 | error('Unable to read file %s: %s.', settings.fileName, message);
148 | end % if (fid > 0)
149 |
--------------------------------------------------------------------------------
/pre_processing/calc_pseudo_ranges.m:
--------------------------------------------------------------------------------
1 | function [pseudoranges] = calc_pseudo_ranges(trackResults, ...
2 | msOfTheSignal, ...
3 | channelList, settings)
4 | %calculatePseudoranges finds relative pseudoranges for all satellites
5 | %listed in CHANNELLIST at the specified millisecond of the processed
6 | %signal. The pseudoranges contain unknown receiver clock offset. It can be
7 | %found by the least squares position search procedure.
8 | %
9 | %[pseudoranges] = calculatePseudoranges(trackResults, msOfTheSignal, ...
10 | % channelList, settings)
11 | %
12 | % Inputs:
13 | % trackResults - output from the tracking function
14 | % msOfTheSignal - pseudorange measurement point (millisecond) in
15 | % the trackResults structure
16 | % channelList - list of channels to be processed
17 | % settings - receiver settings
18 | %
19 | % Outputs:
20 | % pseudoranges - relative pseudoranges to the satellites.
21 |
22 | %--------------------------------------------------------------------------
23 | % SoftGNSS v3.0
24 | %
25 | % Copyright (C) Darius Plausinaitis
26 | % Written by Darius Plausinaitis
27 | % Based on Peter Rinder and Nicolaj Bertelsen
28 | %--------------------------------------------------------------------------
29 | %
30 | %This program is free software; you can redistribute it and/or
31 | %modify it under the terms of the GNU General Public License
32 | %as published by the Free Software Foundation; either version 2
33 | %of the License, or (at your option) any later version.
34 | %
35 | %This program is distributed in the hope that it will be useful,
36 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
37 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 | %GNU General Public License for more details.
39 | %
40 | %You should have received a copy of the GNU General Public License
41 | %along with this program; if not, write to the Free Software
42 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
43 | %USA.
44 | %--------------------------------------------------------------------------
45 |
46 | % CVS record:
47 | % $Id: calculatePseudoranges.m,v 1.1.2.18 2006/08/09 17:20:11 dpl Exp $
48 |
49 | %--- Set initial travel time to infinity ----------------------------------
50 | % Later in the code a shortest pseudorange will be selected. Therefore
51 | % pseudoranges from non-tracking channels must be the longest - e.g.
52 | % infinite.
53 | travelTime = inf(1, settings.numberOfChannels);
54 |
55 | % Find number of samples per spreading code
56 | samplesPerCode = round(settings.samplingFreq / ...
57 | (settings.codeFreqBasis / settings.codeLength));
58 |
59 | %--- For all channels in the list ...
60 | for channelNr = channelList
61 |
62 | %--- Compute the travel times -----------------------------------------
63 | travelTime(channelNr) = ...
64 | trackResults(channelNr).absoluteSample(msOfTheSignal(channelNr)) / samplesPerCode;
65 | end
66 |
67 | %--- Truncate the travelTime and compute pseudoranges ---------------------
68 | minimum = floor(min(travelTime));
69 | travelTime = travelTime - minimum + settings.startOffset;
70 |
71 | %--- Convert travel time to a distance ------------------------------------
72 | % The speed of light must be converted from meters per second to meters
73 | % per millisecond.
74 | pseudoranges = travelTime * (settings.c / 1000);
75 |
--------------------------------------------------------------------------------
/pre_processing/ddm_processing.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | % Script postProcessing.m processes the raw signal from the specified data
10 | % file (in settings) operating on blocks of 37 seconds of data.
11 | %
12 | % First it runs acquisition code identifying the satellites in the file,
13 | % then the code and carrier for each of the satellites are tracked, storing
14 | % the 1msec accumulations. After processing all satellites in the 37 sec
15 | % data block, then postNavigation is called. It calculates pseudoranges
16 | % and attempts a position solutions. At the end plots are made for that
17 | % block of data.
18 |
19 | % THE SCRIPT "RECIPE"
20 | %
21 | % The purpose of this script is to combine all parts of the software
22 | % receiver.
23 | %
24 | % 1.1) Open the data file for the processing and seek to desired point.
25 | %
26 | % 2.1) Acquire satellites
27 | %
28 | % 3.1) Initialize channels (preRun.m).
29 | % 3.2) Pass the channel structure and the file identifier to the tracking
30 | % function. It will read and process the data. The tracking results are
31 | % stored in the trackResults structure. The results can be accessed this
32 | % way (the results are stored each millisecond):
33 | % trackResults(channelNumber).XXX(fromMillisecond : toMillisecond), where
34 | % XXX is a field name of the result (e.g. I_P, codePhase etc.)
35 | %
36 | % 4) Pass tracking results to the navigation solution function. It will
37 | % decode navigation messages, find satellite positions, measure
38 | % pseudoranges and find receiver position.
39 | %
40 | % 5) Plot the results.
41 |
42 | %% Initialization =========================================================
43 | disp ('Starting processing...');
44 |
45 | [fid, message] = fopen(settings.fileName, 'rb', 'ieee-le');
46 |
47 | %If success, then process the data
48 | if (fid > 0)
49 |
50 | % Move the starting point of processing. Can be used to start the
51 | % signal processing at any point in the data record (e.g. good for long
52 | % records or for signal processing in blocks).
53 | fseek(fid, settings.skipNumberOfBytes, 'bof');
54 | % Do acquisition if it is not disabled in settings or if the variable
55 | % acqResults does not exist.
56 |
57 | if ((settings.skipAcquisition == 0) || ~exist('acqResults', 'var'))
58 |
59 | % Read data for acquisition.
60 | fseek(fid, settings.skipNumberOfBytes, 'bof');
61 | tmpdata = fread(fid, settings.dataExtractLen, settings.dataType)';
62 |
63 | tmpdata(tmpdata==1) = -1;
64 | tmpdata(tmpdata==3) = -3;
65 | tmpdata(tmpdata==0) = 1;
66 | tmpdata(tmpdata==2) = 3;
67 |
68 | L = floor((length(tmpdata)/4));
69 |
70 | Data4I = double(tmpdata(1:4:4*(L)));
71 | Data3I = double(tmpdata(2:4:4*(L)));
72 | Data2I = double(tmpdata(3:4:4*(L)));
73 | Data1I = double(tmpdata(4:4:4*(L)));
74 |
75 | data = Data1I;
76 |
77 | if settings.modulationRequired
78 | dataLen = settings.dataExtractLen / 2;
79 | phasePoints = 2 * pi * settings.IF / settings.samplingFreq * (0 : dataLen-1);
80 | data = data(1:2:end) .* cos(phasePoints) - data(2:2:end) .* sin(phasePoints);
81 | elseif settings.demodulationRequired
82 | phasePoints = (0 : settings.dataExtractLen/4-1) * 2 * pi * settings.IF / settings.samplingFreq;
83 | data = data .* cos(phasePoints) + 1i * data .* sin(phasePoints);
84 | end
85 |
86 | disp (' Acquiring satellites...');
87 |
88 | if isequal(settings.acquisitionType, 'normalAcquisition')
89 | acqResults = acquisition(data, settings);
90 | elseif isequal(settings.acquisitionType, 'weakAcquisition')
91 | acqResults = weak_acquisition(data, settings);
92 | elseif isequal(settings.acquisitionType, 'halfBitAcquisition')
93 | acqResults = half_bit_acquisition(data, settings, settings.dataExtractLen);
94 | end
95 |
96 | end
97 |
98 | plot_acquisition(acqResults);
99 |
100 | %% Initialize channels and prepare for the run ============================
101 | % Start further processing only if a GNSS signal was acquired (the
102 | % field FREQUENCY will be set to 0 for all not acquired signals)
103 | if (any(acqResults.carrFreq))
104 | channel = pre_run(acqResults, settings);
105 | show_channel_status(channel, settings);
106 | else
107 | % No satellites to track, exit
108 | disp('No GNSS signals detected, signal processing finished.');
109 | trackResults = [];
110 | return;
111 | end
112 |
113 | % Close the data file
114 | fclose(fid);
115 | else
116 | % Error while opening the data file.
117 | error('Unable to read file %s: %s.', settings.fileName, message);
118 | end % if (fid > 0)
119 |
--------------------------------------------------------------------------------
/pre_processing/ddm_processing_woodbine.m:
--------------------------------------------------------------------------------
1 | % clear; close all;
2 | format ('compact');
3 | format ('long', 'g');
4 | %--------------------------------------------------------------
5 | addpath include % The software receiver functions
6 | addpath geoFunctions % Position calculation related functions
7 | %--------------------------------------------------------------
8 | GPSL1freq = 1575.42*power(10,6);
9 |
10 | Channel = 1;
11 |
12 | switch Channel
13 | case 1
14 | % NLHCP = load('./../../Woodbine_47a_ch1_1.mat');
15 | SourceFilepath = sprintf('./../../Woodbine_47a_ch1_1.bin');
16 | case 2
17 | NRHCP = load('./../../Woodbine_47a_ch2_1.mat');
18 | SourceFilepath = sprintf('./../../Woodbine_47a_ch2_1.bin');
19 | case 3
20 | ZRHCP = load('./../../Woodbine_cf7_ch1_1.mat');
21 | SourceFilepath = sprintf('./../../Woodbine_cf7_ch1_1.bin');
22 | end
23 |
24 | [~,SourceFilename,ext] = fileparts(SourceFilepath);
25 | settings = initSettings(SourceFilepath);
26 | samplesPerCode = round(settings.samplingFreq/(settings.codeFreqBasis / settings.codeLength));
27 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 | [fid, message] = fopen(settings.fileName, 'r','ieee-le');
29 | fseek(fid, settings.skipNumberOfBytes, 'bof');
30 | [Sample, count] = fread(fid,[1, samplesPerCode*1000*2], settings.dataType);
31 | fclose(fid);
32 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 | I = Sample(1:2:end)/2048;
34 | Q = Sample(2:2:end)/2048;
35 | %--------------------------------------------------------------
36 | ts = 1/settings.samplingFreq; % Sampling period in sec
37 | tc = 1/settings.codeFreqBasis; % C/A chip period in sec
38 | %--------------------------------------------------------------
39 | DelayDopplerMap = zeros(11,21);
40 | DDMcollector = cell(100,32);
41 | SatelliteList = 1:32;
42 | %--------------------------------------------------------------
43 | Delayaxis = -5:1:5;
44 | Doppleraxis = -5000:500:5000;
45 | DDMPhase = (0 : (samplesPerCode-1)) * 2 * pi * ts;
46 |
47 | k=2;
48 | %for k=1:10
49 |
50 | switch Channel
51 | case 1
52 | PRN = SatelliteList(NLHCP.acqResults(k).peakMetric>1.3);
53 | DopplerFreq = NLHCP.acqResults(k).carrFreq(PRN);
54 | Delay = NLHCP.acqResults(k).codePhase(PRN);
55 | case 2
56 | PRN = SatelliteList(NRHCP.acqResults(k).peakMetric>1.3);
57 | DopplerFreq = NRHCP.acqResults(k).carrFreq(PRN);
58 | Delay = NRHCP.acqResults(k).codePhase(PRN);
59 | case 3
60 | PRN = SatelliteList(ZRHCP.acqResults(k).peakMetric>1.3);
61 | DopplerFreq = ZRHCP.acqResults(k).carrFreq(PRN);
62 | Delay = ZRHCP.acqResults(k).codePhase(PRN);
63 | end
64 |
65 | %--------------------------------------------------------------
66 | signal_i = I(samplesPerCode*(k-1)+1:samplesPerCode*k);
67 | signal_q = Q(samplesPerCode*(k-1)+1:samplesPerCode*k);
68 | RecSignal = signal_i+1i*signal_q;
69 | %RecSignal = signal_i-signal_q;
70 | %--------------------------------------------------------------
71 | tmpDDMcollector = cell(1,32);
72 |
73 | for ll = 1:length(PRN)
74 | CAcode = generateCAcode(PRN(ll));
75 | codeValueIndex = ceil((ts * (1:samplesPerCode)) / tc);
76 | codeValueIndex(end) = 1023;
77 | tmpCACodesTable= CAcode(codeValueIndex);
78 |
79 | for ii = 1:length(Delayaxis)
80 | for jj = 1:21
81 | CACodesTable = circshift(tmpCACodesTable,-(Delay(ll)-39*Delayaxis(ii)));
82 | %Y = sum(RecSignal.*CACodesTable.*(cos(DDMPhase.*(DopplerFreq(ll)-Doppleraxis(jj)))+1i*sin(DDMPhase.*(DopplerFreq(ll)-Doppleraxis(jj)))),'omitnan');
83 | YY = sum(RecSignal.*CACodesTable.*(exp(-1i*DDMPhase.*(GPSL1freq+Doppleraxis(jj)))) ,'omitnan');
84 | DelayDopplerMap(ii,jj) = (abs(YY))^2;
85 | end
86 | end
87 |
88 | tmpDDMcollector{PRN(ll)}=DelayDopplerMap;
89 |
90 | end
91 |
92 | DDMcollector(k,:) = tmpDDMcollector;
93 |
94 | fprintf('%d th acquistion results has processed \n',k);
95 | %end
96 |
97 | %save(sprintf('/Volumes/TOSHIBA/bladeRF/200223/1/Results/cf7_ch1/DDM_ZRHCP_1_sub.mat'),'DDMcollector');
98 |
99 | max(max(DDMcollector{2, 3}))
100 |
101 | % figure(1)
102 | % imagesc(Doppleraxis,Delayaxis,DelayDopplerMap)
103 | % xlabel('\DeltaDoppler Frequency')
104 | % ylabel('Delay (chip)')
105 |
--------------------------------------------------------------------------------
/pre_processing/find_preambles.m:
--------------------------------------------------------------------------------
1 | function [firstSubFrame, activeChnList] = find_preambles(trackResults, ...
2 | settings)
3 | % findPreambles finds the first preamble occurrence in the bit stream of
4 | % each channel. The preamble is verified by check of the spacing between
5 | % preambles (6sec) and parity checking of the first two words in a
6 | % subframe. At the same time function returns list of channels, that are in
7 | % tracking state and with valid preambles in the nav data stream.
8 | %
9 | %[firstSubFrame, activeChnList] = findPreambles(trackResults, settings)
10 | %
11 | % Inputs:
12 | % trackResults - output from the tracking function
13 | % settings - Receiver settings.
14 | %
15 | % Outputs:
16 | % firstSubframe - the array contains positions of the first
17 | % preamble in each channel. The position is ms count
18 | % since start of tracking. Corresponding value will
19 | % be set to 0 if no valid preambles were detected in
20 | % the channel.
21 | % activeChnList - list of channels containing valid preambles
22 |
23 | %--------------------------------------------------------------------------
24 | % SoftGNSS v3.0
25 | %
26 | % Copyright (C) Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen
27 | % Written by Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen
28 | %--------------------------------------------------------------------------
29 | %
30 | %This program is free software; you can redistribute it and/or
31 | %modify it under the terms of the GNU General Public License
32 | %as published by the Free Software Foundation; either version 2
33 | %of the License, or (at your option) any later version.
34 | %
35 | %This program is distributed in the hope that it will be useful,
36 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
37 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 | %GNU General Public License for more details.
39 | %
40 | %You should have received a copy of the GNU General Public License
41 | %along with this program; if not, write to the Free Software
42 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
43 | %USA.
44 | %--------------------------------------------------------------------------
45 |
46 | % CVS record:
47 | % $Id: findPreambles.m,v 1.1.2.10 2006/08/14 11:38:22 dpl Exp $
48 |
49 | % Preamble search can be delayed to a later point in the tracking results
50 | % to avoid noise due to tracking loop transients
51 | searchStartOffset = 0;
52 |
53 | %--- Initialize the firstSubFrame array -----------------------------------
54 | firstSubFrame = zeros(1, settings.numberOfChannels);
55 |
56 | %--- Generate the preamble pattern ----------------------------------------
57 | preamble_bits = [1 -1 -1 -1 1 -1 1 1];
58 |
59 | % "Upsample" the preamble - make 20 vales per one bit. The preamble must be
60 | % found with precision of a sample.
61 | preamble_ms = kron(preamble_bits, ones(1, 20));
62 |
63 | %--- Make a list of channels excluding not tracking channels --------------
64 | activeChnList = find([trackResults.status] ~= '-');
65 |
66 | %=== For all tracking channels ...
67 | for channelNr = activeChnList
68 |
69 | %% Correlate tracking output with preamble ================================
70 | % Read output from tracking. It contains the navigation bits. The start
71 | % of record is skiped here to avoid tracking loop transients.
72 | bits = trackResults(channelNr).I_P(1 + searchStartOffset : end);
73 |
74 | % Now threshold the output and convert it to -1 and +1
75 | bits(bits > 0) = 1;
76 | bits(bits <= 0) = -1;
77 |
78 | % Correlate tracking output with the preamble
79 | tlmXcorrResult = xcorr(bits, preamble_ms);
80 |
81 | %% Find all starting points off all preamble like patterns ================
82 | clear index
83 | clear index2
84 |
85 | xcorrLength = (length(tlmXcorrResult) + 1) /2;
86 |
87 | %--- Find at what index/ms the preambles start ------------------------
88 | index = find(...
89 | abs(tlmXcorrResult(xcorrLength : xcorrLength * 2 - 1)) > 153)' + ...
90 | searchStartOffset;
91 |
92 | %% Analyze detected preamble like patterns ================================
93 | for i = 1:size(index) % For each occurrence
94 |
95 | %--- Find distances in time between this occurrence and the rest of
96 | %preambles like patterns. If the distance is 6000 milliseconds (one
97 | %subframe), the do further verifications by validating the parities
98 | %of two GPS words
99 |
100 | index2 = index - index(i);
101 |
102 | if (~isempty(find(index2 == 6000)))
103 |
104 | %=== Re-read bit vales for preamble verification ==============
105 | % Preamble occurrence is verified by checking the parity of
106 | % the first two words in the subframe. Now it is assumed that
107 | % bit boundaries a known. Therefore the bit values over 20ms are
108 | % combined to increase receiver performance for noisy signals.
109 | % in Total 62 bits mast be read :
110 | % 2 bits from previous subframe are needed for parity checking;
111 | % 60 bits for the first two 30bit words (TLM and HOW words).
112 | % The index is pointing at the start of TLM word.
113 | bits = trackResults(channelNr).I_P(index(i)-40 : ...
114 | index(i) + 20 * 60 -1)';
115 |
116 | %--- Combine the 20 values of each bit ------------------------
117 | bits = reshape(bits, 20, (size(bits, 1) / 20));
118 | bits = sum(bits);
119 |
120 | % Now threshold and make it -1 and +1
121 | bits(bits > 0) = 1;
122 | bits(bits <= 0) = -1;
123 |
124 | %--- Check the parity of the TLM and HOW words ----------------
125 | if (navPartyChk(bits(1:32)) ~= 0) && ...
126 | (navPartyChk(bits(31:62)) ~= 0)
127 | % Parity was OK. Record the preamble start position. Skip
128 | % the rest of preamble pattern checking for this channel
129 | % and process next channel.
130 |
131 | firstSubFrame(channelNr) = index(i);
132 | break;
133 | end % if parity is OK ...
134 |
135 | end % if (~isempty(find(index2 == 6000)))
136 | end % for i = 1:size(index)
137 |
138 | % Exclude channel from the active channel list if no valid preamble was
139 | % detected
140 | if firstSubFrame(channelNr) == 0
141 |
142 | % Exclude channel from further processing. It does not contain any
143 | % valid preamble and therefore nothing more can be done for it.
144 | activeChnList = setdiff(activeChnList, channelNr);
145 |
146 | disp(['Could not find valid preambles in channel ', ...
147 | num2str(channelNr),'!']);
148 | end
149 |
150 | end % for channelNr = activeChnList
151 |
--------------------------------------------------------------------------------
/pre_processing/gen_ca_code.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function [ caCode ] = gen_ca_code( filePath, prnList )
10 | %GEN_CA_CODE Returns C/A code for specified PRN list.
11 | % Returns a MxN matrix where each row corresponds to
12 | % a PRN where M is length of input argument list and N
13 | % is equal to the number of chips (1023).
14 | fileName = [filePath, 'caCode.mat'];
15 | genCaCode = true;
16 |
17 | if exist(fileName, 'file') == 2
18 | caCode=load(fileName);
19 | if (length(prnList) == 1 && any(ismember(prnList, caCode.prnList))) || ...
20 | all(caCode.prnList == prnList)
21 | caCode=caCode.caCode(prnList, :);
22 | genCaCode = false;
23 | else
24 | genCaCode = true;
25 | end
26 | end
27 |
28 | if genCaCode
29 |
30 | %--- Make the code shift array. The shift depends on the PRN number -------
31 | % The g2s vector holds the appropriate shift of the g2 code to generate
32 | % the C/A code (ex. for SV#19 - use a G2 shift of g2s(19) = 471)
33 | g2s = [ 5, 6, 7, 8, 17, 18, 139, 140, 141, 251, ...
34 | 252, 254, 255, 256, 257, 258, 469, 470, 471, 472, ...
35 | 473, 474, 509, 512, 513, 514, 515, 516, 859, 860, ...
36 | 861, 862 ... end of shifts for GPS satellites
37 | ... Shifts for the ground GPS transmitter are not included
38 | ... Shifts for EGNOS and WAAS satellites (true_PRN = PRN + 87)
39 | 145, 175, 52, 21, 237, 235, 886, 657, ...
40 | 634, 762, 355, 1012, 176, 603, 130, 359, 595, 68, ...
41 | 386];
42 |
43 |
44 | % Parameters
45 | caCodeLength = 1023;
46 | numPrns = length(prnList);
47 |
48 | % C/A code buffer
49 | caCode = zeros(numPrns, caCodeLength);
50 |
51 | % Iterate over PRN list
52 | for prnIdx = 1:numPrns
53 | prn = prnList(prnIdx);
54 | % Generate all G1 & G2 signal chips
55 | g1 = zeros(1, caCodeLength);
56 | g2 = zeros(1, caCodeLength);
57 | reg1 = -1*ones(1, 10);
58 | reg2 = -1*ones(1, 10);
59 | for i=1:caCodeLength
60 | g1(i) = reg1(10);
61 | g2(i) = reg2(10);
62 | saveBitG1 = reg1(3)*reg1(10);
63 | saveBitG2 = reg2(2)*reg2(3)*reg2(6)*reg2(8)*reg2(9)*reg2(10);
64 | reg1 = circshift(reg1, 1);
65 | reg2 = circshift(reg2, 1);
66 | reg1(1) = saveBitG1;
67 | reg2(1) = saveBitG2;
68 | end
69 |
70 | % Form single sample C/A code by multiplying G1 and G2
71 | g2shift = g2s(prn);
72 | caCode(prnIdx, :) = -(g1 .* circshift(g2, g2shift));
73 | end
74 | save(fileName, 'caCode', 'prnList');
75 |
76 | end
77 | end
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/pre_processing/pre_proc_norm_acq_parcode.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function pprocSignals = pre_proc_norm_acq_parcode(sdrParams, caCode)
10 |
11 | optimizeOption = 2; % 2 for double efficiency
12 | if optimizeOption ~= 1 && optimizeOption ~= 2
13 | error('Only two optimization options are available for parallel code search algorithm.');
14 | end
15 |
16 | %%% Parameters
17 | fileNum = sdrParams.stateParams.numFilesProcessed + 1;
18 | samplingFreqHz = sdrParams.dataFileParamsList{fileNum}.samplingFreqHz;
19 | intermFreqHz = sdrParams.dataFileParamsList{fileNum}.intermFreqHz;
20 | chipRateHz = sdrParams.sysParams.caCodeChipRateHz;
21 | acqDopplerBwKhz = sdrParams.sysParams.acqDopplerBwKhz;
22 | acqDopplerResHz = sdrParams.sysParams.acqDopplerResHz;
23 |
24 | samplesPerMs = samplingFreqHz * 1e-3;
25 | numChipsPerMs = chipRateHz * 1e-3;
26 | prnList = sdrParams.sysParams.acqSatelliteList;
27 |
28 | if floor(samplesPerMs) ~= samplesPerMs
29 | error('Number of samples per millisecond can''t have decimal point.');
30 | end
31 |
32 | % Prepare per algorithm per block common signals
33 |
34 | %%% Determine maximum extent to which averaging can be done
35 | averFactor = [1];
36 | temAverFactor = 1;
37 | while samplingFreqHz/temAverFactor > sdrParams.sysParams.minSamplingFreqHz
38 | temAverFactor=temAverFactor+1;
39 | goodAverFactor = samplesPerMs/temAverFactor;
40 | if floor(goodAverFactor) == goodAverFactor
41 | averFactor = [averFactor, temAverFactor];
42 | end
43 | end
44 |
45 | averFactor = averFactor(end);
46 |
47 | %%% each PRN C/A code sequence frequency transform here.
48 | caCodeMappingInd = floor((0:samplesPerMs/averFactor-1) * ...
49 | (chipRateHz *averFactor/ samplingFreqHz)) + 1;
50 |
51 | caCodeMappingInd(caCodeMappingInd == 0) = 1;
52 | caCodeMappingInd(caCodeMappingInd > numChipsPerMs) = numChipsPerMs;
53 | caCodesTable = caCode(:, caCodeMappingInd);
54 | caCodesTable = conj(fft(caCodesTable, [], 2));
55 |
56 |
57 | % Prepare baseband doppler modulated matrix of data
58 | if optimizeOption == 1
59 | numDopplerSamples = floor(acqDopplerBwKhz * 1e3 / acqDopplerResHz) + 1;
60 | intermFreqVec = intermFreqHz;
61 | dopplerFreqVec = acqDopplerResHz*(0:numDopplerSamples-1);
62 | dopplerFreqVec = dopplerFreqVec - median(dopplerFreqVec); % make it two sided
63 | iFfreqVec = intermFreqVec + dopplerFreqVec;
64 | dopplerFreqExp = exp(2i * pi * iFfreqVec' * (0:samplesPerMs-1)...
65 | /(samplingFreqHz));
66 |
67 | pprocSignals.dopplerFreqExp = dopplerFreqExp;
68 | pprocSignals.dopplerResHz = acqDopplerResHz;
69 |
70 | elseif optimizeOption == 2
71 |
72 | % In this method, frequency shift is integer in terms of 1/1ms=1khz
73 | acqDopplerResHz = 1e3; % 1/0.001 for time duration of 1 millisecond
74 | numDopplerSamples = floor(acqDopplerBwKhz * 1e3 / acqDopplerResHz) + 1;
75 | iFfreqVec = intermFreqHz - acqDopplerBwKhz * 0.5e3;
76 | dopplerFreqInitExp = exp(2i * pi * iFfreqVec * (0:samplesPerMs-1)...
77 | /(samplingFreqHz));
78 | dopplerFreqDeltaExp = exp(2i * pi * acqDopplerResHz * (0:samplesPerMs-1)...
79 | /(samplingFreqHz));
80 |
81 | pprocSignals.shiftFactor = acqDopplerResHz * samplesPerMs / ...
82 | samplingFreqHz;
83 | pprocSignals.dopplerFreqInitExp = dopplerFreqInitExp;
84 | pprocSignals.dopplerFreqDeltaExp = dopplerFreqDeltaExp;
85 | pprocSignals.numDopplerSamples = numDopplerSamples;
86 | pprocSignals.dopplerResHz = acqDopplerResHz;
87 |
88 | end
89 |
90 | pprocSignals.caCodesTable = caCodesTable;
91 | pprocSignals.averFactor = averFactor;
92 | pprocSignals.optimizeOption = optimizeOption;
93 |
94 |
95 | end
96 |
--------------------------------------------------------------------------------
/pre_processing/pre_proc_weak_acq_dbzp.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function pprocSignals = pre_proc_weak_acq_dbzp(sdrParams, caCode)
10 |
11 | %%% Parameters
12 | fileNum = sdrParams.stateParams.numFilesProcessed + 1;
13 | samplingFreqHz = sdrParams.dataFileParamsList{fileNum}.samplingFreqHz;
14 | intermFreqHz = sdrParams.dataFileParamsList{fileNum}.intermFreqHz;
15 | chipRateHz = sdrParams.sysParams.caCodeChipRateHz;
16 | acqDopplerBwKhz = sdrParams.sysParams.acqDopplerBwKhz;
17 | cpiTimeMs = sdrParams.sysParams.coherentProcessingTimeMS;
18 |
19 | samplesPerCpi = samplingFreqHz * cpiTimeMs *1e-3;
20 | samplesPerMs = samplingFreqHz * 1e-3;
21 | numChipsPerMs = chipRateHz * 1e-3;
22 | numCaCodeFolds = cpiTimeMs;
23 | prnList = sdrParams.sysParams.acqSatelliteList;
24 |
25 | if floor(samplesPerCpi) ~= samplesPerCpi
26 | error('Number of samples per coherent processing interval can''t have decimal point.');
27 | end
28 |
29 | % Prepare per algorithm per block common signals
30 |
31 | %%% Determine maximum extent to which averaging can be done
32 | averFactor = [1];
33 | temAverFactor = 1;
34 | while samplingFreqHz/temAverFactor > sdrParams.sysParams.minSamplingFreqHz
35 | temAverFactor=temAverFactor+1;
36 | goodAverFactor = samplesPerCpi/temAverFactor;
37 | if floor(goodAverFactor) == goodAverFactor
38 | averFactor = [averFactor, temAverFactor];
39 | end
40 | end
41 | % choose highest dividing factor to maximize number of input samples
42 | % for one averaged output.
43 | averFactor = averFactor(end);
44 |
45 |
46 | %%% Find out integer number of samples per block and doppler bins
47 |
48 | numSamplesPerCpi = samplesPerCpi / averFactor;
49 | %number of doppler bins should be atleast 2/t_cpi
50 | minDopplerBins = round(acqDopplerBwKhz * cpiTimeMs);
51 | candidateNumDopplerBins = [];
52 | for ndb=minDopplerBins:minDopplerBins*2
53 | if floor(numSamplesPerCpi/ndb) == (numSamplesPerCpi/ndb)
54 | candidateNumDopplerBins = [candidateNumDopplerBins, ndb];
55 | end
56 | end
57 | if isempty(candidateNumDopplerBins)
58 | error('Unable to find integer multiple of blockSize for DBZP.');
59 | end
60 | numDopplerBins = min(candidateNumDopplerBins);
61 | numSamplesPerBlock = numSamplesPerCpi/numDopplerBins;
62 |
63 |
64 |
65 | %%% generate code for current PRN
66 | % Convert CA code to DBZP format.
67 |
68 | %%% Map to samples of 1ms
69 | caCodeSampleMap = floor((0:samplesPerMs/averFactor-1) * (numChipsPerMs*averFactor/samplesPerMs)) + 1;
70 | caCodeMapped = caCode(prnList, caCodeSampleMap);
71 | caCodeMapped = repmat(caCodeMapped, 1, numCaCodeFolds);
72 |
73 | numBlocks = samplesPerCpi/averFactor/numSamplesPerBlock;
74 | caCodeDbzpTable = zeros(length(prnList), 2*numSamplesPerBlock, numBlocks);
75 | for prnIdx=1:length(prnList)
76 | caCodePerPrn = reshape(caCodeMapped(prnIdx, :), numSamplesPerBlock, numBlocks);
77 | caCodePerPrn = [caCodePerPrn; zeros(numSamplesPerBlock, numBlocks)];
78 | caCodeDbzpTable(prnIdx, :, :) = caCodePerPrn;
79 | end
80 |
81 |
82 | %%% Prepare baseband doppler modulated matrix of data
83 |
84 | dopplerFreqExp = exp(2i * pi * (intermFreqHz/samplingFreqHz) * (0:samplesPerCpi-1));
85 |
86 |
87 | %%% Save preprocessing common signals and parameters to used in the
88 | % processing of DBZP algorithm.
89 |
90 | pprocSignals.caCodesTable = caCodeDbzpTable;
91 | pprocSignals.dopplerFreqExp = dopplerFreqExp;
92 | pprocSignals.numBlocks = numBlocks;
93 | pprocSignals.numSamplesPerBlock = numSamplesPerBlock;
94 | pprocSignals.averFactor = averFactor;
95 |
96 | end
97 |
--------------------------------------------------------------------------------
/pre_processing/pre_process.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function [ acqAlgoPprocSignals, rxData] = pre_process(sdrParams)
10 | %%% pre_process is responsible for configuration of settings
11 | % and pre-conditioning of the input data.
12 | % This includes per acquisition algorithm parameters
13 | % and common signal preparations.
14 |
15 | %%% Initialize the settings
16 |
17 | % Read data from configured channels
18 | % from current file.
19 | rxData = read_file_data(sdrParams);
20 |
21 |
22 | print_string('Generating C/A code.');
23 |
24 | % Gen/Read CA/Code
25 | caCodeTable = gen_ca_code(sdrParams.stateParams.dataPathIn, ...
26 | sdrParams.sysParams.acqSatelliteList);
27 |
28 | % Prepare signals for each algorithm
29 |
30 | acqAlgoPprocSignals = cell(0);
31 | acqAlgosList = sdrParams.sysParams.acqAlgosList;
32 | for acqIdx = 1:length(acqAlgosList)
33 |
34 | algoName = acqAlgosList{acqIdx};
35 |
36 | switch algoName
37 | case 'norm_acq_parcode'
38 | print_string('Preprocessing: pre_proc_norm_acq_parcode()');
39 | pprocSignals = pre_proc_norm_acq_parcode(sdrParams, caCodeTable);
40 |
41 | case 'weak_acq_dbzp'
42 | print_string('Preprocessing: Calling pre_proc_weak_acq_dbzp()');
43 | pprocSignals = pre_proc_weak_acq_dbzp(sdrParams, caCodeTable);
44 |
45 | otherwise
46 | error("Acquisition algorithm is not recognized.");
47 | end
48 |
49 | acqAlgoPprocSignals{acqIdx} = pprocSignals;
50 | end
51 |
52 | end
53 |
54 |
--------------------------------------------------------------------------------
/pre_processing/read_file_data.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function [ outData ] = read_file_data( sdrParams )
10 | %%%READ_FILE_DATA Read input file data and converts to suitable format.
11 | % Reads input file data and returns a cell of dimension
12 | % of 1xM is number of channels in the data file.
13 |
14 |
15 | % Extract relevant parameters
16 | fileNum = sdrParams.stateParams.numFilesProcessed + 1;
17 | fileName = sdrParams.stateParams.fileNames{fileNum};
18 | dataType = sdrParams.dataFileParamsList{fileNum}.dataType;
19 | samplingFreqHz = sdrParams.dataFileParamsList{fileNum}.samplingFreqHz;
20 | totalChannels = sdrParams.dataFileParamsList{fileNum}.totalChannels;
21 | selectedChannel = sdrParams.dataFileParamsList{fileNum}.selectedChannel;
22 | skipNumberOfBytes = sdrParams.sysParams.skipNumberOfBytes;
23 |
24 | % Define data buffer
25 | outData = cell(1);
26 |
27 | % Open file.
28 | currFileFullName = [sdrParams.stateParams.dataPathIn, fileName];
29 | [fid, message] = fopen(currFileFullName, 'rb', 'ieee-le');
30 | if fid <= 0
31 | % Error while opening the data file.
32 | error('Unable to read file %s: %s.', stateParams.currFileName, message);
33 | else
34 |
35 | % File opened successfully, read the contents.
36 | processDataDurMs = max([sdrParams.sysParams.coherentProcessingTimeMS, ...
37 | sdrParams.sysParams.incoherentProcessingTimeMS]);
38 | processDataDurSec = processDataDurMs * 1e-3;
39 | numSamples = floor(processDataDurSec * samplingFreqHz) * totalChannels;
40 |
41 | % Skip initial bytes
42 | fseek(fid, skipNumberOfBytes, 'bof');
43 |
44 | % Read from data file.
45 | rawData = fread(fid, numSamples, dataType)';
46 |
47 | % Check if sufficient data is present in the file.
48 | if length(rawData) < numSamples
49 | error('Configured processing interval data is not present in data file.');
50 | end
51 |
52 | % Convert from bits to symbols if necessary
53 | % This is file specific.
54 | switch fileName
55 | case 'NTLab_Bands_GPS_GLONASS_L12.bin'
56 | mOneIdx = rawData == 1;
57 | mThreeIdx = rawData == 3;
58 | pOneIdx = rawData == 0;
59 | pThreeIdx = rawData == 2;
60 |
61 | rawData(pOneIdx) = 1;
62 | rawData(mOneIdx) = -1;
63 | rawData(pThreeIdx) = 3;
64 | rawData(mThreeIdx) = -3;
65 |
66 | if selectedChannel == -1
67 | % Read all data from all channel
68 | for chIdx=1:totalChannels
69 | print_string(['Reading input data for channel : ', ...
70 | num2str(chIdx), '/', ...
71 | num2str(totalChannels)]);
72 | outData{chIdx, :} = rawData(chIdx:totalChannels:end);
73 | end
74 | else
75 | % Read all data from selected channel
76 | print_string(['Reading input data for channel : ', ...
77 | num2str(selectedChannel), '/', ...
78 | num2str(selectedChannel)]);
79 | outData{1} = rawData(selectedChannel:totalChannels:end);
80 | end
81 |
82 | case 'GPS_and_GIOVE_A-NN-fs16_3676-if4_1304.bin'
83 |
84 | otherwise
85 | print_string('File data is assumed to be in symbols not bits.');
86 |
87 | end
88 | end
89 | end
90 |
91 |
92 |
--------------------------------------------------------------------------------
/processing/process.m:
--------------------------------------------------------------------------------
1 | %%
2 | % Project Title: GNSS-R SDR
3 | % Author : John Bagshaw
4 | % Contact : jotshaw@yorku.ca
5 | % Supervisor : Prof.Sunil Bisnath
6 | % Institution : York University, Canada.
7 | %%
8 |
9 | function [ processResults] = process( sdrParams, ppData, rxData )
10 | % SUMMARY Function to process coherent processing interval data.
11 | % This function takes in input Raw data, preprocessed common signals
12 | % and processes current frame (coherent processing interval for current
13 | % input data file. process_results returns cell of length C where C is
14 | % number of channels and each cell contains L cells each corresponding to
15 | % different algorithm and each each contains struct containing processing
16 | % results of delay doppler map and acquisition stats.
17 |
18 |
19 |
20 | %%% Extract coherent frame data.
21 | currFileNum = sdrParams.stateParams.numFilesProcessed + 1;
22 | dataParams = sdrParams.dataFileParamsList{currFileNum};
23 | numSamplesPerMs = dataParams.samplingFreqHz * 1e-3;
24 | currFrameNum = sdrParams.stateParams.currFrameNum + 1;
25 | numTotalFrames = sdrParams.stateParams.numTotalFrames;
26 | numSamplesPerFrame = sdrParams.sysParams.coherentProcessingTimeMS * numSamplesPerMs;
27 | frameDataIndex = (currFrameNum-1)*numSamplesPerFrame + 1: ...
28 | currFrameNum * numSamplesPerFrame ;
29 | numChannels = length(rxData);
30 | acqAlgoList = sdrParams.sysParams.acqAlgosList;
31 | numAcqAlgos = length(acqAlgoList);
32 | processResults = cell(numChannels, numAcqAlgos);
33 | for chIdx=1:numChannels
34 |
35 | % Rx data for current frame
36 | % used for coherent integration
37 | % within the function.
38 | frameData = rxData{chIdx}(frameDataIndex);
39 |
40 | % Iterate over all algorithms and process the data.
41 | % These are core algorithms for acquisition.
42 | for acqAlgoIdx = 1:numAcqAlgos
43 |
44 |
45 | %%% Acquisition
46 |
47 | print_string(sprintf('Processing for frame: %d/%d, channel: %d/%d, algorithm: %s', ...
48 | sdrParams.stateParams.currFrameNum+1, ...
49 | sdrParams.stateParams.numTotalFrames, ...
50 | chIdx, ...
51 | numChannels, ...
52 | acqAlgoList{acqAlgoIdx}...
53 | ));
54 |
55 |
56 | clear( acqAlgoList{acqAlgoIdx} ); % Clear previous calls
57 |
58 | processResults{chIdx, acqAlgoIdx} = feval(acqAlgoList{acqAlgoIdx}, ... % Call acqusition function
59 | sdrParams, ...
60 | ppData{acqAlgoIdx}, ...
61 | frameData);
62 |
63 |
64 | %%% Tracking
65 |
66 |
67 |
68 | end
69 | end
70 |
71 |
72 | end
73 |
74 |
75 |
--------------------------------------------------------------------------------
/util/calc_sin.m:
--------------------------------------------------------------------------------
1 | function [re, im] = calc_sin(ar, degree, arg_real, arg_imag)
2 | %Clenshaw summation of sinus with complex argument
3 | %[re, im] = clksin(ar, degree, arg_real, arg_imag);
4 |
5 | % Written by Kai Borre
6 | % December 20, 1995
7 | %
8 | % See also WGS2UTM or CART2UTM
9 | %
10 | % CVS record:
11 | % $Id: clksin.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $
12 | %==========================================================================
13 |
14 | sin_arg_r = sin(arg_real);
15 | cos_arg_r = cos(arg_real);
16 | sinh_arg_i = sinh(arg_imag);
17 | cosh_arg_i = cosh(arg_imag);
18 |
19 | r = 2 * cos_arg_r * cosh_arg_i;
20 | i =-2 * sin_arg_r * sinh_arg_i;
21 |
22 | hr1 = 0; hr = 0; hi1 = 0; hi = 0;
23 |
24 | for t = degree : -1 : 1
25 | hr2 = hr1;
26 | hr1 = hr;
27 | hi2 = hi1;
28 | hi1 = hi;
29 | z = ar(t) + r*hr1 - i*hi - hr2;
30 | hi = i*hr1 + r*hi1 - hi2;
31 | hr = z;
32 | end
33 |
34 | r = sin_arg_r * cosh_arg_i;
35 | i = cos_arg_r * sinh_arg_i;
36 |
37 | re = r*hr - i*hi;
38 | im = r*hi + i*hr;
39 |
--------------------------------------------------------------------------------
/util/cart_2_geo.m:
--------------------------------------------------------------------------------
1 | function [phi, lambda, h] = cart_2_geo(X, Y, Z, i)
2 | %CART2GEO Conversion of Cartesian coordinates (X,Y,Z) to geographical
3 | %coordinates (phi, lambda, h) on a selected reference ellipsoid.
4 | %
5 | %[phi, lambda, h] = cart2geo(X, Y, Z, i);
6 | %
7 | % Choices i of Reference Ellipsoid for Geographical Coordinates
8 | % 1. International Ellipsoid 1924
9 | % 2. International Ellipsoid 1967
10 | % 3. World Geodetic System 1972
11 | % 4. Geodetic Reference System 1980
12 | % 5. World Geodetic System 1984
13 |
14 | %Kai Borre 10-13-98
15 | %Copyright (c) by Kai Borre
16 | %Revision: 1.0 Date: 1998/10/23
17 | %
18 | % CVS record:
19 | % $Id: cart2geo.m,v 1.1.2.2 2006/08/22 13:45:59 dpl Exp $
20 | %==========================================================================
21 |
22 | a = [6378388 6378160 6378135 6378137 6378137];
23 | f = [1/297 1/298.247 1/298.26 1/298.257222101 1/298.257223563];
24 |
25 | lambda = atan2(Y,X);
26 | ex2 = (2-f(i))*f(i)/((1-f(i))^2);
27 | c = a(i)*sqrt(1+ex2);
28 | phi = atan(Z/((sqrt(X^2+Y^2)*(1-(2-f(i)))*f(i))));
29 |
30 | h = 0.1; oldh = 0;
31 | while abs(h-oldh) > 1.e-12
32 | oldh = h;
33 | N = c/sqrt(1+ex2*cos(phi)^2);
34 | phi = atan(Z/((sqrt(X^2+Y^2)*(1-(2-f(i))*f(i)*N/(N+h)))));
35 | h = sqrt(X^2+Y^2)/cos(phi)-N;
36 | end
37 |
38 | phi = phi*180/pi;
39 | % b = zeros(1,3);
40 | % b(1,1) = fix(phi);
41 | % b(2,1) = fix(rem(phi,b(1,1))*60);
42 | % b(3,1) = (phi-b(1,1)-b(1,2)/60)*3600;
43 |
44 | lambda = lambda*180/pi;
45 | % l = zeros(1,3);
46 | % l(1,1) = fix(lambda);
47 | % l(2,1) = fix(rem(lambda,l(1,1))*60);
48 | % l(3,1) = (lambda-l(1,1)-l(1,2)/60)*3600;
49 |
50 | %fprintf('\n phi =%3.0f %3.0f %8.5f',b(1),b(2),b(3))
51 | %fprintf('\n lambda =%3.0f %3.0f %8.5f',l(1),l(2),l(3))
52 | %fprintf('\n h =%14.3f\n',h)
53 | %%%%%%%%%%%%%% end cart2geo.m %%%%%%%%%%%%%%%%%%%
54 |
--------------------------------------------------------------------------------
/util/cart_2_utm.m:
--------------------------------------------------------------------------------
1 | function [E, N, U] = cart_2_utm(X, Y, Z, zone)
2 | %CART2UTM Transformation of (X,Y,Z) to (N,E,U) in UTM, zone 'zone'.
3 | %
4 | %[E, N, U] = cart2utm(X, Y, Z, zone);
5 | %
6 | % Inputs:
7 | % X,Y,Z - Cartesian coordinates. Coordinates are referenced
8 | % with respect to the International Terrestrial Reference
9 | % Frame 1996 (ITRF96)
10 | % zone - UTM zone of the given position
11 | %
12 | % Outputs:
13 | % E, N, U - UTM coordinates (Easting, Northing, Uping)
14 |
15 | %Kai Borre -11-1994
16 | %Copyright (c) by Kai Borre
17 | %
18 | % CVS record:
19 | % $Id: cart2utm.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $
20 |
21 | %This implementation is based upon
22 | %O. Andersson & K. Poder (1981) Koordinattransformationer
23 | % ved Geod\ae{}tisk Institut. Landinspekt\oe{}ren
24 | % Vol. 30: 552--571 and Vol. 31: 76
25 | %
26 | %An excellent, general reference (KW) is
27 | %R. Koenig & K.H. Weise (1951) Mathematische Grundlagen der
28 | % h\"oheren Geod\"asie und Kartographie.
29 | % Erster Band, Springer Verlag
30 |
31 | % Explanation of variables used:
32 | % f flattening of ellipsoid
33 | % a semi major axis in m
34 | % m0 1 - scale at central meridian; for UTM 0.0004
35 | % Q_n normalized meridian quadrant
36 | % E0 Easting of central meridian
37 | % L0 Longitude of central meridian
38 | % bg constants for ellipsoidal geogr. to spherical geogr.
39 | % gb constants for spherical geogr. to ellipsoidal geogr.
40 | % gtu constants for ellipsoidal N, E to spherical N, E
41 | % utg constants for spherical N, E to ellipoidal N, E
42 | % tolutm tolerance for utm, 1.2E-10*meridian quadrant
43 | % tolgeo tolerance for geographical, 0.00040 second of arc
44 |
45 | % B, L refer to latitude and longitude. Southern latitude is negative
46 | % International ellipsoid of 1924, valid for ED50
47 |
48 | a = 6378388;
49 | f = 1/297;
50 | ex2 = (2-f)*f / ((1-f)^2);
51 | c = a * sqrt(1+ex2);
52 | vec = [X; Y; Z-4.5];
53 | alpha = .756e-6;
54 | R = [ 1 -alpha 0;
55 | alpha 1 0;
56 | 0 0 1];
57 | trans = [89.5; 93.8; 127.6];
58 | scale = 0.9999988;
59 | v = scale*R*vec + trans; % coordinate vector in ED50
60 | L = atan2(v(2), v(1));
61 | N1 = 6395000; % preliminary value
62 | B = atan2(v(3)/((1-f)^2*N1), norm(v(1:2))/N1); % preliminary value
63 | U = 0.1; oldU = 0;
64 |
65 | while abs(U-oldU) > 1.e-4
66 | oldU = U;
67 | N1 = c/sqrt(1+ex2*(cos(B))^2);
68 | B = atan2(v(3)/((1-f)^2*N1+U), norm(v(1:2))/(N1+U) );
69 | U = norm(v(1:2))/cos(B)-N1;
70 | end
71 |
72 | %Normalized meridian quadrant, KW p. 50 (96), p. 19 (38b), p. 5 (21)
73 | m0 = 0.0004;
74 | n = f / (2-f);
75 | m = n^2 * (1/4 + n*n/64);
76 | w = (a*(-n-m0+m*(1-m0))) / (1+n);
77 | Q_n = a + w;
78 |
79 | %Easting and longitude of central meridian
80 | E0 = 500000;
81 | L0 = (zone-30)*6 - 3;
82 |
83 | %Check tolerance for reverse transformation
84 | tolutm = pi/2 * 1.2e-10 * Q_n;
85 | tolgeo = 0.000040;
86 |
87 | %Coefficients of trigonometric series
88 |
89 | %ellipsoidal to spherical geographical, KW p. 186--187, (51)-(52)
90 | % bg[1] = n*(-2 + n*(2/3 + n*(4/3 + n*(-82/45))));
91 | % bg[2] = n^2*(5/3 + n*(-16/15 + n*(-13/9)));
92 | % bg[3] = n^3*(-26/15 + n*34/21);
93 | % bg[4] = n^4*1237/630;
94 |
95 | %spherical to ellipsoidal geographical, KW p. 190--191, (61)-(62)
96 | % gb[1] = n*(2 + n*(-2/3 + n*(-2 + n*116/45)));
97 | % gb[2] = n^2*(7/3 + n*(-8/5 + n*(-227/45)));
98 | % gb[3] = n^3*(56/15 + n*(-136/35));
99 | % gb[4] = n^4*4279/630;
100 |
101 | %spherical to ellipsoidal N, E, KW p. 196, (69)
102 | % gtu[1] = n*(1/2 + n*(-2/3 + n*(5/16 + n*41/180)));
103 | % gtu[2] = n^2*(13/48 + n*(-3/5 + n*557/1440));
104 | % gtu[3] = n^3*(61/240 + n*(-103/140));
105 | % gtu[4] = n^4*49561/161280;
106 |
107 | %ellipsoidal to spherical N, E, KW p. 194, (65)
108 | % utg[1] = n*(-1/2 + n*(2/3 + n*(-37/96 + n*1/360)));
109 | % utg[2] = n^2*(-1/48 + n*(-1/15 + n*437/1440));
110 | % utg[3] = n^3*(-17/480 + n*37/840);
111 | % utg[4] = n^4*(-4397/161280);
112 |
113 | %With f = 1/297 we get
114 |
115 | bg = [-3.37077907e-3;
116 | 4.73444769e-6;
117 | -8.29914570e-9;
118 | 1.58785330e-11];
119 |
120 | gb = [ 3.37077588e-3;
121 | 6.62769080e-6;
122 | 1.78718601e-8;
123 | 5.49266312e-11];
124 |
125 | gtu = [ 8.41275991e-4;
126 | 7.67306686e-7;
127 | 1.21291230e-9;
128 | 2.48508228e-12];
129 |
130 | utg = [-8.41276339e-4;
131 | -5.95619298e-8;
132 | -1.69485209e-10;
133 | -2.20473896e-13];
134 |
135 | %Ellipsoidal latitude, longitude to spherical latitude, longitude
136 | neg_geo = 'FALSE';
137 |
138 | if B < 0
139 | neg_geo = 'TRUE ';
140 | end
141 |
142 | Bg_r = abs(B);
143 | [res_clensin] = clsin(bg, 4, 2*Bg_r);
144 | Bg_r = Bg_r + res_clensin;
145 | L0 = L0*pi / 180;
146 | Lg_r = L - L0;
147 |
148 | %Spherical latitude, longitude to complementary spherical latitude
149 | % i.e. spherical N, E
150 | cos_BN = cos(Bg_r);
151 | Np = atan2(sin(Bg_r), cos(Lg_r)*cos_BN);
152 | Ep = atanh(sin(Lg_r) * cos_BN);
153 |
154 | %Spherical normalized N, E to ellipsoidal N, E
155 | Np = 2 * Np;
156 | Ep = 2 * Ep;
157 | [dN, dE] = clksin(gtu, 4, Np, Ep);
158 | Np = Np/2;
159 | Ep = Ep/2;
160 | Np = Np + dN;
161 | Ep = Ep + dE;
162 | N = Q_n * Np;
163 | E = Q_n*Ep + E0;
164 |
165 | if neg_geo == 'TRUE '
166 | N = -N + 20000000;
167 | end;
168 |
169 | %%%%%%%%%%%%%%%%%%%% end cart2utm.m %%%%%%%%%%%%%%%%%%%%
--------------------------------------------------------------------------------
/util/check_t.m:
--------------------------------------------------------------------------------
1 | function corrTime = check_t(time)
2 | %CHECK_T accounting for beginning or end of week crossover.
3 | %
4 | %corrTime = check_t(time);
5 | %
6 | % Inputs:
7 | % time - time in seconds
8 | %
9 | % Outputs:
10 | % corrTime - corrected time (seconds)
11 |
12 | %Kai Borre 04-01-96
13 | %Copyright (c) by Kai Borre
14 | %
15 | % CVS record:
16 | % $Id: check_t.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $
17 | %==========================================================================
18 |
19 | half_week = 302400; % seconds
20 |
21 | corrTime = time;
22 |
23 | if time > half_week
24 | corrTime = time - 2*half_week;
25 | elseif time < -half_week
26 | corrTime = time + 2*half_week;
27 | end
28 | %%%%%%% end check_t.m %%%%%%%%%%%%%%%%%
--------------------------------------------------------------------------------
/util/clen_sin.m:
--------------------------------------------------------------------------------
1 | function result = clen_sin(ar, degree, argument)
2 | %Clenshaw summation of sinus of argument.
3 | %
4 | %result = clsin(ar, degree, argument);
5 |
6 | % Written by Kai Borre
7 | % December 20, 1995
8 | %
9 | % See also WGS2UTM or CART2UTM
10 | %
11 | % CVS record:
12 | % $Id: clsin.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $
13 | %==========================================================================
14 |
15 | cos_arg = 2 * cos(argument);
16 | hr1 = 0;
17 | hr = 0;
18 |
19 | for t = degree : -1 : 1
20 | hr2 = hr1;
21 | hr1 = hr;
22 | hr = ar(t) + cos_arg*hr1 - hr2;
23 | end
24 |
25 | result = hr * sin(argument);
26 | %%%%%%%%%%%%%%%%%%%%%%% end clsin.m %%%%%%%%%%%%%%%%%%%%%
--------------------------------------------------------------------------------
/util/conv_dbzp_form.m:
--------------------------------------------------------------------------------
1 | %% This function arrange linear data into DBZP form
2 | % where data_in is an 1xN array and output is 2k x (N/k)
3 | % and first half of each contains rearranged data while
4 | % second half contains zeros.
5 |
6 | function [ data_out ] = conv_dbzp_form( data_i, ... % input data
7 | k ... % block size to convert into
8 | )
9 |
10 | data_out = reshape(data_i, k, length(data_i)/k);
11 | data_out = [data_out; zeros(size(data_out))];
12 |
13 | end
14 |
15 |
--------------------------------------------------------------------------------
/util/create_data_file.m:
--------------------------------------------------------------------------------
1 | data = dlmread('data.txt', ',');
2 |
3 | str = [];
4 |
5 | str = sprintf('%s\n', '{');
6 | for i=1:100
7 | str = [str, sprintf('%s', '{')];
8 | str = [str, sprintf('%d', data((i-1)*8+1))];
9 | for j=(i-1)*8+2:i*8
10 | str = [str, sprintf(', %d', data(j))];
11 | end
12 | str = [str, sprintf('%s, \n', '}')];
13 | end
14 | str = [str, sprintf('%s\n', '};')]
--------------------------------------------------------------------------------
/util/e_r_corr.m:
--------------------------------------------------------------------------------
1 | function X_sat_rot = e_r_corr(traveltime, X_sat)
2 | %E_R_CORR Returns rotated satellite ECEF coordinates due to Earth
3 | %rotation during signal travel time
4 | %
5 | %X_sat_rot = e_r_corr(traveltime, X_sat);
6 | %
7 | % Inputs:
8 | % travelTime - signal travel time
9 | % X_sat - satellite's ECEF coordinates
10 | %
11 | % Outputs:
12 | % X_sat_rot - rotated satellite's coordinates (ECEF)
13 |
14 | %Written by Kai Borre
15 | %Copyright (c) by Kai Borre
16 | %
17 | % CVS record:
18 | % $Id: e_r_corr.m,v 1.1.1.1.2.6 2006/08/22 13:45:59 dpl Exp $
19 | %==========================================================================
20 |
21 | Omegae_dot = 7.292115147e-5; % rad/sec
22 |
23 | %--- Find rotation angle --------------------------------------------------
24 | omegatau = Omegae_dot * traveltime;
25 |
26 | %--- Make a rotation matrix -----------------------------------------------
27 | R3 = [ cos(omegatau) sin(omegatau) 0;
28 | -sin(omegatau) cos(omegatau) 0;
29 | 0 0 1];
30 |
31 | %--- Do the rotation ------------------------------------------------------
32 | X_sat_rot = R3 * X_sat;
33 |
34 | %%%%%%%% end e_r_corr.m %%%%%%%%%%%%%%%%%%%%
--------------------------------------------------------------------------------
/util/find_utm_zone.m:
--------------------------------------------------------------------------------
1 | function utmZone = find_utm_zone(latitude, longitude)
2 | %Function finds the UTM zone number for given longitude and latitude.
3 | %The longitude value must be between -180 (180 degree West) and 180 (180
4 | %degree East) degree. The latitude must be within -80 (80 degree South) and
5 | %84 (84 degree North).
6 | %
7 | %utmZone = findUtmZone(latitude, longitude);
8 | %
9 | %Latitude and longitude must be in decimal degrees (e.g. 15.5 degrees not
10 | %15 deg 30 min).
11 |
12 | %--------------------------------------------------------------------------
13 | % SoftGNSS v3.0
14 | %
15 | % Copyright (C) Darius Plausinaitis
16 | % Written by Darius Plausinaitis
17 | %--------------------------------------------------------------------------
18 | %This program is free software; you can redistribute it and/or
19 | %modify it under the terms of the GNU General Public License
20 | %as published by the Free Software Foundation; either version 2
21 | %of the License, or (at your option) any later version.
22 | %
23 | %This program is distributed in the hope that it will be useful,
24 | %but WITHOUT ANY WARRANTY; without even the implied warranty of
25 | %MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 | %GNU General Public License for more details.
27 | %
28 | %You should have received a copy of the GNU General Public License
29 | %along with this program; if not, write to the Free Software
30 | %Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
31 | %USA.
32 | %==========================================================================
33 |
34 | %CVS record:
35 | %$Id: findUtmZone.m,v 1.1.2.2 2006/08/22 13:45:59 dpl Exp $
36 |
37 | %% Check value bounds =====================================================
38 |
39 | if ((longitude > 180) || (longitude < -180))
40 | error('Longitude value exceeds limits (-180:180).');
41 | end
42 |
43 | if ((latitude > 84) || (latitude < -80))
44 | error('Latitude value exceeds limits (-80:84).');
45 | end
46 |
47 | %% Find zone ==============================================================
48 |
49 | % Start at 180 deg west = -180 deg
50 |
51 | utmZone = fix((180 + longitude)/ 6) + 1;
52 |
53 | %% Correct zone numbers for particular areas ==============================
54 |
55 | if (latitude > 72)
56 | % Corrections for zones 31 33 35 37
57 | if ((longitude >= 0) && (longitude < 9))
58 | utmZone = 31;
59 | elseif ((longitude >= 9) && (longitude < 21))
60 | utmZone = 33;
61 | elseif ((longitude >= 21) && (longitude < 33))
62 | utmZone = 35;
63 | elseif ((longitude >= 33) && (longitude < 42))
64 | utmZone = 37;
65 | end
66 |
67 | elseif ((latitude >= 56) && (latitude < 64))
68 | % Correction for zone 32
69 | if ((longitude >= 3) && (longitude < 12))
70 | utmZone = 32;
71 | end
72 | end
--------------------------------------------------------------------------------
/util/geo_2_cart.m:
--------------------------------------------------------------------------------
1 | function [X, Y, Z] = geo_2_cart(phi, lambda, h, i)
2 | %GEO2CART Conversion of geographical coordinates (phi, lambda, h) to
3 | %Cartesian coordinates (X, Y, Z).
4 | %
5 | %[X, Y, Z] = geo2cart(phi, lambda, h, i);
6 | %
7 | %Format for phi and lambda: [degrees minutes seconds].
8 | %h, X, Y, and Z are in meters.
9 | %
10 | %Choices i of Reference Ellipsoid
11 | % 1. International Ellipsoid 1924
12 | % 2. International Ellipsoid 1967
13 | % 3. World Geodetic System 1972
14 | % 4. Geodetic Reference System 1980
15 | % 5. World Geodetic System 1984
16 | %
17 | % Inputs:
18 | % phi - geocentric latitude (format [degrees minutes seconds])
19 | % lambda - geocentric longitude (format [degrees minutes seconds])
20 | % h - height
21 | % i - reference ellipsoid type
22 | %
23 | % Outputs:
24 | % X, Y, Z - Cartesian coordinates (meters)
25 |
26 | %Kai Borre 10-13-98
27 | %Copyright (c) by Kai Borre
28 | %
29 | % CVS record:
30 | % $Id: geo2cart.m,v 1.1.2.7 2006/08/22 13:45:59 dpl Exp $
31 | %==========================================================================
32 |
33 | b = phi(1) + phi(2)/60 + phi(3)/3600;
34 | b = b*pi / 180;
35 | l = lambda(1) + lambda(2)/60 + lambda(3)/3600;
36 | l = l*pi / 180;
37 |
38 | a = [6378388 6378160 6378135 6378137 6378137];
39 | f = [1/297 1/298.247 1/298.26 1/298.257222101 1/298.257223563];
40 |
41 | ex2 = (2-f(i))*f(i) / ((1-f(i))^2);
42 | c = a(i) * sqrt(1+ex2);
43 | N = c / sqrt(1 + ex2*cos(b)^2);
44 |
45 | X = (N+h) * cos(b) * cos(l);
46 | Y = (N+h) * cos(b) * sin(l);
47 | Z = ((1-f(i))^2*N + h) * sin(b);
48 | %%%%%%%%%%%%%% end geo2cart.m %%%%%%%%%%%%%%%%%%%%%%%%
49 |
--------------------------------------------------------------------------------
/util/least_square_post.m:
--------------------------------------------------------------------------------
1 | function [pos, el, az, dop] = least_square_pos(satpos, obs, settings)
2 | %Function calculates the Least Square Solution.
3 | %
4 | %[pos, el, az, dop] = leastSquarePos(satpos, obs, settings);
5 | %
6 | % Inputs:
7 | % satpos - Satellites positions (in ECEF system: [X; Y; Z;] -
8 | % one column per satellite)
9 | % obs - Observations - the pseudorange measurements to each
10 | % satellite:
11 | % (e.g. [20000000 21000000 .... .... .... .... ....])
12 | % settings - receiver settings
13 | %
14 | % Outputs:
15 | % pos - receiver position and receiver clock error
16 | % (in ECEF system: [X, Y, Z, dt])
17 | % el - Satellites elevation angles (degrees)
18 | % az - Satellites azimuth angles (degrees)
19 | % dop - Dilutions Of Precision ([GDOP PDOP HDOP VDOP TDOP])
20 |
21 | %--------------------------------------------------------------------------
22 | % SoftGNSS v3.0
23 | %--------------------------------------------------------------------------
24 | %Based on Kai Borre
25 | %Copyright (c) by Kai Borre
26 | %Updated by Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen
27 | %
28 | % CVS record:
29 | % $Id: leastSquarePos.m,v 1.1.2.12 2006/08/22 13:45:59 dpl Exp $
30 | %==========================================================================
31 |
32 | %=== Initialization =======================================================
33 | nmbOfIterations = 7;
34 |
35 | dtr = pi/180;
36 | pos = zeros(4, 1);
37 | X = satpos;
38 | nmbOfSatellites = size(satpos, 2);
39 |
40 | A = zeros(nmbOfSatellites, 4);
41 | omc = zeros(nmbOfSatellites, 1);
42 | az = zeros(1, nmbOfSatellites);
43 | el = az;
44 |
45 | %=== Iteratively find receiver position ===================================
46 | for iter = 1:nmbOfIterations
47 |
48 | for i = 1:nmbOfSatellites
49 | if iter == 1
50 | %--- Initialize variables at the first iteration --------------
51 | Rot_X = X(:, i);
52 | trop = 2;
53 | else
54 | %--- Update equations -----------------------------------------
55 | rho2 = (X(1, i) - pos(1))^2 + (X(2, i) - pos(2))^2 + ...
56 | (X(3, i) - pos(3))^2;
57 | traveltime = sqrt(rho2) / settings.c ;
58 |
59 | %--- Correct satellite position (do to earth rotation) --------
60 | Rot_X = e_r_corr(traveltime, X(:, i));
61 |
62 | %--- Find the elevation angel of the satellite ----------------
63 | [az(i), el(i), dist] = topocent(pos(1:3, :), Rot_X - pos(1:3, :));
64 |
65 | if (settings.useTropCorr == 1)
66 | %--- Calculate tropospheric correction --------------------
67 | trop = tropo(sin(el(i) * dtr), ...
68 | 0.0, 1013.0, 293.0, 50.0, 0.0, 0.0, 0.0);
69 | else
70 | % Do not calculate or apply the tropospheric corrections
71 | trop = 0;
72 | end
73 | end % if iter == 1 ... ... else
74 |
75 | %--- Apply the corrections ----------------------------------------
76 | omc(i) = (obs(i) - norm(Rot_X - pos(1:3), 'fro') - pos(4) - trop);
77 |
78 | %--- Construct the A matrix ---------------------------------------
79 | A(i, :) = [ (-(Rot_X(1) - pos(1))) / obs(i) ...
80 | (-(Rot_X(2) - pos(2))) / obs(i) ...
81 | (-(Rot_X(3) - pos(3))) / obs(i) ...
82 | 1 ];
83 | end % for i = 1:nmbOfSatellites
84 |
85 | % These lines allow the code to exit gracefully in case of any errors
86 | if rank(A) ~= 4
87 | pos = zeros(1, 4);
88 | return
89 | end
90 |
91 | %--- Find position update ---------------------------------------------
92 | x = A \ omc;
93 |
94 | %--- Apply position update --------------------------------------------
95 | pos = pos + x;
96 |
97 | end % for iter = 1:nmbOfIterations
98 |
99 | pos = pos';
100 |
101 | %=== Calculate Dilution Of Precision ======================================
102 | if nargout == 4
103 | %--- Initialize output ------------------------------------------------
104 | dop = zeros(1, 5);
105 |
106 | %--- Calculate DOP ----------------------------------------------------
107 | Q = inv(A'*A);
108 |
109 | dop(1) = sqrt(trace(Q)); % GDOP
110 | dop(2) = sqrt(Q(1,1) + Q(2,2) + Q(3,3)); % PDOP
111 | dop(3) = sqrt(Q(1,1) + Q(2,2)); % HDOP
112 | dop(4) = sqrt(Q(3,3)); % VDOP
113 | dop(5) = sqrt(Q(4,4)); % TDOP
114 | end
115 |
--------------------------------------------------------------------------------
/util/sat_pos.m:
--------------------------------------------------------------------------------
1 | function [satPositions, satClkCorr] = sat_pos(transmitTime, prnList, ...
2 | eph, settings)
3 | %SATPOS Calculation of X,Y,Z satellites coordinates at TRANSMITTIME for
4 | %given ephemeris EPH. Coordinates are calculated for each satellite in the
5 | %list PRNLIST.
6 | %[satPositions, satClkCorr] = satpos(transmitTime, prnList, eph, settings);
7 | %
8 | % Inputs:
9 | % transmitTime - transmission time
10 | % prnList - list of PRN-s to be processed
11 | % eph - ephemeridies of satellites
12 | % settings - receiver settings
13 | %
14 | % Outputs:
15 | % satPositions - positions of satellites (in ECEF system [X; Y; Z;])
16 | % satClkCorr - correction of satellites clocks
17 |
18 | %--------------------------------------------------------------------------
19 | % SoftGNSS v3.0
20 | %--------------------------------------------------------------------------
21 | %Based on Kai Borre 04-09-96
22 | %Copyright (c) by Kai Borre
23 | %Updated by Darius Plausinaitis, Peter Rinder and Nicolaj Bertelsen
24 | %
25 | % CVS record:
26 | % $Id: satpos.m,v 1.1.2.15 2006/08/22 13:45:59 dpl Exp $
27 |
28 | %% Initialize constants ===================================================
29 | numOfSatellites = size(prnList, 2);
30 |
31 | % GPS constatns
32 |
33 | gpsPi = 3.1415926535898; % Pi used in the GPS coordinate
34 | % system
35 |
36 | %--- Constants for satellite position calculation -------------------------
37 | Omegae_dot = 7.2921151467e-5; % Earth rotation rate, [rad/s]
38 | GM = 3.986005e14; % Earth's universal
39 | % gravitational parameter,
40 | % [m^3/s^2]
41 | F = -4.442807633e-10; % Constant, [sec/(meter)^(1/2)]
42 |
43 | %% Initialize results =====================================================
44 | satClkCorr = zeros(1, numOfSatellites);
45 | satPositions = zeros(3, numOfSatellites);
46 |
47 | %% Process each satellite =================================================
48 |
49 | for satNr = 1 : numOfSatellites
50 |
51 | prn = prnList(satNr);
52 |
53 | %% Find initial satellite clock correction --------------------------------
54 |
55 | %--- Find time difference ---------------------------------------------
56 | dt = check_t(transmitTime - eph(prn).t_oc);
57 |
58 | %--- Calculate clock correction ---------------------------------------
59 | satClkCorr(satNr) = (eph(prn).a_f2 * dt + eph(prn).a_f1) * dt + ...
60 | eph(prn).a_f0 - ...
61 | eph(prn).T_GD;
62 |
63 | time = transmitTime - satClkCorr(satNr);
64 |
65 | %% Find satellite's position ----------------------------------------------
66 |
67 | %Restore semi-major axis
68 | a = eph(prn).sqrtA * eph(prn).sqrtA;
69 |
70 | %Time correction
71 | tk = check_t(time - eph(prn).t_oe);
72 |
73 | %Initial mean motion
74 | n0 = sqrt(GM / a^3);
75 | %Mean motion
76 | n = n0 + eph(prn).deltan;
77 |
78 | %Mean anomaly
79 | M = eph(prn).M_0 + n * tk;
80 | %Reduce mean anomaly to between 0 and 360 deg
81 | M = rem(M + 2*gpsPi, 2*gpsPi);
82 |
83 | %Initial guess of eccentric anomaly
84 | E = M;
85 |
86 | %--- Iteratively compute eccentric anomaly ----------------------------
87 | for ii = 1:10
88 | E_old = E;
89 | E = M + eph(prn).e * sin(E);
90 | dE = rem(E - E_old, 2*gpsPi);
91 |
92 | if abs(dE) < 1.e-12
93 | % Necessary precision is reached, exit from the loop
94 | break;
95 | end
96 | end
97 |
98 | %Reduce eccentric anomaly to between 0 and 360 deg
99 | E = rem(E + 2*gpsPi, 2*gpsPi);
100 |
101 | %Compute relativistic correction term
102 | dtr = F * eph(prn).e * eph(prn).sqrtA * sin(E);
103 |
104 | %Calculate the true anomaly
105 | nu = atan2(sqrt(1 - eph(prn).e^2) * sin(E), cos(E)-eph(prn).e);
106 |
107 | %Compute angle phi
108 | phi = nu + eph(prn).omega;
109 | %Reduce phi to between 0 and 360 deg
110 | phi = rem(phi, 2*gpsPi);
111 |
112 | %Correct argument of latitude
113 | u = phi + ...
114 | eph(prn).C_uc * cos(2*phi) + ...
115 | eph(prn).C_us * sin(2*phi);
116 | %Correct radius
117 | r = a * (1 - eph(prn).e*cos(E)) + ...
118 | eph(prn).C_rc * cos(2*phi) + ...
119 | eph(prn).C_rs * sin(2*phi);
120 | %Correct inclination
121 | i = eph(prn).i_0 + eph(prn).iDot * tk + ...
122 | eph(prn).C_ic * cos(2*phi) + ...
123 | eph(prn).C_is * sin(2*phi);
124 |
125 | %Compute the angle between the ascending node and the Greenwich meridian
126 | Omega = eph(prn).omega_0 + (eph(prn).omegaDot - Omegae_dot)*tk - ...
127 | Omegae_dot * eph(prn).t_oe;
128 | %Reduce to between 0 and 360 deg
129 | Omega = rem(Omega + 2*gpsPi, 2*gpsPi);
130 |
131 | %--- Compute satellite coordinates ------------------------------------
132 | satPositions(1, satNr) = cos(u)*r * cos(Omega) - sin(u)*r * cos(i)*sin(Omega);
133 | satPositions(2, satNr) = cos(u)*r * sin(Omega) + sin(u)*r * cos(i)*cos(Omega);
134 | satPositions(3, satNr) = sin(u)*r * sin(i);
135 |
136 |
137 | %% Include relativistic correction in clock correction --------------------
138 | satClkCorr(satNr) = (eph(prn).a_f2 * dt + eph(prn).a_f1) * dt + ...
139 | eph(prn).a_f0 - ...
140 | eph(prn).T_GD + dtr;
141 |
142 | end % for satNr = 1 : numOfSatellites
143 |
--------------------------------------------------------------------------------
/util/sizeof.m:
--------------------------------------------------------------------------------
1 | function nBytes = sizeof(precision)
2 | %%% SIZEOF return the number of bytes of a builtin data type.
3 | error(nargchk(1, 1, nargin, 'struct'));
4 | try
5 | d = regexp(str, '\d*','Match');
6 | nBits = str2num(d{1});
7 | nBytes = ceil(nBits / 8);
8 | catch
9 | error('Unsupported class for finding size');
10 | end
11 |
--------------------------------------------------------------------------------
/util/to_geod.m:
--------------------------------------------------------------------------------
1 | function [dphi, dlambda, h] = to_geod(a, finv, X, Y, Z)
2 | %TOGEOD Subroutine to calculate geodetic coordinates latitude, longitude,
3 | % height given Cartesian coordinates X,Y,Z, and reference ellipsoid
4 | % values semi-major axis (a) and the inverse of flattening (finv).
5 | %
6 | %[dphi, dlambda, h] = togeod(a, finv, X, Y, Z);
7 | %
8 | % The units of linear parameters X,Y,Z,a must all agree (m,km,mi,ft,..etc)
9 | % The output units of angular quantities will be in decimal degrees
10 | % (15.5 degrees not 15 deg 30 min). The output units of h will be the
11 | % same as the units of X,Y,Z,a.
12 | %
13 | % Inputs:
14 | % a - semi-major axis of the reference ellipsoid
15 | % finv - inverse of flattening of the reference ellipsoid
16 | % X,Y,Z - Cartesian coordinates
17 | %
18 | % Outputs:
19 | % dphi - latitude
20 | % dlambda - longitude
21 | % h - height above reference ellipsoid
22 |
23 | % Copyright (C) 1987 C. Goad, Columbus, Ohio
24 | % Reprinted with permission of author, 1996
25 | % Fortran code translated into MATLAB
26 | % Kai Borre 03-30-96
27 | %
28 | % CVS record:
29 | % $Id: togeod.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $
30 | %==========================================================================
31 |
32 | h = 0;
33 | tolsq = 1.e-10;
34 | maxit = 10;
35 |
36 | % compute radians-to-degree factor
37 | rtd = 180/pi;
38 |
39 | % compute square of eccentricity
40 | if finv < 1.e-20
41 | esq = 0;
42 | else
43 | esq = (2 - 1/finv) / finv;
44 | end
45 |
46 | oneesq = 1 - esq;
47 |
48 | % first guess
49 | % P is distance from spin axis
50 | P = sqrt(X^2+Y^2);
51 | % direct calculation of longitude
52 |
53 | if P > 1.e-20
54 | dlambda = atan2(Y,X) * rtd;
55 | else
56 | dlambda = 0;
57 | end
58 |
59 | if (dlambda < 0)
60 | dlambda = dlambda + 360;
61 | end
62 |
63 | % r is distance from origin (0,0,0)
64 | r = sqrt(P^2 + Z^2);
65 |
66 | if r > 1.e-20
67 | sinphi = Z/r;
68 | else
69 | sinphi = 0;
70 | end
71 |
72 | dphi = asin(sinphi);
73 |
74 | % initial value of height = distance from origin minus
75 | % approximate distance from origin to surface of ellipsoid
76 | if r < 1.e-20
77 | h = 0;
78 | return
79 | end
80 |
81 | h = r - a*(1-sinphi*sinphi/finv);
82 |
83 | % iterate
84 | for i = 1:maxit
85 | sinphi = sin(dphi);
86 | cosphi = cos(dphi);
87 |
88 | % compute radius of curvature in prime vertical direction
89 | N_phi = a/sqrt(1-esq*sinphi*sinphi);
90 |
91 | % compute residuals in P and Z
92 | dP = P - (N_phi + h) * cosphi;
93 | dZ = Z - (N_phi*oneesq + h) * sinphi;
94 |
95 | % update height and latitude
96 | h = h + (sinphi*dZ + cosphi*dP);
97 | dphi = dphi + (cosphi*dZ - sinphi*dP)/(N_phi + h);
98 |
99 | % test for convergence
100 | if (dP*dP + dZ*dZ < tolsq)
101 | break;
102 | end
103 |
104 | % Not Converged--Warn user
105 | if i == maxit
106 | fprintf([' Problem in TOGEOD, did not converge in %2.0f',...
107 | ' iterations\n'], i);
108 | end
109 | end % for i = 1:maxit
110 |
111 | dphi = dphi * rtd;
112 | %%%%%%%% end togeod.m %%%%%%%%%%%%%%%%%%%%%%
113 |
--------------------------------------------------------------------------------
/util/topocent.m:
--------------------------------------------------------------------------------
1 | function [Az, El, D] = topocent(X, dx)
2 | %TOPOCENT Transformation of vector dx into topocentric coordinate
3 | % system with origin at X.
4 | % Both parameters are 3 by 1 vectors.
5 | %
6 | %[Az, El, D] = topocent(X, dx);
7 | %
8 | % Inputs:
9 | % X - vector origin corrdinates (in ECEF system [X; Y; Z;])
10 | % dx - vector ([dX; dY; dZ;]).
11 | %
12 | % Outputs:
13 | % D - vector length. Units like units of the input
14 | % Az - azimuth from north positive clockwise, degrees
15 | % El - elevation angle, degrees
16 |
17 | %Kai Borre 11-24-96
18 | %Copyright (c) by Kai Borre
19 | %
20 | % CVS record:
21 | % $Id: topocent.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $
22 | %==========================================================================
23 |
24 | dtr = pi/180;
25 |
26 | [phi, lambda, h] = togeod(6378137, 298.257223563, X(1), X(2), X(3));
27 |
28 | cl = cos(lambda * dtr);
29 | sl = sin(lambda * dtr);
30 | cb = cos(phi * dtr);
31 | sb = sin(phi * dtr);
32 |
33 | F = [-sl -sb*cl cb*cl;
34 | cl -sb*sl cb*sl;
35 | 0 cb sb];
36 |
37 | local_vector = F' * dx;
38 | E = local_vector(1);
39 | N = local_vector(2);
40 | U = local_vector(3);
41 |
42 | hor_dis = sqrt(E^2 + N^2);
43 |
44 | if hor_dis < 1.e-20
45 | Az = 0;
46 | El = 90;
47 | else
48 | Az = atan2(E, N)/dtr;
49 | El = atan2(U, hor_dis)/dtr;
50 | end
51 |
52 | if Az < 0
53 | Az = Az + 360;
54 | end
55 |
56 | D = sqrt(dx(1)^2 + dx(2)^2 + dx(3)^2);
57 | %%%%%%%%% end topocent.m %%%%%%%%%
--------------------------------------------------------------------------------
/util/tropo_corr.m:
--------------------------------------------------------------------------------
1 | function ddr = tropo(sinel, hsta, p, tkel, hum, hp, htkel, hhum)
2 | %TROPO Calculation of tropospheric correction.
3 | % The range correction ddr in m is to be subtracted from
4 | % pseudo-ranges and carrier phases
5 | %
6 | %ddr = tropo(sinel, hsta, p, tkel, hum, hp, htkel, hhum);
7 | %
8 | % Inputs:
9 | % sinel - sin of elevation angle of satellite
10 | % hsta - height of station in km
11 | % p - atmospheric pressure in mb at height hp
12 | % tkel - surface temperature in degrees Kelvin at height htkel
13 | % hum - humidity in % at height hhum
14 | % hp - height of pressure measurement in km
15 | % htkel - height of temperature measurement in km
16 | % hhum - height of humidity measurement in km
17 | %
18 | % Outputs:
19 | % ddr - range correction (meters)
20 | %
21 | % Reference
22 | % Goad, C.C. & Goodman, L. (1974) A Modified Tropospheric
23 | % Refraction Correction Model. Paper presented at the
24 | % American Geophysical Union Annual Fall Meeting, San
25 | % Francisco, December 12-17
26 |
27 | % A Matlab reimplementation of a C code from driver.
28 | % Kai Borre 06-28-95
29 | %
30 | % CVS record:
31 | % $Id: tropo.m,v 1.1.1.1.2.4 2006/08/22 13:46:00 dpl Exp $
32 | %==========================================================================
33 |
34 | a_e = 6378.137; % semi-major axis of earth ellipsoid
35 | b0 = 7.839257e-5;
36 | tlapse = -6.5;
37 | tkhum = tkel + tlapse*(hhum-htkel);
38 | atkel = 7.5*(tkhum-273.15) / (237.3+tkhum-273.15);
39 | e0 = 0.0611 * hum * 10^atkel;
40 | tksea = tkel - tlapse*htkel;
41 | em = -978.77 / (2.8704e6*tlapse*1.0e-5);
42 | tkelh = tksea + tlapse*hhum;
43 | e0sea = e0 * (tksea/tkelh)^(4*em);
44 | tkelp = tksea + tlapse*hp;
45 | psea = p * (tksea/tkelp)^em;
46 |
47 | if sinel < 0
48 | sinel = 0;
49 | end
50 |
51 | tropo = 0;
52 | done = 'FALSE';
53 | refsea = 77.624e-6 / tksea;
54 | htop = 1.1385e-5 / refsea;
55 | refsea = refsea * psea;
56 | ref = refsea * ((htop-hsta)/htop)^4;
57 |
58 | while 1
59 | rtop = (a_e+htop)^2 - (a_e+hsta)^2*(1-sinel^2);
60 |
61 | % check to see if geometry is crazy
62 | if rtop < 0
63 | rtop = 0;
64 | end
65 |
66 | rtop = sqrt(rtop) - (a_e+hsta)*sinel;
67 | a = -sinel/(htop-hsta);
68 | b = -b0*(1-sinel^2) / (htop-hsta);
69 | rn = zeros(8,1);
70 |
71 | for i = 1:8
72 | rn(i) = rtop^(i+1);
73 | end
74 |
75 | alpha = [2*a, 2*a^2+4*b/3, a*(a^2+3*b),...
76 | a^4/5+2.4*a^2*b+1.2*b^2, 2*a*b*(a^2+3*b)/3,...
77 | b^2*(6*a^2+4*b)*1.428571e-1, 0, 0];
78 |
79 | if b^2 > 1.0e-35
80 | alpha(7) = a*b^3/2;
81 | alpha(8) = b^4/9;
82 | end
83 |
84 | dr = rtop;
85 | dr = dr + alpha*rn;
86 | tropo = tropo + dr*ref*1000;
87 |
88 | if done == 'TRUE '
89 | ddr = tropo;
90 | break;
91 | end
92 |
93 | done = 'TRUE ';
94 | refsea = (371900.0e-6/tksea-12.92e-6)/tksea;
95 | htop = 1.1385e-5 * (1255/tksea+0.05)/refsea;
96 | ref = refsea * e0sea * ((htop-hsta)/htop)^4;
97 | end;
98 | %%%%%%%%% end tropo.m %%%%%%%%%%%%%%%%%%%
99 |
--------------------------------------------------------------------------------