source: Sophya/trunk/SophyaLib/NTools/perandom.cc@ 3123

Last change on this file since 3123 was 3109, checked in by cmv, 19 years ago

RandomInterp() + documentation FunRan et Tirage gaussien cmv 20/11/06

File size: 8.7 KB
RevLine 
[2615]1#include "sopnamsp.h"
[244]2#include "machdefs.h"
3#include "pexceptions.h"
[220]4#include "perandom.h"
5#include "pemath.h"
[2322]6#include <iostream>
[220]7
[3075]8
[220]9////////////////////////////////////////////////////////////////////////////
[3075]10/*!
11 \class SOPHYA::FunRan
12 \ingroup NTools
13 Classe for generating random variables from 1D function
14*/
[220]15
[3075]16
17/********* Methode *********/
[3109]18/*! Creator from a function.
19\verbatim
20 - if pdf==true: f est une densite de probabilite (PDF)
21 non necessairement normalisee
22 if pdf==false: f est une fonction de distribution (DF).
23 non necessairement normalisee
24 - Le tirage aleatoire est fait sur un histogramme
25 Histo(xMin,xMax,nBin) (voir convention dans Histo).
26 - Chaque bin de l'histogramme contient la valeur de la PDF
27 (ou de la DF) au centre du bin: h(i)=f(BinCenter(i))
28 - Les valeurs retournees sont les valeurs du centre des bins
29 pour le tirage non interpole et toutes les valeurs
30 entre [xmin,xmax] pour le tirage interpole
31 - La pdf doit etre interpretee comme etant nulle
32 pour des x<=xmin et x>=xmax
33 - Dans le bin "i" entre [x1,x2[ et de centre x0, h(i)=pdf(x0).
34 Pour le tirage interpole, la DF est approximee par un segment
35 et pdf(x0) est l'exces de proba entre x1 et x2:
36 bin 0 entre [xmin,BinHighEdge(0)[ :
37 la pdf va de 0 a pdf(BinCenter(0))
38 bin 1 entre [BinLowEdge(1),BinHighEdge(1)[:
39 la pdf va de pdf(BinCenter(0)) a pdf(BinCenter(1))
40 ...
41 bin n-1 entre [BinLowEdge(n-1),xmax[:
42 la pdf va de pdf(BinCenter(n-2)) a pdf(BinCenter(n-1))
43\endverbatim
[3075]44*/
[3109]45FunRan::FunRan(FunRan::Func f, r_8 xMin, r_8 xMax, int_4 nBin, bool pdf)
46 : Histo(xMin,xMax,nBin)
[220]47{
[3109]48 if(nBin<=1)
[2840]49 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
[3109]50 for(int_4 i=0;i<nBin;i++) (*this)(i) = f(BinCenter(i));
51 create_DF(pdf);
52}
[2840]53
[3109]54/********* Methode *********/
55/*! Creator from a ClassFunc
56See FunRan::FunRan(FunRan::Func...) for further comments.
57*/
58FunRan::FunRan(ClassFunc& f, r_8 xMin, r_8 xMax, int_4 nBin, bool pdf)
59 : Histo(xMin,xMax,nBin)
60{
61 if(nBin<=1)
62 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
63 for(int_4 i=0;i<nBin;i++) (*this)(i) = f(BinCenter(i));
64 create_DF(pdf);
[220]65}
66
[3075]67/********* Methode *********/
[3109]68/*! Creator from an table.
69If pdf=true, tab is a probability density fonction (not necessary normalised).
70If pdf=false, tab is a distribution function (not necessarly normalized to 1).
[3075]71The return random values will be between 0 and nBin-1.
72See FunRan::FunRan(FunRan::Func...) for further comments.
73*/
[3109]74FunRan::FunRan(r_8 *tab, int_4 nBin, bool pdf)
[2840]75: Histo(-0.5,nBin-0.5,nBin)
[220]76{
[3109]77 if(nBin<=1)
78 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
79 for(int_4 i=0;i<nBin;i++) (*this)(i) = tab[i];
80 create_DF(pdf);
[220]81}
82
[3075]83/********* Methode *********/
[3109]84/*! Creator from an table.
85If pdf=true, tab is a probability density fonction (not necessary normalised).
86If pdf=false, tab is a distribution function (not necessarly normalized to 1).
[3075]87The content of tab is identified has the content of
88an Histogram define by Histo(xMin,xMax,nBin).
89See FunRan::FunRan(FunRan::Func...) for further comments.
90*/
[3109]91FunRan::FunRan(r_8 *tab, int_4 nBin, r_8 xMin, r_8 xMax, bool pdf)
[2840]92: Histo(xMin,xMax,nBin)
[220]93{
[3109]94 if(nBin<=1)
95 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
96 for(int_4 i=0;i<nBin;i++) (*this)(i) = tab[i];
97 create_DF(pdf);
[220]98}
99
[3075]100/********* Methode *********/
[3109]101/*! Creator from an histogram
102If pdf=true, h is a probability density fonction (not necessary normalised).
[3075]103If pdf=false, h is a distribution function (not necessarly normalized to 1).
104See FunRan::FunRan(FunRan::Func...) for further comments.
105*/
[2840]106FunRan::FunRan(Histo &h, bool pdf)
[3109]107 : Histo(h)
[2838]108{
[3109]109 if(mBins<=1)
110 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
111 create_DF(pdf);
112}
[2840]113
[3109]114/********* Methode *********/
115void FunRan::create_DF(bool pdf)
116// Creation (si necessaire) et normalisation de la DF
117{
118 // On fabrique la FD si necessaire
119 if(pdf)
120 for(int_4 i=1;i<mBins;i++) (*this)(i) += (*this)(i-1);
[2840]121
[3109]122 // On normalise la FD
[2840]123 if((*this)(mBins-1)<=0.)
124 throw RangeCheckError("FunRan::FunRan(Histo) not a distribution function last bin is <=0");
125 for(int_4 i=0;i<mBins;i++) (*this)(i) /= (*this)(mBins-1);
[2838]126}
127
[3075]128/********* Methode *********/
129/*! Tirage avec retour du numero de bin entre 0 et mBins-1.
130It returns the first bin whose content is greater or equal
[3109]131to the random uniform number (in [0,1[)
[3075]132*/
[1092]133int_4 FunRan::BinRandom()
[220]134{
[2840]135 // recherche du premier bin plus grand ou egal a z
136 r_8 z=drand01();
137 for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) return i;
138 return mBins-1;
[220]139}
140
[3075]141/********* Methode *********/
142/*! Tirage avec retour abscisse du bin non interpole. */
[1092]143r_8 FunRan::Random()
[220]144{
[2840]145 r_8 z=drand01();
146 int ibin = mBins-1;
[3109]147 for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) {ibin=i; break;}
[2840]148 return BinCenter(ibin);
[220]149}
150
[3109]151/********* Methode *********/
152/*! Tirage avec retour abscisse du bin interpole. */
153r_8 FunRan::RandomInterp(void)
154{
155 r_8 z=drand01();
156 int ibin = mBins-1;
157 r_8 z1=0., z2;
158 for(int_4 i=0;i<mBins;i++) {
159 z2 = (*this)(i);
160 if(z<z2) {ibin=i; break;}
161 z1 = z2;
162 }
[220]163
[3109]164 // l'algorithme garanti que "z2-z1 != 0" et "z1<z2"
165 return BinLowEdge(ibin) + (z-z1)/(z2-z1)*binWidth;
166
167}
168
[220]169////////////////////////////////////////////////////////////////////////////
[3075]170/*!
171 \class SOPHYA::FunRan2D
172 \ingroup NTools
173 Classe for generating random variables from 2D function
174*/
[220]175
[3075]176/********* Methode *********/
177/*! Creator for random from a table */
[1092]178FunRan2D::FunRan2D(r_8 *tab, int_4 nBinX, int_4 nBinY)
[220]179{
180 // Tirage en X, somme sur les Y.
[1092]181 r_8* tabX = new r_8[nBinX];
182 for (int_4 i=0; i<nBinX; i++) {
[220]183 tabX[i] = 0;
[1092]184 for (int_4 j=0; j<nBinY; j++) {
[220]185 tabX[i] += tab[i*nBinY +j];
186 }
187 }
188 ranX = new FunRan(tabX, nBinX);
189 delete[] tabX;
190
[2870]191 ranY = new FunRan* [nBinX];
[220]192
[1092]193 for (int_4 k=0; k<nBinX; k++)
[220]194 ranY[k] = new FunRan(tab + nBinY*k, nBinY);
195
196 nx = nBinX;
197}
198
[3075]199/********* Methode *********/
200/*! Creator for random from a table */
[1092]201FunRan2D::FunRan2D(r_8 **tab, int_4 nBinX, int_4 nBinY)
[220]202{
203 // Tirage en X, somme sur les Y.
[1092]204 r_8* tabX = new r_8[nBinX];
205 for (int_4 i=0; i<nBinX; i++) {
[220]206 tabX[i] = 0;
[1092]207 for (int_4 j=0; j<nBinY; j++) {
[220]208 tabX[i] += tab[i][j];
209 }
210 }
211 ranX = new FunRan(tabX, nBinX);
212
[2870]213 ranY = new FunRan* [nBinX];
[220]214
[1092]215 for (int_4 k=0; k<nBinX; k++)
[220]216 if (tabX[k] != 0)
217 ranY[k] = new FunRan(tab[k], nBinY);
218 else ranY[k] = NULL;
219
220 delete[] tabX;
221 nx = nBinX;
222}
223
[3075]224/********* Methode *********/
225/*! Destructor */
[220]226FunRan2D::~FunRan2D()
227{
[1092]228 for (int_4 i=nx-1; i>=0; i--)
[220]229 delete ranY[i];
230
231 delete[] ranY;
232
233 delete ranX;
234}
235
[3075]236/********* Methode *********/
237/*! Tirage avec retour du numeros de bin. */
[1092]238void FunRan2D::BinRandom(int_4& x, int_4& y)
[220]239{
240 x = ranX->BinRandom();
241 y = ranY[x]->BinRandom();
242}
243
[3075]244/********* Methode *********/
245/*! Tirage avec retour abscisse et ordonnee du bin interpole. */
[1092]246void FunRan2D::Random(r_8& x, r_8& y)
[220]247{
248 x = ranX->Random();
[1092]249 int_4 i = int_4(ceil(x));
[220]250 y = ranY[i]->Random();
251}
[3075]252
253
254
255/////////////////////////////////////////////////////////////////
256/*
[3109]257**** Remarques sur complex< r_8 > ComplexGaussRan(double sig) ****
258
259--- variables gaussiennes x,y independantes
260x gaussien: pdf f(x) = 1/(sqrt(2Pi) Sx) exp(-(x-Mx)^2/(2 Sx^2))
261y gaussien: pdf f(y) = 1/(sqrt(2Pi) Sy) exp(-(y-My)^2/(2 Sy^2))
[3075]262x,y independants --> pdf f(x,y) = f(x) f(y)
[3109]263On a:
264 <x> = Integrate[x*f(x)] = Mx
265 <x^2> = Integrate[x^2*f(x)] = Mx^2 + Sx^2
266
267--- On cherche la pdf g(r,t) du module et de la phase
268 x = r cos(t) , y = r sin(t)
269 r=sqrt(x^2+y^2 , t=atan2(y,x)
270 (r,t) --> (x,y): le Jacobien = r
271
[3075]272 g(r,t) = r f(x,y) = r f(x) f(y)
273 = r/(2Pi Sx Sy) exp(-(x-Mx)^2/(2 Sx^2)) exp(-(y-My)^2/(2 Sy^2))
[3109]274
[3075]275- Le cas general est complique
276 (cf D.Pelat cours DEA "bruits et signaux" section 4.5)
[3109]277
[3075]278- Cas ou "Mx = My = 0" et "Sx = Sy = S"
[3109]279 c'est la pdf du module et de la phase d'un nombre complexe
280 dont les parties reelles et imaginaires sont independantes
281 et sont distribuees selon des gaussiennes de variance S^2
[3075]282 g(r,t) = r/(2Pi S^2) exp(-r^2/(2 S^2))
283 La distribution de "r" est donc:
284 g(r) = Integrate[g(r,t),{t,0,2Pi}]
285 = r/S^2 exp(-r^2/(2 S^2))
286 La distribution de "t" est donc:
287 g(t) = Integrate[g(r,t),{r,0,Infinity}]
288 = 1 / 2Pi (distribution uniforme sur [0,2Pi[)
289 Les variables aleatoires r,t sont independantes:
[3109]290 g(r,t) = g(r) g(t)
291On a:
292 <r> = Integrate[r*g(r)] = sqrt(PI/2)*S
293 <r^2> = Integrate[r^2*g(r)] = 2*S^2
294 <r^3> = Integrate[r^3*g(r)] = 3*sqrt(PI/2)*S^3
295 <r^4> = Integrate[r^4*g(r)] = 8*S^4
296
[3097]297- Attention:
[3109]298La variable complexe "c = x+iy = r*exp(i*t)" ainsi definie verifie:
299 <|c|^2> = <c c*> = <x^2+y^2> = <r^2> = 2 S^2
[3097]300Si on veut generer une variable complexe gaussienne telle que
[3109]301 <c c*> = s^2 alors il faut prendre S = s/sqrt(2) comme argument
302
[3075]303*/
Note: See TracBrowser for help on using the repository browser.