RxCS Examples – all
Table of contents:
- Introduction
- 1. Examples – Signal generators
- 2. Examples – Acquisition systems
- 3. Examples – Dictionaries
- 4. Examples – Signal Reconstruction
- 5. Examples – Signal Analysis
Introduction
This example shows how to use a Random Multitone Signal Generator (RMSG) module. RMSG is a powerful module which is able to generate random signals, both sparse and dense in the frequency domain. User have broad control over parameters of generated signals. These parameters are:
- Time length of signals
- Representation sampling frequency of signals
- Signal spectrum resolution
- Spectrum content: amplitudes, phases and frequency positions may be given directly or chosen randomly
- Power of the signals
- Noise level in the signals
- The number of signals to be generated
Interface of every module in the RxCS toolbox is based on Python data structures called dictionaries. You can read more about dictionaries on the official Python documentation page . RMSG is not different, it is configured by an input dictionary which contains all the needed parameters of signals to be generated. When computations are done, the generator returns a dictionary with generated signals and all the parameters of the signals.
Data in dictionaries is accessed through keys. Parameters of signals to be generated must be associated with correct keys. You can find list of keys in the header of every module.
Signal generators-example #1: Let us generate a multitone signal
Let us walk through an illustrative example of usage of the random multitone signal generator. You can find a file with the example in examples/signals in the RxCS package or directly on GitHub .
Firstly, a configuration dictionary dSigConf is created. Two basic configurations for all signals are the time length and the signals’ representation sampling frequency. In this example these are set to 1ms and 1MHz respectively:
40: # Start the dictionary with signal generator configuration
41: dSigConf = {}
42:
43: # Time of the signal is 1 ms
44: dSigConf['tS'] = 1e-3
45:
46: # The signal representation sampling frequency is 1 MHz
47: dSigConf['fR'] = 1e6
48:
The lines below set up parameters for the spectrum of signals: the highest possible frequency of a tone and the signals’ spectrum resolution. The highest frequency is set to 10kHz , so the oversampling ratio is 50 because of the previously set representation sampling frequency. The spectrum resolution parameter is set to 1kHz , which means that any random tone in the signal can have a frequency from a set as follows: {1kHz, 2kHz, … 10kHz}.
49: # The highest possible frequency in the signal is 10 kHz
50: dSigConf['fMax'] = 10e3
51:
52: # The signal spectrum resolution is 1 kHz
53: dSigConf['fRes'] = 1e3
54:
There is a space for ten tones in the spectrum of signals to be generated, yet the lines below tells the generator to put only one tone into every signal:
57: # The number of tones
58: dSigConf['nTones'] = 1
59:
The generator have a possibility to regulate the power of signals and add a noise to them. The lines below set up the power of signals to 1W and add a noise so that signal-to-noise ratio is 5dB:
62: # The power of the signal
63: dSigConf['iP'] = 1
64:
65: # The noise added to the signal
66: dSigConf['iSNR'] = 5
67:
The line below sets up the generator so that it will generate only one signal:
70: # The number of signals to be generated
71: dSigConf['nSigPack'] = 1
72:
Here the generator is started. The function has one argument which is the configuration dictionary and it returns one dictionary with the generated signals:
75: # Run the multitone signal generator
76: dSig = rxcs.sig.sigRandMult.main(dSigConf)
77:
The generator returns a matrix with generated signals (one signal in a row). The matrix is accessible by mSig key. The lines below extract the generated signal from the first row in the matrix:
79: # Get the generated signal
80: mSig = dSig['mSig']
81: vSig = mSig[0, :]
82:
It is worth to note that the generator returns a vector with time samples of the signal:
86: # Get the time vector of the signal
87: vTSig = dSig['vTSig']
88:
We will not analyze rest of the code in the file, it simply analyzes the signal with FFT and plots it in the frequency and in the time domains.
Ok, let’s run it…
Let us run the example and observe its output. When in the examples/signals directory please run the example:
$ python sig_RMSG_ex0.py
If your console supports colors you will see a nice colored output (image below). Every module from RxCS toolbox reports its name, prints out the parameters it was given and reports execution time. Please note that in the case below the execution time equal to 0.00 means that the real execution time was less then 10ms . To suppress any module from being talkative set a key bVerbose to zero in module’s configuration dictionary.
The script plots the generated signal in the frequency and the time domains (images below). Please note that the plotted signal is a bit different in every run of the script.
If you have any questions about the example please write to jap [a with a tail] irfducs _dot_ org .
1.2 Signal generators-example #2: A more complicated multitone signal
Let us walk through another example of using the random multitone signal generator. You can find a file with the example in examples/signals in the RxCS package or directly on GitHub .
In the previous example the generator did produce a signal with one fully random tone in it. But this example is a bit more complicated – in settings for the generator there is a list of frequencies and amplitudes (but not phases!) of tones which must be always present in produced signals. Phases of these tones are not given, the generator will randomly choose them. Beside of these tones, the generator will add three completely random additional tones to the spectrum.
As in the previous example a configuration dictionary dSigConf is created and basic time/frequency settings are given:
54: # Start the dictionary with signal generator configuration
55: dSigConf = {}
56:
57: # Time of the signal is 1 ms
58: dSigConf['tS'] = 1e-3
59:
60: # The signal representation sampling frequency is 100 kHz
61: dSigConf['fR'] = 1e5
62:
Below we give basic parameters of the spectrum. The max frequency of a tone in the spectrum is 40 kHz, the spectrum resolution is 1kHz. Hence. there is a space for 40 tones in the whole spectrum:
63: # The highest possible frequency in the signal is 40 kHz
64: dSigConf['fMax'] = 40e3
65:
66: # The signal spectrum resolution is 1 kHz
67: dSigConf['fRes'] = 1e3
68:
Here is something new comparing to the previous example. Fields vFrqs, vAmps, vPhs in the configuration dictionary are Numpy vectors with frequencies, amplitudes and phases of tones with the parameters given explicitly. In this example the frequencies and amplitudes are given directly, the amplitude of 2kHz tone equals 1, the amplitude of 3kHz tone equals 2 and the amplitude of 4kHz tone equals 3. The vector with phases has only numpy.nan values, which is an info for the generator that the phases should be chosen randomly:
71: # Vector with given frequencies
72: dSigConf['vFrqs'] = np.array([2e3, 3e3, 4e3])
73:
74: # Vector with given amplitudes
75: dSigConf['vAmps'] = np.array([1, 2, 3])
76:
77: # Vector with given phases
78: dSigConf['vPhs'] = np.array([np.nan, np.nan, np.nan])
Beside of the tones given explicitly, the generator will add three completely random tones to the spectrum:
82: # The number of additional tones
83: dSigConf['nTones'] = 3
Here the boundaries for random amplitudes and phases are given. Lines 88-90 set boundaries for the random amplitudes for three additional random tones, the amplitudes will be randomly selected from the set {0.1, 0.2, 0.3, …, 1.0}. Lines 93-95 set boundaries for the random phases (the values of phases must be given in degrees). Random phases for the three additional tones and for the three tones with frequencies given explicitly will be randomly selected from the set {1, 2, 3, …, 90} degress. The code is below:
85: # Amplitude and phase parameters of additional tones:
86:
87: # Amplitude
88: dSigConf['iMinAmp'] = 0.1 # Minimum amplitude
89: dSigConf['iGraAmp'] = 0.1 # Gradation of amplitude
90: dSigConf['iMaxAmp'] = 1.0 # Maximum amplitude
91:
92: # Phase:
93: dSigConf['iMinPhs'] = 0 # Minimum phase of additional tones
94: dSigConf['iGraPhs'] = 1 # Gradation of phase of additional tones
95: dSigConf['iMaxPhs'] = 90 # Maximum phase of additional tones
As in the previous example, the line below sets up the generator so that it will generate only one signal:
99: # The number of signals to be generated
100: dSigConf['nSigPack'] = 1
And now the generator is started with the configuration given above:
103: # Run the multtone signal generator
104: dSig = rxcs.sig.sigRandMult.main(dSigConf)
Ok, let’s run it…
Let us run the example. In the examples/signals directory please type:
$ python sig_RMSG_ex1.py
If your console supports colors you will see a colored output with all the parameters of the generator:
The script plots the generated signal in the frequency domain. You can clearly see three frequencies on 2 kHz, 3 kHz and 4 kHz and three additional tones. Obviously, every time the example is run the three additional tones are placed differently and have different amplitudes, however the amplitudes are always within the boundaries set in lines 88-90.
If you have any questions about the example please write to jap [a with a tail] irfducs _dot_ org .
2.1 Acquisition systems-example #1: Nonuniform sampling
The previous examples showed how to generate signals, the current example shows how to acquire signals. This example shows how to use a pseudorandom nonuniform sampler with ANGIE sampling scheme. You can read more about the ANGIE sampling scheme in the paper “Generation and Analysis of Constrained Random Sampling Patterns” which is avaialble on arXiv .
You can find a file with the example in examples/acquisition in the RxCS package or directly on GitHub .
Configuration of a signal generator.
Multitone Random Signal Generator (MRSG) is used to generate the signal which will be sampled. The lines 40-74, which are shown below, set up the generator parameters. It is a sparse signal with three random tones in the spectrum. If you do not understand the lines below please go through the examples of using MRSG which are above here and here .
39: # Start the dictionary with signal generator configuration
40: dSigConf = {}
41:
42: # Time of the signal is 1 ms
43: dSigConf['tS'] = 1e-3
44:
45: # The signal representation sampling frequency is 1 MHz
46: dSigConf['fR'] = 1e6
47:
48: # The highest possible frequency in the signal is 10 kHz
49: dSigConf['fMax'] = 10e3
50:
51: # The signal spectrum resolution is 1 kHz
52: dSigConf['fRes'] = 1e3
53:
54: # - - - - - - - - - - - - - - - -
55:
56: # The number of tones
57: dSigConf['nTones'] = 3
58:
59: # - - - - - - - - - - - - - - - -
60:
61: # The number of signals to be generated
62: dSigConf['nSigPack'] = 1
Configuration of a sampler.
Note: if you are not familiar with the idea of random sampling patterns please refer to our paper Generation and Analysis of Constrained Random Sampling Patterns .
Lines 68-74 in the example configure the nonuniform sampler. Line 71 sets the sampling grid period to 1 us, line 74 sets the average sampling frequency to 8 kHz. Time length of random sampling patterns does not have to be given, the generator sets the time length automatically – it equals time length of the signals to be sampled.
Minimum interval between sampling points is not set, so the generator sets it to the default value which equals grid period (1 us in this case). Maximum interval between sampling points is not set either, the default value is infinite, which in practice means that there is no requirement for maximum interval between sampling points.
67: # Start the dictionary with signal acquisition configuration
68: dAcqConf = {}
69:
70: # The sampling grid period
71: dAcqConf['Tg'] = 1e-6
72:
73: # The average sampling frequency
74: dAcqConf['fSamp'] = 8e3
Now all the settings for the signal generator and the signal sampler are in place. Line 78 starts the signal generator module, line 79 starts the sampler module. The generator module takes one argument: the configuration dictionary. The sampler module takes always two arguments – the configuration dictionary, and a dictionary with signals to be sampled. The signal sampler returns a dictionary (dObSig) with the observed signals and their parameters:
77: # Run the multitone signal generator and the sampler
78: dSig = rxcs.sig.sigRandMult.main(dSigConf) # the generator
79: dObSig = rxcs.acq.nonuniANGIE.main(dAcqConf, dSig) # the sampler
Lines 85-118 plots the original and the sampled signal in the time domain. Let us take a look on lines 90-91 which extracts the observed signal from the dictionary returned by the signal sampler. Line 90 takes a matrix (mObSig) with observed signals from the dictionary dObSig. The matrix contains observed signals row-wise: one signal in every row. The number of rows in the matrix equals the number of signals in the dictionary (dSig) with signals to be sampled given to the sampler. Because line 62 set the generator so that it produced only one signal, there is only one row in the matrix mObSig. Line 91 takes the first row from the matrix and puts it to a vector vObSig:
89: # Get the observed signal and sampling moments
90: mObSig = dObSig['mObSig'] # the observed signal
91: vObSig = mObSig[0, :]
Finally, let us take a look on lines 128-134. These lines show how to use observation matrices which are returned by the sampler. An observation matrix is a matrix which is a mathematical representation of the process of sampling. An observed signal is a dot product of an original signal and an observation matrix. The dictionary returned by the generator contains a 3D matrix with observation matrices for signals being sampled (one observation matrix p. page). Line 128 gets the 3D matrix with observation matrices. Line 131 takes the first observation matrix, the one applied to the first and the only signal in the example. Line 134 applies the matrix onto the original signal being sampled and creates an observed signal vObSigPhi.
122: # -----------------------------------------------------------------
123: # APPENDIX:
124: # This part is to show how to use the observation matrix, if it is needed
125: # (for example in compressed sensing systems)
126:
127: # Get a 3D matrix with observation matrices
128: m3Phi = dObSig['m3Phi']
129:
130: # Get the first observation matrix (1st page of the m3Phi matrix)
131: mPhi = m3Phi[0, : ,:]
132:
133: # Sample the signal using the observation matrix
134: vObSigPhi = np.dot(mPhi, vSig)
Ok, let’s run it…
Let us run the example. In the examples/acquistion directory please type:
$ python samp_RMSG_ANGIE_ex0.py
Console output from the exmple is as below. Clearly an output from the signal generator and from the signal sampler can be observed:
The example plots the original signal and the sampling points in the time domain. Furthermore, the sampling pattern is plot:
If you have any questions about the example please write to jap [a with a tail] irfducs _dot_ org .
3.1 Dictionaries-example #1: Small IDFT dictionary
The idea of a dictionary is very important in compressed sensing. A dictionary transforms signal from one domain/domains into another. A classic example is an IDFT dictionary which transforms signal from the frequency domain into the time domain. There is a possibility to generate IDFT dictionary using a module available in RxCS package. An example of using the module is given below.
IDFT dictionary which is generated by the module is a row-wise matrix: one row of a dictionary matrix corresponds to one frequency of a tone in the spectrum. IDFT dictionary is frequency symmetrical – there are positive-frequency tones as well as negative-frequency tones in the dictionary.
Configuration of a dictionary:
Here we set up the basic time domain parameters of the dictionary. Time covered by the dictionary is 1 ms, the signal representation frequency is 40 kHz:
9: # Generate settings for the IDFT dictionary
10:
11: # Start the configuration dictionary
12: dCSConf = {}
13:
14: # Time of the dictionary is 1 ms
15: dCSConf['tS'] = 1e-3
16:
17: # The signal representation sampling frequency is 40 kHz
18: dCSConf['fR'] = 4e4
The lines below set up the frequency domain parameters. There are ten tones in the spectrum covered by the dictionary, separation between tones equals 1 kHz:
20: # The frequency separation between tones
21: dCSConf['fDelta'] = 1e3
22:
23: # The number of tones in the dictionary
24: dCSConf['nTones'] = 10
Generation of the dictionary:
Here the IDFT dictionary is generated using the above configuration. The dictionary generator returns two values – dictionary matrix mIDFT and a Python dictionary dDict with parameters of the mIDFT. In line 31 a vector with time moments represented by the dictionary is taken from the Python dictionary dDict.
27: # Generate the IDFT dictionary
28: (mIDFT, dDict) = rxcs.cs.dict.IDFToNoDC.main(dCSConf)
29:
30: # Get the signal time vector from the dictionary
31: vT = dDict['vT']
Generation of the signal:
Here a signal is generated using the IDFT dictionary. Firstly, vector with frequency coefficients is created (lines 37-39). Spectrum of the dictionary contains ten tones, so there are twenty rows in the dictionary – ten for the positive and ten for the negative frequencies. First row of the dictionary (indexed 0) corresponds to the last row (indexed 19), the second row (indexed 1) corresponds to the last but one row (indexed 18) and so on. To generate real signals the coefficients of the corresponding rows must be complex conjugate to each other. Lines 37-39 sets up a vector with two non-zeros coefficients. The non-zero coefficients correspond to the tones of frequency of 1 kHz in the dictionary. There is no complex part of coefficients, so the signal is composed of a non-shifted cosine tone. Line 42 generates the signal, the signal is a multiplication product of the vector with signal coefficients and the dictionary matrix. Due to numerical inaccuracies it is good to take only real part of the product (line 42). Line 43 reshapes the signal vector to a one-dimensional Numpy vector:
34: # Generate the signal using the dictionary
35:
36: # Vector with Fourier coefficients
37: vFcoef = np.zeros((1,20)).astype(complex)
38: vFcoef[0, 0] = 1
39: vFcoef[0, 19] = 1
40:
41: # Generate a signal and change its shape to a single vector
42: vSig = np.real(np.dot(vFcoef,mIDFT))
43: vSig.shape = (vSig.size,)
Ok, let’s run it…
Let us run the example. In the examples/dictionaries directory please type:
$ python dict_IDFT_ex0.py
Console output from the example is as below. The dictionary modules prints all its parameters:
The example plots the generated signal. As expected, the signal consists of a single cosine tone:
If you have any questions about the example please write to jap [a with a tail] irfducs _dot_ org .
3.2 Dictionaries-example #2: Big IDFT dictionary
9: # Generate settings for the IDFT dictionary
10:
11: # Start the configuration dictionary
12: dCSConf = {}
13:
14: # Time of the dictionary is 1 ms
15: dCSConf['tS'] = 1e-3
16:
17: # Time start is 10 us
18: dCSConf['tStart'] = 10e-6
19:
20: # The signal representation sampling frequency is 1 MHz
21: dCSConf['fR'] = 1e6
23: # The frequency separation between tones
24: dCSConf['fDelta'] = 1e3
25:
26: # The number of tones in the dictionary
27: dCSConf['nTones'] = 100
30: # Generate the IDFT dictionary
31: (mIDFT, dDict) = rxcs.cs.dict.IDFToNoDC.main(dCSConf)
34: # Generate the signal using the dictionary
35:
36: # Vector with Fourier coefficients
37: vFcoef = np.zeros((1,200)).astype(complex)
38: vFcoef[0, 1] = -1j
39: vFcoef[0, 18] = 1j
40:
41: # Generate a signal and change its shape to a signle vector
42: vSig = np.real(np.dot(vFcoef,mIDFT))
43: vSig.shape = (vSig.size,)
44:
45: # Get the signal time vector
46: vT = dDict['vT']
Ok, let’s run it…
$ python dict_IDFT_ex1.py
4.1 Signal reconstruction-example #1: Sparse signal made of cosine tones + L1 minimization
In this example a L1 reconstruction module which exists in RxCS is explained. For simplicity, a simple dictionary which consists of cosine signals is used in this example. The sampled signal occupies spectrum of up to 20 Hz. There are two tones present in the spectrum – 3Hz tone and 7Hz tone. Signal is nonuniformly sampled and reconstructed using L1 minimization (regularized regression).
The reconstruction module uses CVXOPT software to run. CVXOPT is a free software package for convex optimization based on the Python programming language. You can read more and download CVXOPT on its home page .
You can find a file with the example in examples/reconstruction in the RxCS package or directly on GitHub .
Dictionary:
At the beginning, a dictionary used in the script is created. The dictionary consists of 20 cosine tones (1-20Hz), each tone is separated with 1 Hz frequency. There are 100 signal representation time samples in the signal. Time represented by the dictionary is 1 s, since 1/1Hz = 1s.
40: # Settings for the dictionary
41: iTSamp = 100 # The number of signal representation time samples
42: iTones = 20 # The number of tones in the dictionary
43: fSep = 1 # Tone frequency separation [Hz]
44:
45: # Run the dictionary generator
46: (vT, mDict) = _CosDict(iTSamp, iTones, fSep)
Lines 201 – 228 implement the dictionary generation function. The dictionary is generated in a loop (line 223), tone by tone.
201: def _CosDict(iTSamp, iTones, fSep):
212: # ---------------------------------------------------------------------
213: # Generate the time vector
214: tS = 1 / fSep # Time of the signal
215: vT = tS/iTSamp*np.arange(iTSamp)
216:
217: # ---------------------------------------------------------------------
218: # Allocate the dictionary matrix
219: mDict = np.zeros((iTSamp,iTones))
220:
221: # ---------------------------------------------------------------------
222: # Generate the dictionary matrix - loop over all tones
223: for inxTone in np.arange(iTones):
224: fFreq = (inxTone + 1)*fSep # Frequency of a tone
225: vTone = np.cos(2*np.pi*fFreq*vT) # Create a tone
226: mDict[:,inxTone] = vTone # Put the tone into the matrix
227:
228: return (vT, mDict)
Signal generation:
Here the signal is generated. Vector vX contains coefficients of the signal for the generated dictionary. Element n-th contains an amplitude of n-th frequency of a generated signal. Two tones are present in the signal, 3Hz tone with amplitude equal to 1 and 7 Hz with amplitude equal to 2, therefore third and seventh entry of the coefficients vector vX are equal to 1 and 2 respectively. Finally, the previously generated dictionary is multiplied with vector vX to generate the signal.
56: # Generate the signal
57:
58: (iRows, iCols) = mDict.shape
59: vX = np.zeros((iCols, 1)) # Here we define signal coefficients
60: vX[2] = 1 # 3 Hz - amplitude = 1
61: vX[6] = 2 # 7 Hz - amplitude = 2
62:
63: # Here we generate the signal using the vector with coefficients and
64: # the dictionary
65: vSig = np.dot(mDict, vX)
Signal sampling:
Here the signal is randomly sampled in a naive way. The observed signal consists of fifteen samples observed in one second, hence the sampling frequency equals 15 Hz, which refers to oversampling ratio of OSR = 0.375 .
Lines 81 – 84 generate a random list with indices of signal samples which will be observed.
81: # Draw indices of signal representation samples which will be acquired
82: vSampInx = np.random.permutation(iTSamp)
83: vSampInx = vSampInx[0:nSamps]
84: vSampInx.sort()
Lines 86 – 94 generates an observation matrix. The observation matrix is a diagonal matrix with removed rows. The rows which are left correspond to the observed samples of the signal. The observation matrix is applied on the signal in line 94.
86: # Generate the observation matrix (nonuniform sampling)
87: inxRow = 0
88: mPhi = np.zeros((nSamps, iTSamp))
89: for inxCol in vSampInx:
90: mPhi[inxRow, inxCol] = 1
91: inxRow = inxRow + 1
92:
93: # Sample the signal using the generated observation matrix
94: vObSig = np.dot(mPhi, vSig)
Here the Theta matrix is created. Theta matrix is a multiplication of the measurement matrix and the dictionary matrix.
99: # Construct the theta matrix
100: #
101: # Theta matrix = observation matrix * dictionary matrix
102: #
103: mTheta = np.dot(mPhi, mDict)
Signal reconstruction:
Python dictionary which contains data and configuration for the regularized regression reconstruction module must be created.
The module is able to reconstruct multiple signals with one call, there should be one Theta matrix and one observations vector p. signal. Therefore matrix with Theta matrices (m3Theta) is 3-dimensional – one Theta matrix p. matrix page. Similarly, observed signal constitute a matrix (mObSig) – one column p. signal. In this example the matrix should reconstruct only one signal, the matrix with Theta matrices is in fact a 2-dimensional matrix, and matrix with observed signal is a vector.
Parameter bComplex should be set to 1, if the Theta matrix contains complex values. Parameter iK is a weight of the denoising part in the regularized regression equation. It should be adjusted to a current level of noise. Look inside the cvxoptL1.py module file for more info.
Lines 105 – 112 set up the python dictionary which is an input to the reconstruction module:
105: # Generate the input dictionary for the L1 reconstruction module
106: #
107: dCS = {} # Initialize the dictionary
108: dCS['m3Theta'] = mTheta # Add the Theta matrix
109: dCS['iK'] = 0.2 # Add the 'k' parameter
110: dCS['mObSig'] = vObSig # Add observed signal
111: dCS['bComplex'] = 0 # Add info that problem does not contain
112: # complex numbers
Here we run the reconstruction module with the generated python dictionary as an input:
162: mCoeff = rxcs.cs.cvxoptL1.main(dCS)
The module reconstructed only one signal, therefore the returned matrix with reconstructed coefficients mCoeff contains one column:
172: vCoeff = mCoeff[:, 0]
Reconstructed signal is a product of the dictionary matrix and the reconstructed vector with coefficients:
176: vSigRecon = np.dot(mDict, vCoeff)
It is always a good practice to remove imaginary part of the signal vector, which may be present due to reconstruction and numerical inaccuracies:
181: vSigRecon = vSigRecon.real
Ok, let’s run it…
Let us run the example. In the examples/dictionaries directory please type:
$ python L1recon_ex0.py
Console output from the example is as below:
The example prints the original signal, the reconstructed signal and the sampling points:
5.1 Signal Analysis-example #1: SNR of the reconstructed signal
10: # Generate signals using the random multitone signal generator
11:
12: dSigConf = {} # Init dict. wth signal generator configuration
13: dSigConf['tS'] = 1e-3 # Time of the signal
14: dSigConf['fR'] = 1e6 # The signal representation sampling frequency
15: dSigConf['fMax'] = 40e3 # The highest possible frequency in the signal
16: dSigConf['fRes'] = 1e3 # The signal spectrum resolution is 1 kHz
17:
18: dSigConf['nTones'] = 2 # The number of tones
19:
20: dSigConf['nSigPack'] = 1 # The number of signals to be generated
22: # Run the multitone signal generator
23: dSig = rxcs.sig.sigRandMult.main(dSigConf)
24: vSig = dSig['mSig'][0, :]
25: vT = dSig['vTSig']
30: dAcqConf = {} # Init dict. with sampler configuration
31: dAcqConf['Tg'] = 1e-6 # The sampling grid period
32: dAcqConf['fSamp'] = 40e3 # The average sampling frequency
33:
34: # Run the sampler
35: dObSig = rxcs.acq.nonuniANGIE.main(dAcqConf, dSig)
36: vObSig = dObSig['mObSig'][0,:]
50: # Generate the dictionary matrix
51: dCSConf = {}
52: dCSConf['tS'] = 1e-3 # Time of the dictionary is 1 ms
53: dCSConf['fR'] = 1e6 # The signal representation sampling frequency
54: dCSConf['fDelta'] = 1e3 # The frequency separation between tones
55: dCSConf['nTones'] = 40 # The number of tones in the dictionary
56:
57: # Generate the IDFT dictionary
58: (mDict, dDict) = rxcs.cs.dict.IDFToNoDC.main(dCSConf)
61: # Compute the Theta matrix
62: m3Phi = dObSig['m3Phi'] # Get the observation matrix from the sampler
63: mPhi = m3Phi[0, :, :] # ^
64:
65: mTheta = np.dot(mPhi, mDict.)
70: dCS = {} # Initialize the dictionary
71: dCS['m3Theta'] = mTheta # Add the Theta matrix
72: dCS['iK'] = 0.5 # Add the 'k' parameter
73: dCS['mObSig'] = vObSig # Add observed signal
74: dCS['bComplex'] = 1 # Problem contains complex numbers
75:
76: # Run the L1 minimization - find the signal coefficients
77: mCoeff = rxcs.cs.cvxoptL1.main(dCS)
79: # Reconstruct the signal using the found signal coefficients and the
80: # dictionary
81: vCoeff = mCoeff[:, 0]
82: vSigRecon = np.dot(mDict.T, vCoeff).real
83:
84: # Put the reconstructed signal into a 2D matrix, and put the matrix into
85: # a dictionary
86: mSig = np.zeros((vSigRecon.size,1))
87: mSig[:,0] = vSigRecon
88: dSigRecon = {}
89: dSigRecon['mSig'] = mSig.T
91: # ---------------------------------------------------------------------
92: # Measure the SNR of the reconstruction
93: dAnaConf = {} # Initialize dictionary with configuration for
94: # the system analysis
95:
96: dAnaConf['iSNRSuccess'] = 15 # if SNR of the reconstruction > 15dB
97: # then the reconstrucion is successfull
98: dAna = rxcs.ana.SNR.main(dSig, dSigRecon, {}, dAnaConf)
Ok, let’s run it…
$ python SNR_ex0.py
Page last updated: 8h September 2014