Computational routine
eng


vco

File content


/* Modnumlib Scicos interfacing function
 * Copyright (C) 2009-2011 Alan Layec
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
 
/* vco Scicos VCO with frequency divider Event block
 * Type 4 simulation function ver 1.1 - scilab-3.0
 * 1 decembre 2003 - IRCOM GROUP - Author : A.Layec
 * 10 janvier 2005 : rajout option du rapport de division dynamique
 *                   passage type 4
 *                   remplace otutes les anciennes routines vco
 */

/* REVISION HISTORY :
 * $Log$
 */

#include <math.h>

#include "modnum_lib.h"
#include "scicos_block.h"

/* Calcul la forme temporelle de sortie d'un VCO et ses instants de transitions
 * produit un évènement en sortie toutes les N fois (N:rapport de division)
 *
 * entrées régulières : u1[0] : u3(t) tension de commande
 *                     u2[0] : valeur du rapport de division
 *
 * sorties régulières : y[0] : ys(t)=cos(wot+phi(t)) 
 *                 avec phi(t)=integral(Kv*u3(t))dt pour le cas linéaire 
 *                phi(t)=intégral(gain*tanh(coef*u3(t)))dt pour le cas non-linéaire
 *
 * entrées évènementielles : Tstep pas de résolution
 *
 * sorties évènementielles : evout[0] : Instant de passage aux valeurs rpar[3]*(ipar[0]+u1[0])
 * 
 * paramètres réels :   rpar[0] : pas d'intégration
 *                      rpar[1] : wo pulsation libre de l'oscillateur
 *                      rpar[2] : kv sensibilité
 *                      rpar[3] : instant de transition
 *                    si ipar[1]==1 :
 *                      rpar[4] : gain de la fonction non-linéaire
 *                      rpar[5] : coeffficient de la fonction non-linéaire
 *                      rpar[6] : moyenne du bruit sur la commande
 *                      rpar[7] : variance du bruit sur la commande
 * 
 * paramètres entiers : ipar[0] : réalise une détection dynamique
 *                               0 : passage aux valeurs rpar[1]
 *                                1 : passage aux valeurs rpar[1]*u2[0]
 *                      ipar[1] : réalise la fonction non-linéaire en entrée du VCO
 *                                0 : linéaire
 *                                1 : alpha*tanh(beta*u1[0])
 *                      ipar[2] : réalise un deuxième diviseur de fréquence à rapport entier
 *                                0 : pas de sencond diviseur
 *                              sinon valeur du 2eme rapport
 *                      ipar[3] : type de bruit
 *                                0 : pas de bruit
 *                                1 : bruit normal sur la commande d'entrée
 *
 * état discret : z[0] : valeur de la phase instantannée
 *               z[1] : valeur de l'entrée à l'état précédent
 *                z[2] : valeur de l'angle instantannée
 *               z[3] : valeur de 'angle à l'état précédent
 *                z[4] : compteur incremental de l'angle (ex: ..+2*%pi*N[k-1]+2*%pi*N[k]+..)
 *                z[5] : valeur de la distance à parcourir jusqu'à la prochaine transition (ex : 2*%pi*N)
 *                z[6] : compteur incremental de l'angle du 2eme diviseur (ex: ..+2*%pi*N[k-1]+2*%pi*N[k]+..)
 */

/*prototype*/
void vco(scicos_block *block,int flag)
{
 /*déclaration des variables*/
 double *y;
 double *u1;
 double *u2;

 double step; /*pas d'intégration*/
 double wo; /*pulsation libre*/
 double kv; /*sensibilité*/
 double v; /*valeur de passage*/
 double t; /*valeur du temps de simulation*/
 double f_u; /*valeur de l'entrée(avec sa fonction)*/
 double alpha; /*gain de la fonc non-linéaire*/
 double beta; /*coef de la func non-linéaire*/

 /*Récupération des adresses des ports réguliers*/
 y=(double *)block->outptr[0];
 u1=(double *)block->inptr[0];
 u2=(double *)block->inptr[1];
 step=block->rpar[0];
 wo=block->rpar[1];
 kv=block->rpar[2];
 v=block->rpar[3];

 /* Le flag 1 calcule l'intégrale discrète (trapèze) de la tension d'entrée
  * calcul de l'angle instantannée theta(t)=(wot+phi(t))
  * Place le cos(theta(t)) dans y[]
  */
 if(flag==1)
 {
  /*Calcul de la fonction d'entrée*/
  if (block->ipar[1]!=0)
  {
   alpha=block->rpar[4];
   beta=block->rpar[5];
   f_u=alpha*tanh(beta*u1[0]);
  }
  else f_u=u1[0];
  /*multiplication par sensibilité linéaire*/
  f_u=kv*f_u; 

  if (block->ipar[3]==1) /*Test si bruit*/
  {
   /*déclaration*/
   double phi_n;
   int i,k;

   /*Appel noiseblk_c*/
   noiseblk_c((i=1,&i),(k=1,&k),&block->rpar[7],&block->rpar[6],&phi_n);

   /*rajout bruit*/
   f_u=f_u+(phi_n);
  }
  /*Calcul de la phase instantannée : intégrale de la valeur d'entrée par la méthode des trapèzes*/
  block->z[0]=(step/2)*(f_u+block->z[1])+block->z[0];
  /*Mise en mémoire de f_u*/
  block->z[1]=f_u;
  /*Calcul de l'angle wo*t+phi(t)*/
  t=get_scicos_time(); /*récupération de la valeur du temps*/
  block->z[2]=t*wo+block->z[0];

  /*Calcul du cos(wo*t+phi(t))*/
  y[0]=cos(block->z[2]);
 }

 /* Le flag 3 détermine l'instant de passage de theta(t) à rpar[3]*ipar[0]->z[5]
  * par une méthode d'extrapolation et place le résultat dans tvec[0]
  */

 else if(flag==3)
 {
  if (block->ipar[0]==1)
  {
   /*déclaration*/
   double *u2;
   /*récupération adresse*/
   u2=(double *)block->inptr[1];
   /*fprintf(stderr,"U2[0]=%f\n",u2[0]);*/
   block->z[5]=v*u2[0];
  }
  else block->z[5]=v;
  /*block->z[5]=v*block->ipar[0];*/

  /*Teste si la valeur de transistion est dépassée*/
  if((block->z[2]-block->z[4])>=block->z[5])
  {
   /*Calcul de l'instant de transition*/
   block->evout[0]=(((block->z[4]+block->z[5])-block->z[3])*step)/(block->z[2]-block->z[3]);

   /*Incrément valeur z[4]*/
   block->z[4]=block->z[4]+block->z[5];
  }

  /*Test si il existe un deuxième port de sortie evènenemtiel*/
  /*fprintf(stderr,"nevout=%d\n",block->nevout);*/
  if(block->ipar[2]!=0) 
  {
   if((block->z[2]-block->z[6])>=v*block->ipar[2])
   {
    /*Calcul de l'instant de transition*/
    block->evout[1]=(((block->z[6]+v*block->ipar[2])-block->z[3])*step)/(block->z[2]-block->z[3]);
    /*Incrément valeur z[6]*/
    block->z[6]=block->z[6]+v*block->ipar[2];
   }
  }
 }

 /*Le flag 2 mémorise la valeur de thetha_k-1 dans z[3]*/
 else if(flag==2)
 {
  /*Mise en mémoire de*/
  block->z[3]=block->z[2];
 }
}