Skip to content
This repository was archived by the owner on Apr 13, 2021. It is now read-only.

Commit c024e03

Browse files
author
Pasi Miettinen
committed
Merge branch 'i149-iqgen-snr-control' of https://github.com/valeri-atamaniouk/peregrine into i115-glonass-acq
2 parents a7f9925 + db4eb28 commit c024e03

28 files changed

+2255
-463
lines changed

peregrine/include/glo_ca_code.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# -*- coding: utf-8 -*-
2+
#!/usr/bin/env python
3+
4+
# Copyright (C) 2016 Swift Navigation Inc.
5+
#
6+
# Contact: Pasi Miettinen <pasi.miettinen@exafore.com>
7+
# This source is subject to the license found in the file 'LICENSE' which must
8+
# be be distributed together with this source. All other rights reserved.
9+
#
10+
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
11+
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
12+
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
13+
14+
import types
15+
import sys
16+
import numpy as np
17+
18+
19+
def generate_glo_ca_code():
20+
"""
21+
Function generates PRN sequence for Glonass.
22+
All GLONASS satellites use the same C/A-code,
23+
generated by a 9-bit shift register.
24+
"""
25+
code = '111111111'
26+
output = np.zeros(511, np.int8)
27+
for i in xrange(len(output)):
28+
if '0' == code[6]:
29+
output[i] = 1
30+
else:
31+
output[i] = -1
32+
if int(code[4]) ^ int(code[8]):
33+
code = '1' + code[:8]
34+
else:
35+
code = '0' + code[:8]
36+
return output
37+
38+
39+
def readonly(value):
40+
return property(lambda self: value)
41+
42+
43+
class glo_ca_code(types.ModuleType):
44+
"""
45+
Implement module level variable as readonly by imitating module with
46+
this class.
47+
"""
48+
49+
value = readonly(generate_glo_ca_code())
50+
51+
def __dir__(self):
52+
return ['__doc__', '__name__', 'value']
53+
54+
tmp = glo_ca_code(__name__)
55+
tmp.__doc__ = """
56+
PR ranging code is a sequence of maximum length of shift register with a
57+
period 1 millisecond and bit rate 511 kbps. PR ranging code is sampled at
58+
the output of 7th stage of the 9-stage shift register. The initialization
59+
vector to generate this sequence is (111111111). The first character of the
60+
PR ranging code is the first character in the group 111111100, and it is
61+
repeated every 1 millisecond. The generating polynomial, which corresponds
62+
to the 9-stage shift register is G(X) = 1 + X^5 + X^9
63+
64+
Function outputs the bitstream as str and time advances from left to right
65+
output[0] ... output[510]
66+
0ms ----------> 1ms
67+
68+
In the sequence '0' is represented as '1', 1 as -1
69+
"""
70+
sys.modules[__name__] = tmp

peregrine/iqgen/bits/amplitude_base.py

Lines changed: 193 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,130 @@
1414
1515
"""
1616

17+
import numpy
18+
19+
20+
class NoiseParameters(object):
21+
'''
22+
Container class for holding noise generation parameters.
23+
'''
24+
25+
def __init__(self, samplingFreqHz, noiseSigma):
26+
'''
27+
Parameters
28+
----------
29+
samplingFreqHz : float or long
30+
Sampling frequency in Hz
31+
noiseSigma : float
32+
Noise Sigma value
33+
'''
34+
super(NoiseParameters, self).__init__()
35+
self.samplingFreqHz = samplingFreqHz
36+
self.noiseSigma = noiseSigma
37+
38+
# Compute coefficient for 1ms integration
39+
self.signalK = noiseSigma * 2. * \
40+
numpy.sqrt(1000000. / float(samplingFreqHz))
41+
42+
self.freqTimeTau = 1e-6 * float(samplingFreqHz)
43+
44+
def getSamplingFreqHz(self):
45+
'''
46+
Get sampling frequency.
47+
48+
Returns
49+
-------
50+
float or long
51+
Sampling frequency in Hz
52+
'''
53+
return self.samplingFreqHz
54+
55+
def getNoiseSigma(self):
56+
'''
57+
Get noise Sigma.
58+
59+
Returns
60+
-------
61+
float
62+
Noise sigma value
63+
'''
64+
return self.noiseSigma
65+
66+
def getFreqTimesTau(self):
67+
'''
68+
Get sampling integration parameter.
69+
70+
Returns
71+
-------
72+
float
73+
Integration parameter of the sampling frequency times integration time.
74+
'''
75+
return self.freqTimeTau
76+
77+
def getSignalK(self):
78+
'''
79+
Get amplification coefficient for SNR at 0 dB.
80+
81+
Returns
82+
-------
83+
float
84+
Signal amplification coefficient for SNR at 0 dB.
85+
'''
86+
return self.signalK
87+
1788

1889
class AmplitudeBase(object):
1990
'''
2091
Amplitude control for a signal source.
92+
93+
Attributes
94+
----------
95+
UNITS_AMPLITUDE : string
96+
Type of object for measuring signal in amplitude. SNR is dependent on
97+
amplitude square.
98+
UNITS_POWER : string
99+
Type of object for measuring signal in power. SNR is linearly dependent on
100+
power.
101+
UNITS_SNR : string
102+
Type of object for measuring signal in SNR.
103+
UNITS_SNR_DB : string
104+
Type of object for measuring signal in SNR dB.
105+
21106
'''
22107

23-
def __init__(self):
108+
UNITS_AMPLITUDE = 'AMP'
109+
UNITS_POWER = 'PWR'
110+
UNITS_SNR = 'SNR'
111+
UNITS_SNR_DB = 'SNR_DB'
112+
113+
def __init__(self, units):
24114
'''
25115
Constructs base object for amplitude control.
116+
117+
Parameters
118+
----------
119+
units : string
120+
Object units. Can be one of the supported values:
121+
- AmplitudeBase::UNITS_AMPLITUDE -- Amplitude units
122+
- AmplitudeBase::UNITS_SNR_DB -- SNR in dB
123+
- AmplitudeBase::UNITS_SNR -- SNR
124+
- AmplitudeBase::UNITS_POWER -- Power units
26125
'''
27126
super(AmplitudeBase, self).__init__()
127+
self.units = units
128+
129+
def getUnits(self):
130+
'''
131+
Provides access to units.
132+
133+
Returns
134+
-------
135+
string
136+
Amplitude units
137+
'''
138+
return self.units
28139

29-
def applyAmplitude(self, signal, userTimeAll_s):
140+
def applyAmplitude(self, signal, userTimeAll_s, noiseParams=None):
30141
'''
31142
Applies amplitude modulation to signal.
32143
@@ -37,6 +148,8 @@ def applyAmplitude(self, signal, userTimeAll_s):
37148
[-1; +1]. This vector is modified in place.
38149
userTimeAll_s : numpy.ndarray
39150
Sample time vector. Each element defines sample time in seconds.
151+
noiseParams : NoiseParameters
152+
Noise parameters to adjust signal amplitude level.
40153
41154
Returns
42155
-------
@@ -45,13 +158,88 @@ def applyAmplitude(self, signal, userTimeAll_s):
45158
'''
46159
raise NotImplementedError()
47160

48-
def computeMeanPower(self):
161+
def computeSNR(self, noiseParams):
49162
'''
50-
Computes mean signal power.
163+
Computes signal to noise ratio in dB.
164+
165+
Parameters
166+
----------
167+
noiseParams : NoiseParameters
168+
Noise parameter container
51169
52170
Returns
53171
-------
54172
float
55-
Mean signal power for the configured amplitude
173+
SNR in dB
56174
'''
57175
raise NotImplementedError()
176+
177+
@staticmethod
178+
def convertUnits2SNR(value, units, noiseParams):
179+
'''
180+
Converts signal units to SNR in dB
181+
182+
Parameters
183+
----------
184+
noiseParams : NoiseParameters
185+
Noise parameter container
186+
187+
Returns
188+
-------
189+
float
190+
SNR in dB
191+
'''
192+
193+
noiseSigma = noiseParams.getNoiseSigma()
194+
freqTimesTau = noiseParams.getFreqTimesTau()
195+
196+
if units == AmplitudeBase.UNITS_AMPLITUDE:
197+
power = numpy.square(value)
198+
snr = freqTimesTau * power / (4. * noiseSigma * noiseSigma)
199+
snrDb = 10 * numpy.log10(snr)
200+
elif units == AmplitudeBase.UNITS_POWER:
201+
power = value
202+
snr = freqTimesTau * power / (4. * noiseSigma * noiseSigma)
203+
snrDb = 10 * numpy.log10(snr)
204+
elif units == AmplitudeBase.UNITS_SNR:
205+
snr = value
206+
snrDb = 10 * numpy.log10(snr)
207+
elif units == AmplitudeBase.UNITS_SNR_DB:
208+
snrDb = value
209+
else:
210+
assert False
211+
return snrDb
212+
213+
@staticmethod
214+
def convertUnits2Amp(value, units, noiseParams):
215+
'''
216+
Converts signal units to amplitude
217+
218+
Parameters
219+
----------
220+
noiseParams : NoiseParameters
221+
Noise parameter container
222+
223+
Returns
224+
-------
225+
float
226+
SNR in dB
227+
'''
228+
229+
noiseSigma = noiseParams.getNoiseSigma()
230+
freqTimesTau = noiseParams.getFreqTimesTau()
231+
232+
if units == AmplitudeBase.UNITS_AMPLITUDE:
233+
amp = value
234+
elif units == AmplitudeBase.UNITS_POWER:
235+
amp = numpy.sqrt(value)
236+
elif units == AmplitudeBase.UNITS_SNR:
237+
snr = value
238+
amp = numpy.sqrt(4. * snr / freqTimesTau) * noiseSigma
239+
elif units == AmplitudeBase.UNITS_SNR_DB:
240+
snrDb = value
241+
snr = 10. ** (0.1 * snrDb)
242+
amp = numpy.sqrt(4. * snr / freqTimesTau) * noiseSigma
243+
else:
244+
assert False
245+
return amp

peregrine/iqgen/bits/amplitude_factory.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,29 @@ def fromMapForm(self, data):
4545
raise ValueError("Invalid object type")
4646

4747
def __PolyAmplitude_ToMap(self, obj):
48-
data = {'type': 'PolyAmplitude', 'coeffs': obj.coeffs}
48+
data = {'type': 'PolyAmplitude',
49+
'coeffs': obj.coeffs,
50+
'units': obj.units}
4951
return data
5052

5153
def __SineAmplitude_ToMap(self, obj):
5254
data = {'type': 'SineAmplitude',
5355
'initial': obj.initial,
5456
'amplitude': obj.amplitude,
55-
'period': obj.period_s}
57+
'period': obj.period_s,
58+
'units': obj.units}
5659
return data
5760

5861
def __MapTo_PolyAmplitude(self, data):
5962
coeffs = data['coeffs']
60-
return PolyAmplitude(coeffs)
63+
units = data['units']
64+
return PolyAmplitude(units, coeffs)
6165

6266
def __MapTo_SineAmplitude(self, data):
6367
initial = data['initial']
6468
amplitude = data['amplitude']
6569
period = data['period']
66-
return SineAmplitude(initial, amplitude, period)
70+
units = data['units']
71+
return SineAmplitude(units, initial, amplitude, period)
6772

6873
factoryObject = ObjectFactory()

0 commit comments

Comments
 (0)