vco
/* Modnumlib Scicos interfacing function
* Copyright (C) 2009 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];
}
}