├── README.md ├── generateFastFadingChannel.m ├── scm ├── Contents.m ├── antparset.m ├── cas.m ├── dipole.m ├── ds.m ├── generate_bulk_par.m ├── interp_gain.m ├── interp_gain_c.m ├── interp_gain_mex.c ├── license.txt ├── linkparset.m ├── pathloss.m ├── readme.txt ├── scm.m ├── scm_11-01-2005.pdf ├── scm_core.m ├── scm_mex_core.c ├── scm_mex_core.m └── scmparset.m └── simConfig.m /README.md: -------------------------------------------------------------------------------- 1 | # generate_ChannelInf 2 | generate channel information according to 3GPP spatial channel model(SCM) 3 | -------------------------------------------------------------------------------- /generateFastFadingChannel.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingXudong/generate_ChannelInf/32b001d515cb7baa60f6b80ee3eab1a398584275/generateFastFadingChannel.m -------------------------------------------------------------------------------- /scm/Contents.m: -------------------------------------------------------------------------------- 1 | % SCM channel model 2 | % Version 1.2, Jan 11, 2005 3 | % 4 | % Channel model functions 5 | % scm - 3GPP Spatial Channel Model (3GPP TR 25.996) 6 | % scmparset - Model parameter configuration for SCM 7 | % linkparset - Link parameter configuration for SCM 8 | % antparset - Antenna parameter configuration for SCM 9 | % pathloss - Pathloss model for 2GHz 10 | % 11 | % Miscellaneous functions 12 | % cas - Circular angle spread (3GPP TR 25.996) 13 | % ds - RMS delay spread 14 | % dipole - Field pattern of half wavelength dipole 15 | % 16 | % Utility functions 17 | % interp_gain - Antenna field pattern interpolation 18 | % interp_gain_c - Antenna field pattern interpolation (requires GSL) 19 | % scm_core - Channel coefficient computation for a geometric channel model 20 | % scm_mex_core - SCM_CORE written in ANSI-C 21 | % generate_bulk_par - Generation of SCM bulk parameters 22 | % 23 | 24 | % $Revision: 1.1 $ $Date: Dec 12, 2004$ 25 | -------------------------------------------------------------------------------- /scm/antparset.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingXudong/generate_ChannelInf/32b001d515cb7baa60f6b80ee3eab1a398584275/scm/antparset.m -------------------------------------------------------------------------------- /scm/cas.m: -------------------------------------------------------------------------------- 1 | function [sigma_AS]=cas(theta,P,units) 2 | %CAS Circular angle spread (3GPP TR 25.996) 3 | % SIGMA_AS=CAS(THETA,P) returns the circular angle spread SIGMA_AS as 4 | % defined in Annex A of 3GPP TR 25.996 v6.1.0. THETA are the angles (in 5 | % radians) of paths and P are powers of the paths. THETA and P must be 6 | % of same size and the (i,j)th element of P must be the power 7 | % corresponding to the (i,j)th angle. In 3GPP notation both THETA and P 8 | % are N X M matrices, where N is the number of paths and M is the number 9 | % of subpaths. 10 | % 11 | % With SIGMA_AS=CAS(THETA,P,'deg') input and output angles are given in 12 | % degrees. 13 | 14 | % Author: Jari Salo (HUT) 15 | % $Revision: 0.1 $ $Date: July 20, 2004$ 16 | 17 | 18 | % check that input args have same size 19 | if (any(size(theta)-size(P))==1) 20 | error('cas: Input argument size mismatch!') 21 | end 22 | 23 | deg_flag=0; % unit is radians 24 | if (nargin>2) 25 | if (strcmp(lower(units),'deg')==1) 26 | theta=theta/180*pi; % computation is in radians 27 | deg_flag=1; % unit is degrees 28 | end 29 | end 30 | 31 | 32 | % vectorize inputs 33 | P=P(:); 34 | theta=theta(:); 35 | 36 | len_theta=length(theta); 37 | 38 | delta=linspace(-pi,pi); % a 100-point grid for minimization 39 | delta_mat=repmat(delta,len_theta,1); 40 | theta_mat=repmat(theta,1,length(delta)); 41 | theta_mat=prin_value(theta_mat+delta_mat); 42 | P_mat=repmat(P,1,length(delta)); 43 | 44 | % mean values over the grid 45 | mu_thetas=sum( theta_mat.*P_mat )./sum(P_mat); 46 | 47 | % demeaned angles 48 | theta_nm_mus=theta_mat-repmat(mu_thetas,len_theta,1); 49 | theta_nm_mus=prin_value(theta_nm_mus); 50 | cas_vec= sqrt(sum(theta_nm_mus.^2.*P_mat)./sum(P_mat)); 51 | 52 | sigma_AS=min(cas_vec); 53 | 54 | if (deg_flag==1) % map back to degrees 55 | sigma_AS=sigma_AS/pi*180; 56 | end 57 | 58 | 59 | 60 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 61 | % A function to map inputs from (-inf,inf) to (-pi,pi) 62 | function y=prin_value(x) 63 | y=mod(x,2*pi); 64 | y=y-2*pi*floor(y/pi); 65 | 66 | -------------------------------------------------------------------------------- /scm/dipole.m: -------------------------------------------------------------------------------- 1 | function pattern=dipole(varargin) 2 | %DIPOLE Field pattern of half wavelength dipole 3 | % PAT=DIPOLE(AZ) returns the azimuth field pattern 4 | % at angles given in AZ (degrees). 5 | % 6 | % PAT is a 3D-array with dimensions [2 1 LENGTH(AZ)]. 7 | % The first two dimensions are the V and H 8 | % polarizations, respectively. 9 | % 10 | % PAT=DIPOLE(AZ,SLANT) gives the pattern of a 11 | % slanted dipole. The slant angle is defined as 12 | % the counter clock-wise angle (in degrees) seen 13 | % from the front of the dipole. 14 | % 15 | % Currently elevation is not supported. 16 | % 17 | % Example: To create a 2-element BS array with 18 | % 45 degrees slanted dipoles: 19 | % g=zeros(2,2,1,100); antpar=antparset; 20 | % az=linspace(-180,180); 21 | % g(1,:,:,:)=dipole(az,45); 22 | % g(2,:,:,:)=dipole(az,-45); 23 | % antpar.BsGainPattern=g; 24 | % antpar.BsGainAnglesAz=az; 25 | % 26 | % See also ANTPARSET. 27 | 28 | % Author: Jari Salo (HUT) 29 | % $Revision: 0.1 $ $Date: July 22, 2004$ 30 | 31 | 32 | az=varargin{1}; 33 | 34 | if (nargin>1) 35 | slant=varargin{2}; 36 | slant=-slant/180*pi; % change sign 37 | else 38 | slant=0; 39 | end 40 | 41 | % put all angles to radians 42 | az=az/180*pi; 43 | 44 | siz_az=size(az); % elevation has same size 45 | az_vec=az(:); 46 | 47 | % assume elevation is zero 48 | [X Y Z]=sph2cart(az_vec, zeros(size(az_vec)), repmat(1,size(az_vec))); 49 | 50 | % rotation matrix in cartesian coordinates 51 | R = [1 0 0; 0 cos(slant) -sin(slant); 0 sin(slant) cos(slant) ]; 52 | XYZr=R*[X.'; Y.'; Z.']; 53 | [az el r]=cart2sph(XYZr(1,:), XYZr(2,:), XYZr(3,:)); 54 | el=reshape(el(:),siz_az); 55 | 56 | % our coordinate system has elevation 90 deg to the zenith 57 | % while the standard dipole formula has zero angle in zenith 58 | offset=-pi/2; 59 | el=-(el+offset); % elevation is now from -90 to 90 (directly below to zenith) 60 | 61 | 62 | % ideal pattern of a slanted dipole 63 | % the dipole pattern becomes singular at {0,180} degrees elevation 64 | tol=1e6*eps; 65 | I1=find(abs(el) 2 | ndims(P) > 2) 20 | error('Input arguments must be vectors or matrices!') 21 | end 22 | 23 | 24 | if (min(size(tau))==1) % if tau is a vector 25 | tau=tau(:); 26 | elseif (size(P,1) ~= size(tau,1) | size(P,2) ~= size(tau,2) ) 27 | error('Input argument size mismatch!') 28 | end 29 | 30 | % if P is a vector 31 | if (min(size(P))==1) 32 | P=P(:); 33 | end 34 | 35 | 36 | 37 | % make the minimum delay of each column zero 38 | if (min(size(tau))==1) % if tau is a vector 39 | tau=repmat(tau,1,size(P,2))-min(tau); 40 | else % if tau is matrix 41 | tau=tau-repmat(min(tau),size(tau,1),1); 42 | end 43 | 44 | 45 | Dvec=sum(tau.*P)./sum(P); 46 | D=repmat(Dvec,size(tau,1),1); 47 | 48 | % compute std of delay spread 49 | sigma_DS=sqrt( sum((tau-D).^2.*P)./sum(P) ); 50 | 51 | 52 | if (nargout>1) 53 | excess_delay=max(tau); 54 | end 55 | 56 | -------------------------------------------------------------------------------- /scm/generate_bulk_par.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingXudong/generate_ChannelInf/32b001d515cb7baa60f6b80ee3eab1a398584275/scm/generate_bulk_par.m -------------------------------------------------------------------------------- /scm/interp_gain.m: -------------------------------------------------------------------------------- 1 | function gains = interp_gain(field_patterns, angles, at_values, interp_method) 2 | %INTERP_GAIN Antenna field pattern interpolation 3 | % G = INTERP_GAIN(PAT, ANGLES, DATA, METHOD) are the complex antenna 4 | % field patterns interpolated at azimuth angles given in DATA, given in 5 | % degrees. SIZE(G)=[NUM_EL SIZE(DATA)], where NUM_EL is the number of 6 | % rows in matrix PAT. PAT has LENGTH(ANGLES) columns; ANGLES is a vector 7 | % defining the angles (in degrees) at which the antenna element patterns 8 | % in the rows of PAT have been defined. Note: LENGTH(ANGLES) must equal 9 | % SIZE(PAT,2), i.e. all field patterns have to be specified over the 10 | % same azimuth grid. 11 | % 12 | % METHOD is a string defining interpolation method. For a list of 13 | % methods, see INTERP1. It is recommended that the antenna field patterns 14 | % in PAT are given so that there are no duplicate points in ANGLES and 15 | % that the support of the interpolated function spans over the entire 16 | % azimuth angle, i.e. 360 degrees. (Note that e.g. linear interpolation 17 | % cannot extrapolate values falling outside the support of the 18 | % interpolated function.) 19 | % 20 | % Phase and magnitude are interpolated separately. 21 | % 22 | % Elevation interpolation is not supported currently. 23 | % 24 | % See also INTERP_GAIN_C. 25 | 26 | % Authors: Jari Salo (HUT), Jussi Salmi (HUT), Giovanni Del Galdo (TUI) 27 | % $Revision: 0.1 $ $Date: July 22, 2004$ 28 | 29 | 30 | % if it's a vector, make sure that it's a row vector 31 | if (min(size(field_patterns,2)==1)) 32 | field_patterns=field_patterns(:).'; 33 | end 34 | 35 | if (size(field_patterns,2) ~= length(angles(:))) 36 | error('Size mismatch in antenna parameters! ') 37 | end 38 | 39 | siz_at_values = size(at_values); 40 | nd = ndims(at_values); 41 | num_elements = size(field_patterns,1); 42 | 43 | at_values=prin_value(at_values); 44 | 45 | % interpolation 46 | % Note that extrapolation is not possible with e.g. linear interpolation 47 | % Note also that interpolated values are in degrees 48 | if (isreal(field_patterns)==0) % if complex-valued do amplitude and phase separately 49 | int_gain = interp1(angles(:), abs(field_patterns.'), at_values(:),interp_method); 50 | int_phase = interp1(angles(:), unwrap(angle(field_patterns.'),1), at_values(:),interp_method); 51 | else % otherwise interpolate only the real part 52 | int_gain = interp1(angles(:), field_patterns.', at_values(:),interp_method); 53 | int_phase= -pi*(-0.5+0.5*sign(int_gain)); % take into account the sign of real part 54 | end 55 | 56 | % back to complex values, this has size [PROD(siz_at_values) num_elements] 57 | abs_gain=abs(int_gain); 58 | gains=complex(abs_gain.*cos(int_phase), abs_gain.*sin(int_phase)); 59 | 60 | % make the output size [num_elements siz_at_values] 61 | gains=reshape(gains,[siz_at_values num_elements]); 62 | gains=permute(gains,[nd+1 1:nd]); 63 | 64 | 65 | 66 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 67 | % A function that maps inputs from (-inf,inf) to (-180,180) 68 | function y=prin_value(x) 69 | y=mod(x,360); 70 | y=y-360*floor(y/180); 71 | -------------------------------------------------------------------------------- /scm/interp_gain_c.m: -------------------------------------------------------------------------------- 1 | function gains = interp_gain_c(field_patterns, angles, at_values, interp_method) 2 | %INTERP_GAIN_C Antenna field pattern interpolation (requires GSL) 3 | % G = INTERP_GAIN_C(PAT, ANGLES, DATA, METHOD) are the 4 | % complex antenna field patterns interpolated at azimuth angles given in DATA, 5 | % given in degrees. SIZE(G)=[NUM_EL SIZE(DATA)], where NUM_EL is the 6 | % number of rows in matrix PAT. PAT has LENGTH(ANGLES) columns; ANGLES 7 | % is a vector defining the angles (in degrees) at which the antenna 8 | % element patterns in the rows of PAT have been defined. Note: LENGTH(ANGLES) 9 | % must equal SIZE(PAT,2), i.e. all field patterns have to be specified 10 | % over the same azimuth grid. 11 | % 12 | % METHOD is a string defining interpolation method. The recommended methods 13 | % are: 14 | % 'linear' = linear interpolation 15 | % 'cspline' = cubic spline with periodic boundary conditions 16 | % 'nearest' = rounds to nearest known point 17 | % 18 | % The default method is 'cspline'. Note that 'linear' cannot extrapolate 19 | % values falling outside the support of the interpolated function and 20 | % 'nearest' requires that ANGLES is uniformly sampled in angular domain. 21 | % 22 | % Usage of this function requires that interp_gain_mex.c is compiled. 23 | % To compile, type 24 | % 25 | % mex -lgsl -lgslcblas -lm interp_gain_mex.c 26 | % 27 | % The compilation requires that GNU Scientific Library (GSL) is properly 28 | % installed in your system and the mex compiler is able to use it. 29 | % 30 | % It is recommended that the antenna field patterns in PAT are given 31 | % so that there are no duplicate points in ANGLES and that the 32 | % support of the interpolated function spans over the entire azimuth 33 | % angle, i.e. 360 degrees. 34 | % 35 | % Real and imaginary parts are interpolated separately. Elevation 36 | % interpolation is not supported currently. 37 | % 38 | % Ref.: http://www.gnu.org/software/gsl/ 39 | % 40 | % See also INTERP_GAIN. 41 | 42 | % Authors: Jussi Salmi (HUT), Jari Salo (HUT) 43 | % $Revision: 0.1 $ $Date: Aug 11, 2004$ 44 | 45 | 46 | % field_pattern - complex field patterns of the antennas, SIZE()=[NUM_EL AZ_VALUES] 47 | % angles - a vector with LENGTH(AZ_VALUES) 48 | % at_values - an N-D array 49 | % gains - interpolated complex gains, SIZE()=[NUM_EL SIZE(at_values)] 50 | 51 | 52 | if (size(field_patterns,2) ~= numel(angles)) 53 | error('Size mismatch in antenna parameters! ') 54 | end 55 | 56 | siz_at_values = size(at_values); 57 | nd = ndims(at_values); 58 | num_elements = size(field_patterns,1); 59 | 60 | tol = 1e-5; % tolerance to be added if dublicate angles exist 61 | 62 | % next lines sort the interpolation values in ascending order and 63 | % check if there are same values more than once. 64 | [angles I] = sort(angles); 65 | Id = 1; 66 | while (~isempty(Id)) 67 | y_diff = diff(angles); 68 | Id = find(y_diff==0); 69 | angles(Id) = angles(Id) - tol; 70 | end 71 | 72 | % check interpolation method 73 | % Additional methods are: 74 | % 'csplinenat' = cubic spline with natural boundary conditions 75 | % 'akima' = Non-rounded Akima spline with natural boundary conditions. 76 | % 'akimap' = Non-rounded Akima spline with periodic boundary conditions. 77 | 78 | if isequal(lower(interp_method),'linear') 79 | type = 1; 80 | else 81 | if isequal(lower(interp_method),'cspline') 82 | type = 2; 83 | else 84 | if isequal(lower(interp_method),'nearest') 85 | type = 3; 86 | else 87 | if isequal(lower(interp_method),'csplinenat') 88 | type = 4; 89 | else 90 | if isequal(lower(interp_method),'akima') 91 | type = 5; 92 | else 93 | if isequal(lower(interp_method),'akimap') 94 | type = 6; 95 | else 96 | type = 2; % default is 'cspline' 97 | end 98 | end 99 | end 100 | end 101 | end 102 | end 103 | 104 | % interpolate real part values 105 | % extrapolate values outside the user-defined antenna pattern 106 | interp_real = interp_gain_mex(angles(:), real(field_patterns(:,I).'), at_values(:),type); 107 | 108 | if isreal(field_patterns) % check if fieldpatterns is real valued 109 | gains = interp_real; 110 | 111 | else % fieldpatterns is complex 112 | 113 | % Interpolate imaginary part. Note that interpolated values are in degrees 114 | % extrapolate values outside the user-defined antenna pattern 115 | interp_imag = interp_gain_mex(angles(:), imag(field_patterns(:,I).'), at_values(:),type); 116 | 117 | % back to complex values, this has size [PROD(siz_at_values) num_elements] 118 | gains=complex(interp_real,interp_imag); 119 | end 120 | 121 | % make the output size [num_elements siz_at_values] 122 | gains=reshape(gains,[siz_at_values num_elements]); 123 | gains=permute(gains,[nd+1 1:nd]); 124 | -------------------------------------------------------------------------------- /scm/interp_gain_mex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * interp_gain_mex.c 3 | * 4 | * This file contains mex Gateway for interpolation with 5 | * GNU Scientific Library interpolation functions. 6 | * 7 | * The system must have GNU Scientific library installed. 8 | * 9 | * Compilation: 10 | * 11 | * mex interp_gain_mex.c -lgsl -lgslcblas -lm 12 | * 13 | * @author Jussi Salmi, Helsinki University of Technology, Radio Laboratory, SMARAD Center of Excellence 14 | * @date 2004/07/26 15 | 16 | */ 17 | 18 | #include 19 | #include 20 | #include "mex.h" 21 | #include 22 | #include 23 | #include 24 | #define LINEAR 1 /* for linear interpolation */ 25 | #define CUBIC_P 2 /* for cubic spline with periodic boundary conditions */ 26 | #define LUT 3 /* look-up table interpolation, finds nearest known point */ 27 | #define CUBIC 4 /* cubic spline with natural boundary conditions */ 28 | #define AKIMA 5 /* Non-rounded Akima spline with natural boundary conditions. */ 29 | #define AKIMA_P 6 /* Non-rounded Akima spline with periodic boundary conditions. */ 30 | /* Akima methods use the non-rounded corner algorithm of Wodicka. */ 31 | 32 | 33 | /** 34 | * This is the mex-function for GNU Scientific Library interpolation. 35 | * 36 | * Input arguments are: 37 | * 38 | * prhs[0] = xn - points where the values of yn are known (1-Dimensional vector) 39 | * prhs[1] = yn - function values of the points xn ( size [length(xn)][num of separate data sets]) 40 | * prhs[2] = xi - points where yi values are evaluated (1-Dimensional vector) 41 | * prhs[3] = type - interpolation type used in calculations (integer) 42 | * 43 | * Output argument is 44 | * plhs[0] = yi - output matrix of interpolated values (size [length(xi)][num of separate data sets]) 45 | */ 46 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 47 | double *xn, *yn, *xi, *yi, step; /* variables for input arguments */ 48 | int i, ii, lut_i; /* running index variables */ 49 | int nsize, isize, type, *yn_dims, num_elements, halfn; /* for the parameter sizes */ 50 | gsl_interp_accel *accelerator; /* interpolation accelerator */ 51 | gsl_spline *spline; /* interpolation object */ 52 | 53 | /* get the output dimensions */ 54 | yn_dims = (int*)mxGetDimensions(prhs[1]); 55 | /* xi_dims = (int*)mxGetDimensions(prhs[2]);*/ 56 | isize = mxGetNumberOfElements(prhs[2]); /* number of output points */ 57 | 58 | nsize = yn_dims[0]; /* number of points for interpolation */ 59 | num_elements = yn_dims[1]; /* number of separate interpolations */ 60 | 61 | /* taking inputs */ 62 | xn = (double*)mxGetPr(prhs[0]); 63 | yn = (double*)mxGetPr(prhs[1]); 64 | xi = (double*)mxGetPr(prhs[2]); 65 | type = (int)mxGetScalar(prhs[3]); 66 | 67 | /* creates matrix for output */ 68 | plhs[0] = (mxArray*) mxCreateDoubleMatrix(num_elements, isize, mxREAL); 69 | yi = (double*)mxGetPr(plhs[0]); 70 | 71 | accelerator = gsl_interp_accel_alloc(); 72 | spline = gsl_spline_alloc(gsl_interp_cspline_periodic, nsize); 73 | 74 | /* look-up method */ 75 | if (type == LUT) { 76 | halfn = (int)0.5*nsize; 77 | step = 0.5*fabs(*(xn+halfn)-*(xn+halfn+1)); 78 | for (i=0; i 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /scm/linkparset.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingXudong/generate_ChannelInf/32b001d515cb7baa60f6b80ee3eab1a398584275/scm/linkparset.m -------------------------------------------------------------------------------- /scm/pathloss.m: -------------------------------------------------------------------------------- 1 | function loss=pathloss(scmpar,linkpar) 2 | %PATHLOSS Pathloss models for 2GHz and 5GHz 3 | % PATH_LOSSES=PATHLOSS(SCMPAR,LINKPAR) returns path losses in dB scale 4 | % for all links defined in SCM input struct LINKPAR for the center 5 | % frequency and scenario given in SCMPAR. The output is a column vector 6 | % whose length is equal to the number of links defined in LINKPAR, e.g. 7 | % LENGTH(LINKPAR.MsBsDistance). The center frequencies and distances in 8 | % SCMPAR must be specified in Herzes and meters, respectively. 9 | % 10 | % PATHLOSS supports 2 GHz center frequency and the SCM scenarios: 11 | % suburban macro, urban macro, and urban micro [1]. MS and BS heights 12 | % are not currently supported. 13 | % 14 | % The 2GHz path loss model is based on [1, Table 5.1]. 15 | % 16 | % Refs. [1]: 3GPP TR 25.996 v6.1.0 (2003-09) 17 | % 18 | % See also SCMPARSET and LINKPARSET. 19 | 20 | % Authors: Jari Salo (HUT), Daniela Laselva (EBIT) 21 | % $Revision: 0.21 $ $Date: Dec 12, 2004$ 22 | 23 | 24 | 25 | % extract required parameters from the input structs 26 | NumUsers=length(linkpar.MsBsDistance); 27 | MsBsDistance=linkpar.MsBsDistance; 28 | Scenario=scmpar.Scenario; 29 | CenterFrequency=scmpar.CenterFrequency; 30 | Options=scmpar.ScmOptions; 31 | 32 | % print out a warning if center freqency is not within a tolerance 33 | tol=2e8; % Hz 34 | if (abs(CenterFrequency - 2e9)>tol) 35 | CenterFrequency=2e9; 36 | warning('MATLAB:CenterFrequencyChanged','Center frequency of 2GHz used for path loss computation.') 37 | else 38 | CenterFrequency=2e9; 39 | end 40 | 41 | 42 | switch lower(Scenario) 43 | 44 | case {'suburban_macro'} 45 | 46 | switch (CenterFrequency) % other frequencies may be added, if necessary 47 | 48 | case (2e9) % SCM suburban macro [1, Section 5.2 and Table 5.1] 49 | if (min(MsBsDistance)<35) 50 | warning('MATLAB:TooSmallMsBsDistance','MsBsDistance less than 35 meters encountered. Path loss computation may be unreliable.') 51 | end 52 | loss=31.5+35*log10(MsBsDistance); 53 | end 54 | 55 | 56 | case {'urban_macro'} 57 | 58 | switch (CenterFrequency) % other frequencies may be added, if necessary 59 | 60 | case (2e9) % SCM urban_macro model [1, Section 5.2 and Table 5.1] 61 | if (min(MsBsDistance)<35) 62 | warning('MATLAB:TooSmallMsBsDistance','MsBsDistance less than 35 meters encountered. Path loss computation may be unreliable.') 63 | end 64 | loss=34.5+35*log10(MsBsDistance); 65 | 66 | end 67 | 68 | 69 | case {'urban_micro'} 70 | 71 | % options for urban micro 72 | switch lower(Options) 73 | 74 | case {'none','polarized','urban_canyon'} 75 | 76 | switch (CenterFrequency) % other frequencies may be added, if necessary 77 | 78 | case (2e9) % SCM urban micro model [1, Section 5.2 and Table 5.1] 79 | if (min(MsBsDistance)<20) 80 | warning('MATLAB:TooSmallMsBsDistance','MsBsDistance less than 20 meters encountered. Path loss computation may be unreliable.') 81 | end 82 | loss=34.53+38*log10(MsBsDistance); 83 | 84 | end 85 | 86 | 87 | case ('los') 88 | 89 | switch (CenterFrequency) % other frequencies may be added, if necessary 90 | 91 | case (2e9) % SCM urban micro model [1, Section 5.2 and Table 5.1] 92 | if (min(MsBsDistance)<20) 93 | warning('MATLAB:TooSmallMsBsDistance','MsBsDistance less than 20 meters encountered. Path loss computation may be unreliable.') 94 | end 95 | loss=30.18+26*log10(MsBsDistance); 96 | 97 | end 98 | 99 | 100 | end % end options for urban micro 101 | 102 | 103 | 104 | end % end switch Scenario 105 | 106 | 107 | % output 108 | loss=loss(:); 109 | -------------------------------------------------------------------------------- /scm/readme.txt: -------------------------------------------------------------------------------- 1 | MATLAB implementation of SCM channel model 2 | Version 1.2 3 | Jan 11, 2005 4 | 5 | Requires MATLAB 6.5.0 (R13) or later. 6 | 7 | 8 | Installation instructions: 9 | 10 | Create a directory called 'winner', copy all files in this zip into the directory, and add the directory to Matlab's path. To get started, type 'help winner'. 11 | 12 | 13 | -------------------------------------------------------------------------------- /scm/scm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingXudong/generate_ChannelInf/32b001d515cb7baa60f6b80ee3eab1a398584275/scm/scm.m -------------------------------------------------------------------------------- /scm/scm_11-01-2005.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingXudong/generate_ChannelInf/32b001d515cb7baa60f6b80ee3eab1a398584275/scm/scm_11-01-2005.pdf -------------------------------------------------------------------------------- /scm/scm_core.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingXudong/generate_ChannelInf/32b001d515cb7baa60f6b80ee3eab1a398584275/scm/scm_core.m -------------------------------------------------------------------------------- /scm/scm_mex_core.c: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * scm_mex_core.c 4 | * 5 | * This file contains functions for calculation of Spatial channel model for 6 | * Multiple Input Multiple Output (MIMO) simulations. It also has a mex gateway function 7 | * for Matlab use. 8 | * 9 | * Compilation: 10 | * 11 | * In Matlab type: 12 | * 13 | * mex scm_mex_core.c 14 | * 15 | * Instructions for input arguments is found in scm_mec_core.m help file. 16 | * 17 | * 18 | * @author Jussi Salmi, Helsinki University of Technology, Radio Laboratory, SMARAD Center of Excellence 19 | * @date 2004/12/07 20 | * 21 | * Refs: 22 | * [1] 3GPP TR 25.996 V6.1.0 (2003-09) 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include "mex.h" 29 | #define PI 3.14159265358979323846 30 | #define DEFAULT_LUT_POINTS 16384 /* must be a power of two */ 31 | #define GENERAL 1 32 | #define POLARIZED 2 33 | #define LOS 3 34 | 35 | 36 | /** 37 | * Function complex_multiply calculates the multiplication of two complex numbers. 38 | * The complex numbers must be in cartesian form of (a + ib) 39 | * (a + ib)(c + id) = (ac - bd) + i[(a + b)(c + d) - ac - bd] 40 | * @param a real part of the first number 41 | * @param b imaginary part of the first number 42 | * @param c real part of the second number 43 | * @param d imaginary part of the second number 44 | * @param re_ans real part of the answer 45 | * @param im_ans imaginary part of the answer 46 | */ 47 | void complex_multiply(const double a, const double b, 48 | const double c, const double d, double *re_ans, double *im_ans) { 49 | 50 | *re_ans = a*c-b*d; 51 | *im_ans = b*c+a*d; 52 | } 53 | 54 | /** 55 | * Function complex_multiply calculates the multiplication of three complex numbers. 56 | * @param ar real part of the first number 57 | * @param ai imaginary part of the first number 58 | * @param br real part of the second number 59 | * @param bi imaginary part of the second number 60 | * @param cr real part of the third number 61 | * @param ci imaginary part of the third number 62 | * @param re_ans real part of the answer 63 | * @param im_ans imaginary part of the answer 64 | */ 65 | void complex_multiply_3(const double ar, const double ai, 66 | const double br, const double bi, const double cr, const double ci, 67 | double *re_ans, double *im_ans) { 68 | 69 | *re_ans = ar*br*cr-ar*bi*ci-ai*br*ci-ai*bi*cr; 70 | *im_ans = ar*br*ci+ar*bi*cr+ai*br*cr-ai*bi*ci; 71 | } 72 | 73 | /** 74 | * Function matrix_multiply calculates open a multiplication of [a][B][c], where 75 | * a and c are two-element complex vectors and B is a 2-by-2 complex matrix. 76 | * @param a1_re real part of a1 77 | * @param a1_im imaginary part of a1 78 | * @param a2_re real part of a2 79 | * @param a2_im imaginary part of a2 80 | * @param c1_re real part of c1 81 | * @param c1_im imaginary part of c1 82 | * @param c2_re real part of c2 83 | * @param c2_im imaginary part of c2 84 | * @param b11_re real part of b11 85 | * @param b11_im imaginary part of b11 86 | * @param b12_re real part of b12 87 | * @param b12_im imaginary part of b12 88 | * @param b21_re real part of b21 89 | * @param b21_im imaginary part of b21 90 | * @param b22_re real part of b22 91 | * @param b22_im imaginary part of b22 92 | * @param ans_real_part pointer to output real part 93 | * @param ans_imag_part pointer to output imaginary part 94 | */ 95 | void matrix_multiply(double a1_re,double a1_im, double a2_re, double a2_im, 96 | double c1_re, double c1_im, double c2_re, double c2_im, 97 | double b11_re, double b11_im, double b12_re, double b12_im, 98 | double b21_re, double b21_im, double b22_re, double b22_im, 99 | double *ans_real_part, double *ans_imag_part) { 100 | 101 | double real_part, imag_part; 102 | /* calculating the matrix multiplication open */ 103 | complex_multiply_3(a1_re,a1_im,c1_re,c1_im,b11_re,b11_im,&real_part,&imag_part); 104 | *ans_real_part = real_part; 105 | *ans_imag_part = imag_part; 106 | complex_multiply_3(a2_re,a2_im,c1_re,c1_im,b21_re,b21_im,&real_part,&imag_part); 107 | *ans_real_part += real_part; 108 | *ans_imag_part += imag_part; 109 | complex_multiply_3(a1_re,a1_im,c2_re,c2_im,b12_re,b12_im,&real_part,&imag_part); 110 | *ans_real_part += real_part; 111 | *ans_imag_part += imag_part; 112 | complex_multiply_3(a2_re,a2_im,c2_re,c2_im,b22_re,b22_im,&real_part,&imag_part); 113 | *ans_real_part += real_part; 114 | *ans_imag_part += imag_part; 115 | } 116 | 117 | /** 118 | * Function sumloop calculates the repeating summation of subpaths. 119 | * @param m number of subpaths 120 | * @param exp_helper table of t-independent terms in complex sinusoidials 121 | * @param exp_t_coeff table of t-dependent terms 122 | * @param real_multiplier real part of product of gain terms 123 | * @param imag_multiplier imaginary part of product of gain terms 124 | * @param t time instant 125 | * @param real_sum pointer to real part of the sum 126 | * @param imag_sum pointer to imaginary part of the sum 127 | */ 128 | void sumloop(int m, const double *exp_helper,const double *exp_t_coeff, 129 | const double *real_multiplier, const double *imag_multiplier, double t, 130 | double *real_sum, double *imag_sum) { 131 | 132 | int m_i; 133 | double angle, a, b; 134 | m_i = 0; 135 | while (m_i < m) { 136 | angle = exp_helper[m_i] + exp_t_coeff[m_i]* t; 137 | complex_multiply(real_multiplier[m_i], imag_multiplier[m_i], 138 | cos(angle), sin(angle), &a, &b); 139 | *real_sum += a; /* real part of the multiplication */ 140 | *imag_sum += b; /* imaginary part of the multiplication */ 141 | m_i++; 142 | } 143 | } 144 | 145 | /** 146 | * Function sumloop_with_table calculates the repeating summation of subpaths using quantized cosine. 147 | * @param m_i starting index of subpaths 148 | * @param stop final index +1 149 | * @param exp_helper table of t-independent terms in complex sinusoidials 150 | * @param exp_t_coeff table of t-dependent terms 151 | * @param real_multiplier real part of product of gain terms 152 | * @param imag_multiplier imaginary part of product of gain terms 153 | * @param t time instant 154 | * @param lm order of terms to be summed 155 | * @param real_sum pointer to real part of the sum 156 | * @param imag_sum pointer to imaginary part of the sum 157 | * @param cos_table table of quantized cosine values 158 | * @param r2p coefficient for look-up table (num_of_points/(2*PI)) 159 | * @param divider constant used by look-up table 160 | * @param halfpi (pi/2) 161 | */ 162 | void sumloop_with_table(int m, const double *exp_helper,const double *exp_t_coeff, 163 | const double *real_multiplier, const double *imag_multiplier, double t, 164 | double *real_sum, double *imag_sum, const double *cos_table, const double r2p, 165 | const long int divider, const double halfpi) { 166 | 167 | int m_i; 168 | double angle, a, b; 169 | 170 | m_i = 0; 171 | while (m_i < m) { 172 | angle = exp_helper[m_i] + exp_t_coeff[m_i]* t; 173 | complex_multiply(real_multiplier[m_i], imag_multiplier[m_i], 174 | cos_table[abs(angle*r2p)÷r], cos_table[abs((angle-halfpi)*r2p)÷r], 175 | &a, &b); 176 | *real_sum += a; /* real part of the multiplication */ 177 | *imag_sum += b; /* imaginary part of the multiplication */ 178 | m_i++; 179 | } 180 | } 181 | 182 | /** 183 | * Function scm_sum computes coefficients for 3GPP Spatial channel model [1 5.5.1. 184 | * The parameter angles must be in radians! 185 | * @param sin_look_up_points if nonzero, then look-up table for sin/cos is used. Use -1 for default number of points. 186 | * @param u the number of MS elements 187 | * @param s the number of BS elements 188 | * @param n number of multipaths 189 | * @param m number of subpaths for each n multipath 190 | * @param k number of individual links 191 | * @param *re_sq_G_BS real part of square root of BS Gain coefficients (size [k][s][n][m]) 192 | * @param *im_sq_G_BS imaginary part of BS Gain coefficients (size [k][s][n][m]) 193 | * @param *re_sq_G_MS real part of MS Gain coefficients (size [k][u][n][m]) 194 | * @param *im_sq_G_MS imaginary part of MS Gain coefficients (size [k][u][n][m]) 195 | * @param k_CONST wavenumber (2*pi/lambda) 196 | * @param *d_s distance of BS antenna s from ref. antenna (s=1), (size [s]) 197 | * @param *d_u distance of MS antenna u from ref. antenna (u=1), (size [u]) 198 | * @param *aod Angel of Departure (size [k][n][m]) 199 | * @param *aoa Angel of Arrival (size [k][n][m]) 200 | * @param *phase phase of the mth subpath of the nth path (size [k][n][m]) 201 | * @param *v magnitude of the MS velocity vector (size [k]) 202 | * @param *theta_v angle of the MS velocity vector (size [k]) 203 | * @param *ts vector of time samples (size [k][tn]) 204 | * @param tn number of time samples 205 | * @param *sq_Pn square root of Pn (size [k][n]) 206 | * @param GainsAreScalar has value 1 if gain is scalar, zero if not 207 | * @param *re_h pointer to real part of output h, h has to be initialized outside scm function (size [u][s][n][tn][k]) 208 | * @param *im_h pointer to imag part of output h 209 | * @param *output_SubPathPhase pointer to output phases (size [k][n][m]) 210 | * @return 0 if success, 1 if bad arguments 211 | */ 212 | int scm_sum(const long int sin_look_up_points, const int u, const int s, const int n, const int m, const int k, 213 | const double *re_sq_G_BS, const double *im_sq_G_BS, const double *re_sq_G_MS, const double *im_sq_G_MS, 214 | const double k_CONST, const double *d_s, const double *d_u, const double *aod, const double *aoa, 215 | const double *phase, const double *v, const double *theta_v, const double *ts, const int tn, 216 | const double *sq_Pn, int GainsAreScalar, double *re_h, double *im_h, double *output_SubPathPhase) { 217 | 218 | int i, t_i, n_i, m_i, u_i, s_i, k_i; /* running index variables */ 219 | 220 | /* notation conversion variables from [][] to *(p[0]+var) */ 221 | long int ksnm, kunm, knm, usntk, kn, kt, usn, usntk_i, ksn, kun; 222 | 223 | int msreal, bsreal, both_real; /* boolean variables to check complexity of gains */ 224 | double delta_t; 225 | double a, b, c, d, real_sum, imag_sum, kds, kdu, kv, gainScalar_re, gainScalar_im; 226 | double *real_multiplier; 227 | double *imag_multiplier; 228 | double *exp_helper; /* part of coefficient for exp(j...) in the sum */ 229 | double *exp_t_coeff; 230 | double *cos_table; 231 | double r2p; 232 | double halfpi; 233 | double one_over_sq_m; 234 | 235 | long int num_of_points, divider, pows_of_two; 236 | 237 | real_multiplier = (double*)malloc(m*sizeof(double)); 238 | imag_multiplier = (double*)calloc(m,sizeof(double)); 239 | exp_t_coeff = (double*)malloc(m*sizeof(double)); 240 | exp_helper = (double*)malloc(m*sizeof(double)); 241 | 242 | /* check if gains are real valued */ 243 | bsreal = 0; 244 | msreal = 0; 245 | both_real = 0; 246 | if (im_sq_G_BS == NULL) 247 | bsreal = 1; 248 | if (im_sq_G_MS == NULL) 249 | msreal = 1; 250 | if (bsreal && msreal) 251 | both_real = 1; 252 | 253 | /* check if gains are scalar */ 254 | if (GainsAreScalar) { 255 | a = *re_sq_G_BS; 256 | c = *re_sq_G_MS; 257 | if (both_real) { 258 | gainScalar_re = a*c; 259 | gainScalar_im = 0; 260 | } 261 | else { 262 | if (bsreal) 263 | b = 0.0; 264 | else 265 | b = *im_sq_G_BS; 266 | if (msreal) 267 | d = 0.0; 268 | else 269 | d = *im_sq_G_MS; 270 | complex_multiply(a, b, c, d, 271 | &gainScalar_re, &gainScalar_im); 272 | } 273 | } 274 | 275 | usn = u*s*n; /* for output pointing */ 276 | ksn = k*s*n; /* for parameter pointing */ 277 | kun = k*u*n; 278 | one_over_sq_m = 1/sqrt(m); 279 | 280 | /* checks if look-up table is used for sin/cos */ 281 | if (sin_look_up_points) { 282 | if (sin_look_up_points == -1) 283 | num_of_points = DEFAULT_LUT_POINTS; 284 | else { 285 | pows_of_two = 2; 286 | while (pows_of_two < sin_look_up_points) 287 | pows_of_two = pows_of_two*2; 288 | num_of_points = pows_of_two; 289 | if (pows_of_two != sin_look_up_points) 290 | printf("Warning: Number of LU points is not a power-of-2: size changed to %li.\n", num_of_points); 291 | } 292 | 293 | divider = num_of_points-1; 294 | r2p = num_of_points/(2*PI); 295 | halfpi = PI*0.5; 296 | 297 | cos_table = (double*)malloc(num_of_points*sizeof(double)); 298 | 299 | /* calculate the table */ 300 | for (i=0;i1) { 307 | delta_t = *(ts+k+k_i)-*(ts+k_i); 308 | } 309 | kv = k_CONST * v[k_i]; 310 | /* cycling u, u is a given constant*/ 311 | for(u_i=0; u_i < u; u_i++) { 312 | kdu = k_CONST * *(d_u+u_i); 313 | /* cyckling s, s is a given constant */ 314 | for(s_i=0;s_i< s; s_i++) { 315 | kds = k_CONST * *(d_s+s_i); 316 | /* running through paths, n is a given constant*/ 317 | for(n_i=0;n_i1) /* output pphase can be evaluated only if more than one time sample */ 355 | *(output_SubPathPhase+knm) = exp_t_coeff[m_i]* (*(ts+k*(tn-1)+k_i)+delta_t); 356 | } 357 | 358 | usntk_i = usn*tn*k_i + u*s*n_i + u*s_i + u_i; 359 | /* cycling the time vector */ 360 | for (t_i=0; t_i1) 385 | delta_t = *(ts+k+k_i)-*(ts+k_i); 386 | kv = k_CONST * v[k_i]; 387 | /* cycling u, u is a given constant*/ 388 | for(u_i=0; u_i < u; u_i++) { 389 | kdu = k_CONST * *(d_u+u_i); 390 | /* cyckling s, s is a given constant */ 391 | for(s_i=0;s_i< s; s_i++) { 392 | kds = k_CONST * *(d_s+s_i); 393 | /* running through paths, n is a given constant*/ 394 | for(n_i=0;n_i1) /* output pphase can be evaluated only if more than one time sample */ 432 | *(output_SubPathPhase+knm) = exp_t_coeff[m_i]* (*(ts+k*(tn-1)+k_i)+delta_t); 433 | } 434 | 435 | usntk_i = usn*tn*k_i + u*s*n_i + u*s_i + u_i; 436 | /* cycling the time vector */ 437 | for (t_i=0; t_i1) 590 | delta_t = *(ts+k+k_i)-*(ts+k_i); 591 | kv = k_CONST * v[k_i]; /* value depends only on k */ 592 | /* u is a given constant */ 593 | for (u_i=0; u_i1) /* output pphase can be evaluated only if more than one time sample */ 699 | *(output_SubPathPhase+knm) = exp_t_coeff[m_i]* (*(ts+k*(tn-1)+k_i)+delta_t); 700 | } 701 | usntk_i = usn*tn*k_i + u*s*n_i + u*s_i + u_i; 702 | /* cycling the time vector */ 703 | for (t_i=0; t_i1) { 728 | delta_t = *(ts+k+k_i)-*(ts+k_i); 729 | } 730 | kv = k_CONST * v[k_i]; /* value depends only on k */ 731 | /* u is a given constant */ 732 | for (u_i=0; u_i1) /* output pphase can be evaluated only if more than one time sample */ 832 | *(output_SubPathPhase+knm) = exp_t_coeff[m_i]* (*(ts+k*(tn-1)+k_i)+delta_t); 833 | } 834 | 835 | usntk_i = usn*tn*k_i + u*s*n_i + u*s_i + u_i; 836 | /* cycling the time vector */ 837 | for (t_i=0; t_i1) { 924 | delta_t = *(ts+k*1+k_i)-*(ts+k_i); 925 | *(output_los_phase+k_i) = exp_t_coeff * (*(ts+k*(tn-1)+k_i)+delta_t); 926 | } 927 | usn = u*s*n; 928 | 929 | /* u is a given constant*/ 930 | for(u_i=0; u_i < u; u_i++) { 931 | /* s is a given constant */ 932 | for(s_i=0;s_i< s; s_i++) { 933 | 934 | for(n_i=0; n_i