• Welcome to Diskuse2 Elektrika.cz. Please login or sign up.
 

Jak v Mosaicu generovat náhodná čísla?

Started by Jan Rittich, 26.08.2013, 21:47

previous topic - next topic

Jan Rittich

26.08.2013, 21:47 Last Edit: 26.08.2013, 21:54 by Miroslav Minařík
Má někdo zkušenosti s naprogramováním generátoru náhodných čísel v Mosaicu?
Asi se mi budou hodit všechny nápady jaký vás napadnou.
" Člověka nemůžeš nic naučit; můžete mu pouze pomoci najít to v sobě samém. " Galileo Galilei

Slavomír Skopalík

Pokud to neni opravdu nutne, tak se pouzivaji generatory psedonahodnych cisel. Tj. zvenku se tvari jako nahodne, ale jejich posloupnost je predem dana.
Maji tu vyhodu, ze v pripade chyby v programu, je mozne cely proces otestovat.
Mezi nejjednodusi patri posuvny register + XOR hradlo z nekterych z poslednich bitu.

Kratke pojednani treba zde:
http://www.kemt.fei.tuke.sk/predmety/KEMT414_AK/_materialy/Cvicenia/kryp_4.pdf

http://en.wikipedia.org/wiki/Random_number_generation

Ukazka kodu (netestoval jsem to):

m_w = <choose-initializer>;    /* must not be zero */
m_z = <choose-initializer>;    /* must not be zero */

uint get_random()
{
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;  /* 32-bit result */
}

Zajisteni opravdu nahodneho generatoru je velmi slozite bez specialniho HW.

Milan Bydžovský

Pokud stačí psedonáhodné číslo, zde je kód přepsaný z Cčka do ST, který lze v PLC využít. Funkce r4_uniform_01 vrací čísla s rovnoměrným rozdělením. Funkční blok r4_normal_01 vrací čísla s pseudonormálním rozdělením, stejně jako r4_normal, který má navíc parametr pro střední hodnotu a odchylku.

Code Select

FUNCTION r4_uniform_01 : REAL
(*
  R4_UNIFORM_01 returns a unit pseudorandom R4.

  This routine implements the recursion

    seed = 16807 * seed mod ( 2**31 - 1 )
    r4_uniform_01 = seed / ( 2**31 - 1 )

  The integer arithmetic never requires more than 32 bits,
  including a sign bit.

  If the initial seed is 12345, then the first three computations are

    Input     Output      R4_UNIFORM_01
    SEED      SEED

       12345   207482415  0.096616
   207482415  1790989824  0.833995
  1790989824  2035175616  0.947702
*)
  VAR_INPUT
    init_seed : BOOL;
  END_VAR
  VAR
    k : DINT;
  END_VAR
  VAR_IN_OUT
    seed : DINT;
  END_VAR
  VAR_EXTERNAL
    AT %SL52 : DINT;
  END_VAR

  if init_seed then
    seed := %SL52;
  end_if;

  k := seed / 127773;

  seed := 16807 * ( seed - k * 127773 ) - k * 2836;

  IF  seed < 0 THEN
    seed := seed + 2147483647;
  END_IF;
//
//  Although SEED can be represented exactly as a 32 bit integer,
//  it generally cannot be represented exactly as a 32 bit real number!
//
  r4_uniform_01 := DINT_TO_REAL(seed) * 4.656612875E-10;

END_FUNCTION

FUNCTION_BLOCK r4_normal_01
(*
  R4_NORMAL_01 returns a unit pseudonormal R4.

  The standard normal probability distribution function (PDF) has
  mean 0 and standard deviation 1.

  The Box-Muller method is used, which is efficient, but
  generates two values at a time.

*)

  VAR_IN_OUT
    seed : DINT;
  END_VAR
  VAR CONSTANT
    PI : REAL := 3.141592653589793;
  END_VAR
  VAR
    used   : DINT := -1;
    seed2  : DINT;
    y      : REAL;
    r1, r2 : REAL;
  END_VAR
  VAR_OUTPUT
    x : REAL;
  END_VAR

  IF ( used = -1 ) THEN
    used := 0;
  END_IF;
//
//  If we've used an even number of values so far, generate two more, return one,
//  and save one.
//
  IF used MOD 2 = 0 THEN
    r1 := r4_uniform_01 ( false, seed );


    seed2 := seed;
    r2 := r4_uniform_01 ( false, seed2 );

    x := sqrt ( -2.0 * log ( r1 ) ) * cos ( 2.0 * PI * r2 );
    y := sqrt ( -2.0 * log ( r1 ) ) * sin ( 2.0 * PI * r2 );
//
//  Otherwise, return the second, saved, value and the corresponding
//  value of SEED.
//
  ELSE
    x := y;
    seed := seed2;
  END_IF;

  used := used + 1;

END_FUNCTION_BLOCK


FUNCTION_BLOCK r4_normal
(*

  R4_NORMAL returns a scaled pseudonormal R4.

  The normal probability distribution function (PDF) is sampled,
  with mean A and standard deviation B.

*)
  VAR
    i_r4_normal_01 : r4_normal_01;
  END_VAR

  VAR_INPUT
    a : REAL;
    b : REAL;
  END_VAR
  VAR_IN_OUT
    seed : DINT;
  END_VAR
  VAR_OUTPUT
    x : REAL;
  END_VAR

  i_r4_normal_01(seed := seed);
  x := a + b * i_r4_normal_01.x;

END_FUNCTION_BLOCK


Jan Rittich

Zatím děkuji za inspiraci pokusím se to použít.
" Člověka nemůžeš nic naučit; můžete mu pouze pomoci najít to v sobě samém. " Galileo Galilei

Erhard Mareček

Použil jsem tohle:

Random                : UDINT;

Random := MOD(Random*214013 + 2531011, 16777216);     // Random generator

Odzkoušeno.