]> Creatis software - CreaPhase.git/blob - octave_packages/communications-1.1.1/qaskdeco.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / communications-1.1.1 / qaskdeco.m
1 ## Copyright (C) 2003 David Bateman
2 ##
3 ## This program is free software; you can redistribute it and/or modify it under
4 ## the terms of the GNU General Public License as published by the Free Software
5 ## Foundation; either version 3 of the License, or (at your option) any later
6 ## version.
7 ##
8 ## This program is distributed in the hope that it will be useful, but WITHOUT
9 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 ## details.
12 ##
13 ## You should have received a copy of the GNU General Public License along with
14 ## this program; if not, see <http://www.gnu.org/licenses/>.
15
16 ## -*- texinfo -*-
17 ## @deftypefn {Function File} {@var{msg} =} qaskdeco (@var{c},@var{m})
18 ## @deftypefnx {Function File} {@var{msg} =} qaskdeco (@var{inphase},@var{quadr},@var{m})
19 ## @deftypefnx {Function File} {@var{msg} =} qaskdeco (@var{...},@var{mnmx})
20 ##
21 ## Demaps an analog signal using a square QASK constellation. The input signal
22 ## maybe either a complex variable @var{c}, or as two real variables 
23 ## @var{inphase} and @var{quadr} representing the in-phase and quadrature 
24 ## components of the signal.
25 ##
26 ## The argument @var{m} must be a positive integer power of 2. By deafult the
27 ## same constellation as created in @dfn{qaskenco} is used by @dfn{qaskdeco}.
28 ## If is possible to change the values of the minimum and maximum of the
29 ## in-phase and quadrature components of the constellation to account for
30 ## linear changes in the signal values in the received signal. The variable
31 ## @var{mnmx} is a 2-by-2 matrix of the following form
32 ##
33 ## @multitable @columnfractions 0.125 0.05 0.25 0.05 0.25 0.05
34 ## @item @tab | @tab min in-phase   @tab , @tab max in-phase   @tab |
35 ## @item @tab | @tab min quadrature @tab , @tab max quadrature @tab |
36 ## @end multitable
37 ## 
38 ## If @code{sqrt(@var{m})} is an integer, then @dfn{qaskenco} uses a Gray
39 ## mapping. Otherwise, an attempt is made to create a nearly square mapping 
40 ## with a minimum Hamming distance between adjacent constellation points.
41 ## @end deftypefn
42 ## @seealso{qaskenco}
43
44 function a = qaskdeco(varargin)
45
46   have_mnmx = 0;
47   if (nargin == 2)
48     c = varargin{1};
49     inphase = real(c);
50     quadr = imag(c);
51     M = varargin{2};
52   elseif (nargin == 3)
53     if (all(size(varargin{3}) == [2 2]))
54       c = varargin{1};
55       inphase = real(c);
56       quadr = imag(c);
57       M = varargin{2};
58       mnmx = varargin{3};
59       have_mnmx = 1;
60     else
61       inphase = varargin{1};
62       quadr = varargin{2};
63       M = varargin{3};
64     endif
65   elseif (nargin == 4)
66     inphase = varargin{1};
67     quadr = varargin{2};
68     M = varargin{3};
69     mnmx = varargin{4};
70     have_mnmx = 1;
71   else
72     error ("qaskdeco: incorrect number of arguments");
73   endif
74
75   if (iscomplex(inphase) || iscomplex(quadr))
76     error ("qaskdeco: error in in-phase and/or quadrature components");
77   endif
78
79   if (!isscalar(M) || (M != ceil(M)) || (M < 2))
80     error ("qaskdeco: order of modulation must be a positive integer greater than 2");
81   endif
82
83   if (log2(M) != ceil(log2(M)))
84     error ("qaskdeco: the order must be a power of two");
85   endif
86
87   if (have_mnmx)
88     if (any(size(mnmx) != [2 2]))
89       error ("qaskdeco: error in max/min constellation values");
90     endif
91   else
92     if ((M == 2) || (M == 4))
93       mnmx = [-1, 1; -1, 1];
94     elseif (M == 8)
95       mnmx = [-3, 3; -1, 1];
96     elseif (sqrt(M) == floor(sqrt(M)))
97       NC = 2^floor(log2(sqrt(M)));
98       mnmx = [-NC+1, NC-1; -NC+1, NC-1];
99     else
100       NC = 2^floor(log2(sqrt(M))) + 2*sqrt(M/32);
101       mnmx = [-NC+1, NC-1; -NC+1, NC-1];
102     endif     
103   endif
104
105   if (M == 2)
106     layout = [0, 1]';
107   elseif (M == 4)
108     layout = [0, 1; 2, 3];
109   elseif (M == 8)
110     layout = [4, 5; 0, 1; 2, 3; 6, 7];
111   else
112     NC =2^floor(log2(sqrt(M)));
113     MM = NC * NC;
114     Gray = [0 1];
115     for i=2:ceil(log2(NC))
116       Gray = [Gray 2^(i-1) + fliplr(Gray)];
117     end
118     Gray = fliplr(de2bi(shift(Gray,length(Gray)/2 - 1)));
119     Gray2 = zeros(MM,log2(MM));
120     Gray2(:,1:2:log2(MM)) = repmat(Gray,NC,1);
121     for i=1:NC
122       Gray2(i:NC:MM,2:2:log2(MM)) = Gray;
123     end
124     layout = reshape(bi2de(fliplr(Gray2)),NC,NC);
125
126     if (MM != M)
127       ## Not sure this is the best that can be done for these mappings. If
128       ## anyone wants to improve this, go ahead, but do it in qaskenco too.
129       OFF = sqrt(M/32);
130       NR = NC + 2*OFF;
131       layout2 = NaN * ones(NR);
132       layout2(1+OFF:OFF+NC,1+OFF:OFF+NC) = layout;
133       
134       layout2(1:OFF,1+OFF:OFF+NC) = MM + layout(OFF:-1:1,:);
135       layout2(NR-OFF+1:NR,1+OFF:OFF+NC) = MM + layout(NC:-1:NC-OFF+1,:);
136
137       layout2(1+2*OFF:NC,1:OFF) = MM + layout(OFF+1:NC-OFF,OFF:-1:1);
138       layout2(1+2*OFF:NC,NR-OFF+1:NR) = MM + ...
139           layout(OFF+1:NC-OFF,NC:-1:NC-OFF+1);
140
141       layout2(1+OFF:2*OFF,1:OFF) = MM + ...
142           layout(NC/2:-1:NC/2-OFF+1,NC/2:-1:OFF+1);
143       layout2(NC+1:OFF+NC,1:OFF) = MM + ...
144           layout(NC-OFF:-1:NC/2+1,NC/2:-1:OFF+1);
145
146       layout2(1+OFF:2*OFF,NR-OFF+1:NR) = MM + ...
147           layout(NC/2:-1:NC/2-OFF+1,NC-OFF:-1:NC/2+1);
148       layout2(NC+1:OFF+NC,NR-OFF+1:NR) = MM + ...
149           layout(NC-OFF:-1:NC/2+1,NC-OFF:-1:NC/2+1);
150       layout = layout2;
151     endif
152   endif
153
154   ix = 1 + (inphase - mnmx(1,1))/(mnmx(1,2)-mnmx(1,1))*(size(layout,1)-1);
155   qx = 1 + (quadr - mnmx(2,1))/(mnmx(2,2)-mnmx(2,1))*(size(layout,2)-1);
156
157   try    wfi = warning("off", "Octave:fortran-indexing");
158   catch  wfi = 0;
159   end
160
161   unwind_protect
162     a = layout(size(layout,1)*(max(min(round(qx),size(layout,2)),1)-1) + ...
163                max(min(round(ix),size(layout,1)),1));
164     ## XXX FIXME XXX Why is this necessary??
165     if ((M == 2) &&(size(inphase,1) == 1))
166       a = a';
167     endif
168
169     if (any(isnan(a(:))))
170       ## We have a non-square constellation, with some invalid points.
171       ## Map to nearest valid constellation points...
172       indx = find(isnan(a(:)));
173       ix = ix(indx);
174       qx = qx(indx);
175       ang = atan2(quadr(indx),inphase(indx));
176
177       qx(find(ang > 3*pi/4)) = NR-OFF;
178       ix(find((ang <= 3*pi/4) & (ang > pi/2))) = OFF+1;
179       ix(find((ang <= pi/2) & (ang > pi/4))) = NR - OFF;
180       qx(find((ang <= pi/4) & (ang > 0))) = NR - OFF;
181       qx(find((ang <= 0) & (ang > -pi/4))) = OFF+1;
182       ix(find((ang <= -pi/4) & (ang > -pi/2))) = NR - OFF;
183       ix(find((ang <= -pi/2) & (ang > -3*pi/4))) = OFF+1;
184       qx(find(ang <= -3*pi/4)) = OFF+1;
185
186       a(indx) = layout(size(layout,1)*(max(min(round(qx), ...
187                 size(layout,2)),1)-1) + max(min(round(ix),size(layout,1)),1));
188     endif
189   unwind_protect_cleanup
190     warning (wfi);
191   end_unwind_protect
192
193 endfunction
194
195 %!function dec = __fntestqask1__ (msg, m)
196 %! [inp, qudr] = qaskenco (msg, m);
197 %! dec = qaskdeco (inp, qudr, m);
198
199 %!function __fntestqask2__ (m, dims)
200 %! msg = floor( rand(dims) * m);
201 %! assert (__fntestqask1__ (msg, m), msg);
202
203 %!test __fntestqask2__ (2, [100,100])
204 %!test __fntestqask2__ (4, [100,100])
205 %!test __fntestqask2__ (8, [100,100])
206 %!test __fntestqask2__ (16, [100,100])
207 %!test __fntestqask2__ (32, [100,100])
208 %!test __fntestqask2__ (64, [100,100])
209
210 %!test __fntestqask2__ (2, [100,100,3])
211 %!test __fntestqask2__ (4, [100,100,3])
212 %!test __fntestqask2__ (8, [100,100,3])
213 %!test __fntestqask2__ (16, [100,100,3])
214 %!test __fntestqask2__ (32, [100,100,3])
215 %!test __fntestqask2__ (64, [100,100,3])