Connaissez-vous des méthodes de calcul de câbles porteurs de téléphériques ?
Pour ma part, j'ai développé deux logiciels de calcul:
- Une version pour les téléphériques dont les câbles sont tirés par contrepoids: GHTyro sur le site Remontées Mécaniques
- Une autre version pour les TPH à cables fixes, tenant compte de l'allongement des câbles. Avis aux programmeurs:
Pour le moment, je ne mets que le programme en langage Pascal (unités de code seulement) (logiciel libre) car je ne sais pas insérer une image ici.
Le programme est développé dans le cadre du projet Vertaco Traverse (sur Google: Vertaco Traverse), une tyrolienne en corde spéléo dépassant le kilomètre de portée.
Code principal
unit Calculs; interface uses SysUtils, Classes, Math, GPFunctions, Forms; // constantes physiques const TAB = #9; DTR = PI/180; RTD = 180/PI; // caractéristiques générales de l'ouvrage type TGeneralCaracteristiques = record // position des ancrages Lo: double; Ho: Double; // nombre d'éléments de câble NbElements : integer; // longueur du câble par défaut LongueurInitialeCable: double; // chargement réparti ChargeRepartie: double; // chargement concentré ValeurQ : double; // caractéristiques des câbles DiametreCables: double; MasseLineique : double; // masse linéique de chaque câble NbCables : integer; ForceRepartie : double; // force répartie: w = g.m.b * // élasticité du cable en Elasticite% par TensionCaracteristique (ex: 2%/80 daN) Elasticite : double; TensionCaracteristique: double; // tension caractéristique // barre sur laquelle est appliqué l'effort concentré NoBarreEffortConcentre: integer; // paramètres de départ TensionInitiale : double; AngleInitial : double; // incréments IncrEffort : double; IncrAngle : double; // tolérance de distance DistanceMax : double; // précision des calculs PrecisionCalcul: double; end; // valeurs calculées (=colonnes du tableau) type TValeursCalculeesTroncon = record // chargement total sur le tronçon: // charge répartie + charge concentrée Charge : double; // longueur déformée du tronçon B_Prime : double; // effort normal à droite Effort : double; // angle du tronçon Angle : double; // composantes dx, dy : double; // coordonnées du point droit Xd, Yd : double; end; // tableau de résultats type TConfigCable = record // efforts normaux No : double; // effort extrémité gauche Nq : double; // effort au niveau de l'équipage N1 : double; // effort extrémité droite // angles Alpha0 : double; // angle extrémité gauche AlphaQg : double; // angle à gauche de l'équipage AlphaQd : double; // angle à droite de l'équipage // longueur d'un élément de câble: b LongueurB : double; // longueur du câble LongCable : double; // numéro de la barre sur laquelle est appliqué le chargement NoBarreChargee: integer; // longueur totale du câble LongueurCable : double; // coordonnées de la charge roulante Xq, Yq : double; // coordonnées de l'ancrage (calculées) X1, Y1 : double; // distance calculée Distance : double; // tableau détaillé ResultatsTroncons: array of TValeursCalculeesTroncon; end; // classe Tyrolienne type TTyrolienne = class function Init(const GC: TGeneralCaracteristiques): Boolean; function GetGeneralCaracteristiques: TGeneralCaracteristiques; procedure SetGeneralCaracteristiques(const GC: TGeneralCaracteristiques); // calcul de la configuration du câble function CalculerConfigurationCable(const NoTableau: integer; // tableau de résultats considéré const NoBarre : integer; // numéro de la barre chargée const N_Initial: double; // effort normal initial const Alpha_0 : double; // Angle initial const LongueurBarre: double; // longueur d'un élément de câble out LongueurDuCable: double; out XAtteint, YAtteint: double; // longueur développée du câble out Angle_1: double; // angle de sortie out N_Final : double // effort en sortie ): double; // distance par rapport à l'ancrage d'arrivée // détermination d'une configuration function DeterminerConfigurationCable(const Application: TApplication; // pour ProcessMessages const NoTableau: integer; // tableau de résultats considéré const NoBarre : integer; // numéro de la barre chargée const N_Dep, N_Arr: double; // effort normal initial const A_Dep, A_Arr: double; // Angle initial const Inc_N, Inc_A: double; // Incréments const Tolerance: double // tolérance ): int64; // détermination de la cote mini et maxi du câble procedure SetCableCotesMinMax(const NoTableau: integer); // résultats éléments de câble function GetTronconCalcule(const NoTableau, Idx: integer): TValeursCalculeesTroncon; // calculer l'angle initial câble déchargé par la méthode de Jippé function GetAlphaInitial(const EffortPrecontrainte: double): double; // numéro de barre en fonction de X function GetNumeroBarre(const NoTableau: integer; const X: double): integer; // position du câble par rapport à l'ancrage function GetDeltaZCable(const NoTableau: integer; const X: double): double; private // flag pour arrêter le calcul FCancelled: boolean; // flag pour les représentations graphiques FCanDraw : boolean; // caractéristiques de l'ouvrage FGeneralCaracteristiques: TGeneralCaracteristiques; // tableaux de résultats FConfigurationsCables : array[0..0] of TConfigCable; // Cote maxi et mini du câble (encombrement du câble) FCoteMiniCable, FCoteMaxiCable: double; public property Cancelled: boolean read FCancelled write FCancelled; property CanDraw : boolean read FCanDraw write FCanDraw; property GeneralCaracteristiques: TGeneralCaracteristiques read FGeneralCaracteristiques write FGeneralCaracteristiques; property CoteMiniCable: double read FCoteMiniCable write FCoteMiniCable; property CoteMaxiCable: double read FCoteMaxiCable write FCoteMaxiCable; end; implementation function TTyrolienne.Init(const GC: TGeneralCaracteristiques): Boolean; var i: integer; RT: TValeursCalculeesTroncon; begin DispMessageMeth(self, 'Init'); Result := False; FCancelled := False; FCanDraw := False; SetGeneralCaracteristiques(GC); if FGeneralCaracteristiques.NbElements = 0 then begin DispMessageMeth(self, 'Init KO: Nombre de barres nul'); Exit; end; // dimensionner les tableaux with FConfigurationsCables[0] do begin SetLength(ResultatsTroncons, 0); SetLength(ResultatsTroncons, 1 + FGeneralCaracteristiques.NbElements); // configurer tableau for i := 0 to FGeneralCaracteristiques.NbElements do begin //RT.Charge := FGeneralCaracteristiques.ChargeRepartie; FillChar(RT, SizeOf(TValeursCalculeesTroncon), 0); end; end; //*) // calcul de valeurs with FGeneralCaracteristiques do begin ChargeRepartie := (MasseLineique /1000) * g * NbCables; LongueurInitialeCable := CalcLongueurCable(Lo, Ho, AngleInitial); end; // afficher données initiales DispMessage('------------------'); DispMessage('Données initiales'); DispMessage('------------------'); with FGeneralCaracteristiques do begin DispMessage(Format(' Lo = %.2f m',[Lo])); DispMessage(Format(' Ho = %.2f m',[Ho])); DispMessage(''); DispMessage(Format(' Longueur câble = %.2f m',[LongueurInitialeCable])); DispMessage(Format(' Câble discrétisé en %d éléments',[NbElements])); DispMessage(''); DispMessage(Format(' Nombre de câbles: %d',[NbCables])); DispMessage(Format(' Diamètre des cables = %.2f mm',[DiametreCables])); DispMessage(Format(' Masse linéique: w = %.2f g/m',[MasseLineique])); DispMessage(Format(' Elasticité: E = %.2f%% sous %.2f',[100 * Elasticite, TensionCaracteristique])); DispMessage(''); DispMessage(Format(' Charge répartie G = %.2f N',[ChargeRepartie])); DispMessage(Format(' Charge concentrée Q = %.2f N sur la barre #%d)',[ValeurQ, NoBarreEffortConcentre])); DispMessage(''); DispMessage(Format(' Tension initiale = %.2f N',[TensionInitiale])); DispMessage(Format(' Angle initial = %.5f °',[AngleInitial])); DispMessage(''); DispMessage(Format(' Incrément efforts = %.2f N',[IncrEffort])); DispMessage(Format(' Incrément angle = %.5f °',[IncrAngle])); DispMessage(''); DispMessage(Format(' Tolérance distance = %.2f m',[DistanceMax])); DispMessage('------------------'); end; end; function TTyrolienne.GetGeneralCaracteristiques: TGeneralCaracteristiques; begin Result := FGeneralCaracteristiques; end; procedure TTyrolienne.SetGeneralCaracteristiques(const GC: TGeneralCaracteristiques); begin FGeneralCaracteristiques := GC; end; // calcul de la configuration du câble // retourne la distance à l'appui //ce code a l'air de bien fonctionner function TTyrolienne.CalculerConfigurationCable(const NoTableau: integer; // tableau de résultats considéré const NoBarre : integer; // numéro de la barre chargée const N_Initial: double; // effort normal initial const Alpha_0 : double; const LongueurBarre: double; // longueur d'un élément de câble out LongueurDuCable: double; out XAtteint, YAtteint: double; // écart par rapport à l'appui out Angle_1 : double; // angle de sortie out N_Final : double // effort en sortie ): double; // Angle initial var i,Nb: integer; Am: Double; Eq101a, Eq101b: double; b: double; begin Result := 1e10; //DispMessageMeth(self, Format('CalculerConfigurationCable: Cas %d - Barre %d',[NoTableau, NoBarre])); //DispMessage(Format('N_G = %.2f - A_G = %.5f',[N_Initial, RTD *Alpha_0])); // b: longueur initiale des tronçons b := LongueurBarre; //WriteLn(b); with FConfigurationsCables[NoTableau] do begin // longueur cable LongCable := 0.00; with ResultatsTroncons[0] do begin Angle := Alpha_0; Charge := FGeneralCaracteristiques.ChargeRepartie * b; B_Prime := B; Effort := N_Initial; dx := 0.00; dy := 0.00; Xd := 0.00; Yd := 0.00; end; //with ResultatsTroncons[0] do begin Nb:= FGeneralCaracteristiques.NbElements; LongueurDuCable := 0.00; for i := 1 to Nb do begin ResultatsTroncons[i].Charge := FGeneralCaracteristiques.ChargeRepartie * b; if (i = NoBarre) then begin// ajout des forces concentrées ResultatsTroncons[i].Charge := ResultatsTroncons[i].Charge + FGeneralCaracteristiques.ValeurQ; end; // ajout du poids du blaireau qui a mis sa poignée à l'envers ... ResultatsTroncons[34].Charge := ResultatsTroncons[34].Charge + 1000.00; Eq101a := CalcEqu101a(ResultatsTroncons[i-1].Effort, ResultatsTroncons[i-1].Angle, 0.00); Eq101b := CalcEqu101b(ResultatsTroncons[i-1].Effort, ResultatsTroncons[i-1].Angle, ResultatsTroncons[i].Charge); //WriteLn(Eq101a, Eq101b); ResultatsTroncons[i].Effort := CalcN1(Eq101a, Eq101b); ResultatsTroncons[i].Angle := CalcAlpha1(Eq101a, Eq101b); // calcul de b' ResultatsTroncons[i].B_Prime := CalcBPrime(b, FGeneralCaracteristiques.Elasticite, ResultatsTroncons[i-1].Effort, ResultatsTroncons[i].Effort, FGeneralCaracteristiques.TensionCaracteristique);// //); // WriteLn(RTD*ResultatsTroncons[i-1].Angle, RTD*ResultatsTroncons[i].Angle); // longueur câble LongueurDuCable := LongueurDuCable + ResultatsTroncons[i].B_Prime; LongCable := LongueurDuCable; // composantes de b': angle moyen Am := AngleMoy(ResultatsTroncons[i-1].Angle, ResultatsTroncons[i].Angle); ResultatsTroncons[i].dx := CalcBPrimeX(ResultatsTroncons[i].B_Prime, Am); ResultatsTroncons[i].dy := CalcBPrimeY(ResultatsTroncons[i].B_Prime, Am); // coordonnées de l'extrémité de la barre ResultatsTroncons[i].Xd := ResultatsTroncons[i-1].Xd + ResultatsTroncons[i].dx; ResultatsTroncons[i].Yd := ResultatsTroncons[i-1].Yd + ResultatsTroncons[i].dy; end; //for i := 0 to FGeneralCaracteristiques.NbElements-1 do begin // longueur corrigée de la barre = longueur de l'élément n°1. //DispMessage (Format('b = %.2f, b'' = %.2f',[LongueurBarre, ResultatsTroncons[Nb].B_Prime])); //LongueurBarre := ResultatsTroncons[Nb].B_Prime; // écart = extrémités de la barre XAtteint := ResultatsTroncons[Nb].Xd;// - FGeneralCaracteristiques.Lo; YAtteint := ResultatsTroncons[Nb].Yd;// - FGeneralCaracteristiques.Ho; // distance //Distance := Hypot(DeltaX, DeltaY); Distance := Hypot(ResultatsTroncons[Nb].Xd - FGeneralCaracteristiques.Lo, ResultatsTroncons[Nb].Yd - FGeneralCaracteristiques.Ho); // angle à l'extrémité du câble Angle_1 := ResultatsTroncons[Nb].Angle; N_Final := ResultatsTroncons[Nb].Effort; // valeur de retour Result := Distance; end; //with FConfigurationsCables[NoTableau] do begin end; // détermination d'une configuration // Valeur de retour: nombre d'itérations function TTyrolienne.DeterminerConfigurationCable(const Application: TApplication; // pour ProcessMessages const NoTableau: integer; // tableau de résultats considéré const NoBarre : integer; // numéro de la barre chargée const N_Dep, N_Arr: double; // effort normal initial const A_Dep, A_Arr: double; // Angle initial (radians) const Inc_N, Inc_A: double; // Incréments const Tolerance: double // tolérance ): int64; var // écarts-types angles et efforts StdDevAngs, // = DTR * 8.00; StdDevEffort: double; // = 2000; i: integer; // angle d'entrée Alpha_G: double; // dilution angulaire Alpha_Dilution: double; // effort d'entrée N_Gauche: double; // dilution de l'effort normal N_Dilution: double; //--------------------------------- LCable: double; LBR : double; // longueur de la barre élémentaire LongueurCable0: double; //longueur cable avant détermination LongueurCable1: double; //longueur cable après détermination LongCablePrecontraint: double; // longueur du câble précontraint XAtteint, YAtteint : double; // écart en X et Y par rapport à l'appui IncrL, IncrA : double; // incréments Distance : double; // distance à un ancrage // corde ravalée à chaque itération CableRavale : double; // différences DeltaX, DeltaY : double; // angle de sortie Alpha_D: double; // effort de sortie N_Droite : double; // Distance mini DistMini: double; // NbIterations NbIters: Int64; begin Result := -1; FCancelled := False; // écarts-types StdDevAngs := DTR * 10.00; // = DTR * 8.00; StdDevEffort:= FGeneralCaracteristiques.TensionInitiale * 0.1; // initialisation du générateur de nombres aléatoires Randomize(); DispMessageMeth(self, Format('DeterminerConfigurationCable: Cas %d - Barre %d',[NoTableau, NoBarre])); DispMessage(''); DispMessage(Format('Efforts: de %f a %f',[N_Dep, N_Arr])); DispMessage(Format('Angles : de %f a %f',[RTD * A_Dep, RTD * A_Arr])); DispMessage(''); // Première détermination pour obtenir la configuration du câble déchargé: angle et effort initiaux //-------------------------------------------------------------------------------------- Alpha_G := A_Dep; N_Gauche := N_Dep; DispMessage(Format('Angle départ : %f - Effort initial %f',[RTD * Alpha_G, N_Gauche])); FGeneralCaracteristiques.LongueurInitialeCable := CalcLongueurCable(FGeneralCaracteristiques.Lo, FGeneralCaracteristiques.Ho, Alpha_G ); //------------------------------------------------ LongueurCable0 := FGeneralCaracteristiques.LongueurInitialeCable; LBR := LongueurCable0 / FGeneralCaracteristiques.NbElements; LCable := 0; // Première détermination pour le calcul de la longueur du câble ravalé Distance := CalculerConfigurationCable(0, // tableau de résultats considéré 0, //FGeneralCaracteristiques.NoBarreEffortConcentre, // numéro de la barre chargée N_Gauche, // effort normal initial Alpha_G, // angle initial en radians LBR, // longueur d'un élément de câble LCable, XAtteint, YAtteint, Alpha_D, N_Droite ); CableRavale := LCable - FGeneralCaracteristiques.LongueurInitialeCable; LongCablePrecontraint := LongueurCable0 - CableRavale; //------------------------------------------------- // Utilisation de la méthode de Monte - Carlo pour la détermination NbIters := 0; DistMini := 1E06; repeat Application.ProcessMessages; if FCancelled then begin DispMessage('*** Calcul arrêté par l''utilisateur ***'); Break; end; //LongueurCable0 := FGeneralCaracteristiques.LongueurInitialeCable; // Deux déterminations pour déterminer la longueur de câble ravalé // for i := 0 to 1 do begin //LBR := LongueurCable0 / FGeneralCaracteristiques.NbElements; LBR := LongCablePrecontraint / FGeneralCaracteristiques.NbElements; LCable := 0; Distance := CalculerConfigurationCable(0, // tableau de résultats considéré NoBarre, //FGeneralCaracteristiques.NoBarreEffortConcentre, // numéro de la barre chargée N_Gauche, // effort normal initial Alpha_G, // angle initial en radians LBR, // longueur d'un élément de câble LCable, XAtteint, YAtteint, Alpha_D, N_Droite ); if (Distance < DistMini) then DistMini := Distance; // correction sur la barre LongueurCable1 := LCable; CableRavale := (LongueurCable1 - LongueurCable0); // * 0.9; //DispMessage(Format('L0 = %.2f - L1 = %.2f - r = %.2f', [LongueurCable0, LongueurCable1, CableRavale])); //LongueurCable0 := LongueurCable0 - CableRavale; //*) // end; // for ou while // nouveau tir Alpha_G := RandRange(A_Dep - DTR * 25, DTR * 25); N_Gauche := RandRange(N_Dep, N_Dep *2.0); //RandG(N_Dep, StdDevEffort); DispMessage(Format('It: %d - Ng = %.0f - A=%.6f -Dist = %.2f',[NbIters, N_Gauche, Alpha_G, DistMini])); Inc(NbIters); //if (NbIters > 5000) then Break; until (DistMini < FGeneralCaracteristiques.PrecisionCalcul); DispMessage(Format('Itération: %d - Distance = %.2f',[NbIters, DistMini])); // affichage de la longueur de câble ravalé: DispMessage(Format('Longueur de câble ravalée: %.2f m',[CableRavale])); // écrire résultats dans fichier with TStringList.Create do begin try Add('Barre' + TAB + 'Charge' + TAB + 'Longueur' + TAB + 'Angle' + TAB + 'Effort' + TAB + 'X' + TAB + 'Y'); Add(''); for i := 0 to FGeneralCaracteristiques.NbElements do begin with FConfigurationsCables[0].ResultatsTroncons[i] do begin Add(Format('%d' + TAB + // barre '%.3f' + TAB + // Charge '%.3f' + TAB + // Longueur '%.5f' + TAB + // Angle '%.2f' + TAB + // Effort '%.2f' + TAB + // X extrémité droite '%.2f' + TAB // Y ext droite ,[ i, Charge, B_Prime, Angle, Effort, Xd, Yd ]) ); end; end; SaveToFile(ExtractFilePath(ParamStr(0)) + 'miaou.txt'); finally end; end; Result := NbIters; end; procedure TTyrolienne.SetCableCotesMinMax(const NoTableau: integer); var i : integer; RT: TValeursCalculeesTroncon; begin DispMessage('SetCableCotesMinMax'); FCoteMiniCable := 0; FCoteMaxiCable := 0; for i := 1 to FGeneralCaracteristiques.NbElements do begin RT := GetTronconCalcule(NoTableau, i); if (RT.Yd > FCoteMaxiCable) then FCoteMaxiCable := RT.Yd; if (RT.Yd < FCoteMiniCable) then FCoteMiniCable := RT.Yd; end; end; // résultats éléments de câble function TTyrolienne.GetTronconCalcule(const NoTableau, Idx: integer): TValeursCalculeesTroncon; var CFC: TConfigCable; begin CFC := FConfigurationsCables[NoTableau]; Result := CFC.ResultatsTroncons[Idx]; end; // calculer l'angle initial câble déchargé // par la méthode de Jippé function TTyrolienne.GetAlphaInitial(const EffortPrecontrainte: double): double; const DecrementAngulaireApproche = 0.2 * PI/180.00; DecrementAngulaireFinition = 0.01 * DecrementAngulaireApproche; // anciennement: 0.001 * ... var NbIter : integer; _N0, _N1 : double; PoidsCable: double; Lsur2 : double; AlphaG, AlphaD : double; LgCable : double; aaa, bbb : double; procedure CalcsInternesInWhile; begin CalcPolynomeByAngle(FGeneralCaracteristiques.Lo, FGeneralCaracteristiques.Ho, AlphaG, AlphaD, aaa,bbb); LgCable := CalcLengthArcParabole(aaa,bbb, FGeneralCaracteristiques.Lo); PoidsCable := LgCable * FGeneralCaracteristiques.ChargeRepartie; AlphaD := ArcTan(ValueDerivPolynomeForX(aaa,bbb, FGeneralCaracteristiques.Lo)); _N0:=GetN0(PoidsCable, AlphaG, AlphaD); _N1:=GetN1(PoidsCable, AlphaG, AlphaD); end; begin _N0:=1e9; NbIter:=0; AlphaG:=Arctan(FGeneralCaracteristiques.Ho / FGeneralCaracteristiques.Lo) - DecrementAngulaireFinition; // Itérations d'approche while(_N0>EffortPrecontrainte) do begin try Inc(NbIter); CalcsInternesInWhile; AlphaG:=AlphaG - DecrementAngulaireApproche; except dispMessage('666'); end; // try end; // while // on prépare la finition AlphaG:=AlphaG + 2 * DecrementAngulaireApproche; CalcsInternesInWhile; // Itérations de finition NbIter:=0; while(_N0 > EffortPrecontrainte) do begin try Inc(NbIter); CalcsInternesInWhile; AlphaG:=AlphaG - DecrementAngulaireFinition; except DispMessage('666'); end; end; //while // résultats (* Lsur2:= Lo/2; fMax := (Ho/Lo) * Lsur2 - ValuePolynomeForX(a,b, Lsur2); // flèche maxi LCorde := Hypot(Lo, Ho); AlphaC := ArcCos(Lo/LCorde); AlphaM := ArcTan(ValueDerivPolynomeForX(a,b,Lsur2)); N1:=GetN1(PoidsCable,AlphaG, AlphaD); // affichage de la géométrie du câble //*) Result := AlphaG; end; // numéro de barre en fonction de X OK. // A n'utiliser qu'après une détermination. function TTyrolienne.GetNumeroBarre(const NoTableau: integer; const X: double): integer; var i: integer; B0, B1: TValeursCalculeesTroncon; begin Result := -1; for i:=1 to FGeneralCaracteristiques.NbElements do begin B0 := GetTronconCalcule(NoTableau, i-1); B1 := GetTronconCalcule(NoTableau, i); //DispMessage(Format('%d - %f - %f %f',[I, X, B0.Xd, B1.Xd])); if (IsInRange(X, B0.Xd, B1.Xd)) then begin Result := i; exit; end; end; end; // position du câble par rapport à l'ancrage function TTyrolienne.GetDeltaZCable(const NoTableau: integer; const X: double): double; var NB: integer; B0, B1: TValeursCalculeesTroncon; dx, dy: double; m : double; begin Result := -1E06; // valeur d'erreur NB := GetNumeroBarre(NoTableau, X); if (NB=0) then Exit; B0 := GetTronconCalcule(NoTableau, NB-1); B1 := GetTronconCalcule(NoTableau, NB); dx := B1.XD - B0.XD; dy := B1.YD - B0.YD; m := dy / dx; Result := B0.YD + m * (X - B0.XD) - FGeneralCaracteristiques.Ho; // cote de l'ancrage //DispMessage(Format('GetDeltaZCable: %d, %f', [NB, Result])); end; end.
Unité Pascal de fonctions générales
unit GPFunctions; interface uses SysUtils, Math, Classes; function IsInRange(const V, V1, V2: double): boolean; // affichage de débug procedure DispMessage(const Msg: string); procedure DispMessageMeth(const Obj: TObject; const Meth: string); // calculs de polynomes (longueurs, paramètres) // calcul de la longueur développée d'une section de parabole function CalcLengthArcParabole(const a,b,L: Double): Double; // calcul des valeurs y pour les polynomes et leurs dérivées function ValuePolynomeForX(const aa,bb,xx: Double):Double; function ValueDerivPolynomeForX(const aa,bb, xx: Double): Double; //calcul du polynome avec angle imposé procedure CalcPolynomeByAngle(const L,H: Double; const A0: Double; var A1: Double; var aa,bb: Double); // calcul de la longueur d'un câble // déterminé par sa parabole* function CalcLongueurCable(const L, H, A0: double): double; // calcul de la longueur b' du tronçon déformé function CalcBPrime(const b, e, T0, T1, Tn: double): double; // calcul des composantes de b' en fonction de Alpha0 et Alpha1 function AngleMoy(const A0, A1: double): double; function CalcBPrimeX(const BPrime, Am: double): double; function CalcBPrimeY(const BPrime, Am: double): double; // élimination de l'angle Alpha (voir cours) function CalcEqu101a(const N0, Alpha0, Fx: double): double; // élimination de l'angle Alpha (voir cours) function CalcEqu101b(const N0, Alpha0, Fy: double): double; // effort en extrémité droite de la barre function CalcN1(const Equ101a, Equ101b: double): double; // angle pour la barre i function CalcAlpha1(const Equ101a, Equ101b: double): double; // calcul des efforts dans le triangle des forces // Données: angles Alpha0 et Alpha1; force F // en cas d'erreur, retourne une valeur négative function GetN1(const F: Double; const Alpha0, Alpha1: Double): Double; function GetN0(const F: Double; const Alpha0, Alpha1: Double): Double; // nb aléatoires sur étendue function RandRange(const Min, Max: double): double; // constantes physiques const EPSILON = 1E-12; const PI_2 = PI/2; const g = 9.810; implementation function IsInRange(const V, V1, V2: double): boolean; begin result := (V >= V1) and (V <= V2); end; procedure DispMessage(const Msg: string); begin WriteLn(msg); end; // affichage des infos d'une méthode d'objet procedure DispMessageMeth(const Obj: TObject; const Meth: string); begin WriteLn(Format('%s.%s',[Obj.ClassName, Meth])); end; //------------------------------------------------------------------------------ // calcul de la longueur initiale du câble // L: Longueur travée // H: Dénivelé // A0: Angle au départ function CalcLongueurCable(const L, H, A0: double): double; var A1: double; aa,bb: double; begin // calcul du polynome d'équilibre d'une section de câble seul CalcPolynomeByAngle(L,H, A0, A1, aa,bb); Result := CalcLengthArcParabole(aa, bb, L); end; // calcul de la longueur développée d'une section de parabole // Ld = Integrale(0, L, sqrt(1+y'²), dx) avec y'= 2.a.x + b function CalcLengthArcParabole(const a,b,L: Double): Double; (* -- sous-expressions de la primitive de sqrt(1+(2a.x + b)**2) -- *) function q2AXB(const aa,bb, XX: Double): Double; begin Result:=2*aa*XX + bb; end; function qRAC2(const aa, bb, XX: Double): Double; begin (* -- utilisation de IntPower(x,n), plus rapide que Power(x,n) -- *) Result:=Sqrt(1 + IntPower(q2AXB(aa,bb, XX),2)); end; (* -- primitive de sqrt(1+(2a.x + b)^2) -- *) function S(const X: Double): Double; var M1, M2: Double; begin M1:=q2AXB(a,b,X); M2:=qRAC2(a,b,X); Result:= (M1*M2 +ln(Abs(4*a*(M1+M2)))) / (4*a); end; begin Result:=S(L) - S(0.00); end; // calcul des valeurs y pour les polynomes function ValuePolynomeForX(const aa,bb,xx: Double):Double; begin Result:= xx * (aa * xx + bb); end; function ValueDerivPolynomeForX(const aa,bb, xx: Double): Double; begin Result:= 2 * aa * xx + bb; end; // calcul du câble - Méthode de Lismonde // 18/07/2008 // calcul de la longueur b' du tronçon déformé // si erreur > longueur négative function CalcBPrime(const b, e, T0, T1, Tn: double): double; var T: Double; begin try //DispMessage(Format('e = %f - T0 = %f T1 = %f TM = %f',[e, T0, T1, Tm])); //T := (T0 + T1)/2; // tension moyenne /(2*Tm) T := (T1+T0)/2; // //T := T/Tm; Result := b * (1 + (e / Tn) * T); //Result := b; except Result :=-1.0; end; end; // calcul des composantes de b' en fonction de Alpha0 et Alpha1 function AngleMoy(const A0, A1: double): double; begin Result := (A0 + A1) / 2; end; function CalcBPrimeX(const BPrime, Am: double): double; begin Result := BPrime * cos(Am); end; function CalcBPrimeY(const BPrime, Am: double): double; begin Result := BPrime * sin(Am); end; // élimination de l'angle Alpha (voir cours) function CalcEqu101a(const N0, Alpha0, Fx: double): double; begin Result := N0 * cos(Alpha0) + Fx; end; // élimination de l'angle Alpha (voir cours) function CalcEqu101b(const N0, Alpha0, Fy: double): double; begin Result := N0 * sin(Alpha0) + Fy; end; // effort en extrémité droite de la barre function CalcN1(const Equ101a, Equ101b: double): double; begin Result := Hypot(Equ101a, Equ101b); end; // angle pour la barre i function CalcAlpha1(const Equ101a, Equ101b: double): double; begin Result := ArcTan(Equ101b/Equ101a); end; //------------------------------------------------------------------------------ //******************************************** // calcul du polynome d'équilibre d'une section de câble seul procedure CalcPolynomeByAngle(const L,H: Double; const A0: Double; var A1: Double; var aa,bb: Double); var TanA0: Double; begin TanA0 := tan(A0); aa:=(H - TanA0*L)/(L*L); bb:=TanA0; A1:=ArcTan(ValueDerivPolynomeForX(aa,bb,L)); end; // calcul des efforts dans le triangle des forces // Données: angles Alpha0 et Alpha1; force F // en cas d'erreur, retourne une valeur négative function GetN1(const F: Double; const Alpha0, Alpha1: Double): Double; var DT:Double; begin Result:=-1.690; DT:= Alpha1 - Alpha0; if (Abs(DT)<EPSILON) then Exit; //Result:=F * sin(PI_2 + Alpha0) / sin(DT); Result:=F * sin(Alpha0 + PI_2) / sin(Alpha1 - Alpha0); end; //------------------------------- function GetN0(const F: Double; const Alpha0, Alpha1: Double): Double; var DT:Double; begin Result:=-1.690; DT:= Alpha1 - Alpha0; if (Abs(DT)<EPSILON) then Exit; Result:=F * sin(PI_2 - Alpha1) / sin(Alpha1 - Alpha0); end; // nombres aléatoires sur étendue function RandRange(const Min, Max: double): double; begin Result := Min + Random * (Max - Min); end; end.