/* 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]; } }