1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Alessandro Tasora, Radu Serban, Rainer Gericke
13 // =============================================================================
14 
15 #include "chrono/physics/ChShaft.h"
16 #include "chrono/physics/ChShaftsTorqueConverter.h"
17 #include "chrono/physics/ChSystem.h"
18 
19 namespace chrono {
20 
21 // Register into the object factory, to enable run-time dynamic creation and persistence
CH_FACTORY_REGISTER(ChShaftsTorqueConverter)22 CH_FACTORY_REGISTER(ChShaftsTorqueConverter)
23 
24 ChShaftsTorqueConverter::ChShaftsTorqueConverter()
25     : shaft1(NULL),
26       shaft2(NULL),
27       shaft_stator(NULL),
28       torque_in(0),
29       torque_out(0),
30       state_warning_reverseflow(false),
31       state_warning_wrongimpellerdirection(false) {
32     K = chrono_types::make_shared<ChFunction_Const>(0.9);
33     T = chrono_types::make_shared<ChFunction_Const>(0.9);
34 }
35 
ChShaftsTorqueConverter(const ChShaftsTorqueConverter & other)36 ChShaftsTorqueConverter::ChShaftsTorqueConverter(const ChShaftsTorqueConverter& other) : ChPhysicsItem(other) {
37     shaft1 = NULL;
38     shaft2 = NULL;
39     shaft_stator = NULL;
40 
41     torque_in = other.torque_in;
42     torque_out = other.torque_out;
43 
44     state_warning_reverseflow = other.state_warning_reverseflow;
45     state_warning_wrongimpellerdirection = other.state_warning_wrongimpellerdirection;
46 
47     K = std::shared_ptr<ChFunction>(other.K->Clone());  // deep copy
48     T = std::shared_ptr<ChFunction>(other.T->Clone());  // deep copy
49 }
50 
Initialize(std::shared_ptr<ChShaft> mshaft1,std::shared_ptr<ChShaft> mshaft2,std::shared_ptr<ChShaft> mshaft_stator)51 bool ChShaftsTorqueConverter::Initialize(std::shared_ptr<ChShaft> mshaft1,       // input shaft
52                                          std::shared_ptr<ChShaft> mshaft2,       // output shaft
53                                          std::shared_ptr<ChShaft> mshaft_stator  // stator shaft (often fixed)
54 ) {
55     ChShaft* mm1 = mshaft1.get();
56     ChShaft* mm2 = mshaft2.get();
57     ChShaft* mm_stator = mshaft_stator.get();
58     assert(mm1 && mm2 && mm_stator);
59     assert((mm1 != mm2) && (mm1 != mm_stator));
60     assert((mm1->GetSystem() == mm2->GetSystem()) && (mm1->GetSystem() == mm_stator->GetSystem()));
61 
62     shaft1 = mm1;
63     shaft2 = mm2;
64     shaft_stator = mm_stator;
65 
66     SetSystem(shaft1->GetSystem());
67 
68     return true;
69 }
70 
GetSpeedRatio() const71 double ChShaftsTorqueConverter::GetSpeedRatio() const {
72     double wrel1 = shaft1->GetPos_dt() - shaft_stator->GetPos_dt();
73     double wrel2 = shaft2->GetPos_dt() - shaft_stator->GetPos_dt();
74 
75     if ((fabs(wrel1) < 10e-9) || (fabs(wrel2) < 10e-9))
76         return 0;
77 
78     return wrel2 / wrel1;
79 }
80 
Update(double mytime,bool update_assets)81 void ChShaftsTorqueConverter::Update(double mytime, bool update_assets) {
82     // Inherit time changes of parent class
83     ChPhysicsItem::Update(mytime, update_assets);
84 
85     // update class data
86 
87     state_warning_wrongimpellerdirection = false;
88     state_warning_reverseflow = false;
89 
90     // Compute actual speed ratio
91     double mR = GetSpeedRatio();
92 
93     // The speed ratio must always be in the [0...1] range,
94     // anyway let's correct singular cases:
95 
96     // - it should be unusual that speed ratio >1, say if the impeller
97     //   outruns turbine (if there's a clutch lock-in, this should happen).
98     //   If so, assume a reflection of T curve and a polar reflection of K curve, after 1.
99     if (mR > 1) {
100         mR = 1 - (mR - 1);
101         state_warning_reverseflow = true;
102     }
103 
104     // - if the output shaft is spinning a bit backward, when
105     //   close to stall, maybe win/wout < 0. If so, set as stall anyway:
106     if (mR < 0)
107         mR = 0;
108 
109     // - if input impeller shaft is spinning in negative direction,
110     //   this is assumed as an error: set all torques to zero and bail out:
111     if (shaft1->GetPos_dt() - shaft_stator->GetPos_dt() < 0) {
112         state_warning_wrongimpellerdirection = true;
113         torque_in = 0;
114         torque_out = 0;
115         return;
116     }
117 
118     // Compute actual capacity factor
119     double mK = K->Get_y(mR);
120 
121     // Compute actual torque factor
122     double mT = T->Get_y(mR);
123 
124     // compute input torque (with minus sign because applied TO input thaft)
125     torque_in = -pow((shaft1->GetPos_dt() / mK), 2);
126 
127     if (state_warning_reverseflow)
128         torque_in = -torque_in;
129 
130     // compute output torque (with opposite sign because
131     // applied to output shaft, with same direction of input shaft)
132     if (state_warning_reverseflow) {
133         // in reverse flow situation the converter is always in clutch mode (TR=1)
134         // so the torque cannot be increased
135         torque_out = -torque_in;
136 
137     } else {
138         torque_out = -mT * torque_in;
139     }
140 }
141 
142 //// STATE BOOKKEEPING FUNCTIONS
143 
IntLoadResidual_F(const unsigned int off,ChVectorDynamic<> & R,const double c)144 void ChShaftsTorqueConverter::IntLoadResidual_F(const unsigned int off,  // offset in R residual
145                                                 ChVectorDynamic<>& R,    // result: the R residual, R += c*F
146                                                 const double c           // a scaling factor
147 ) {
148     if (shaft1->IsActive())
149         R(shaft1->GetOffset_w()) += torque_in * c;
150     if (shaft2->IsActive())
151         R(shaft2->GetOffset_w()) += torque_out * c;
152     if (shaft_stator->IsActive())
153         R(shaft_stator->GetOffset_w()) += GetTorqueReactionOnStator() * c;
154 }
155 
156 // SOLVER INTERFACES
157 
VariablesFbLoadForces(double factor)158 void ChShaftsTorqueConverter::VariablesFbLoadForces(double factor) {
159     // Apply torques to the three connected 1D variables:
160     shaft1->Variables().Get_fb()(0) += torque_in * factor;
161     shaft2->Variables().Get_fb()(0) += torque_out * factor;
162     shaft_stator->Variables().Get_fb()(0) += GetTorqueReactionOnStator() * factor;
163 }
164 
165 // FILE I/O
166 
ArchiveOUT(ChArchiveOut & marchive)167 void ChShaftsTorqueConverter::ArchiveOUT(ChArchiveOut& marchive) {
168     // version number
169     marchive.VersionWrite<ChShaftsTorqueConverter>();
170 
171     // serialize parent class
172     ChPhysicsItem::ArchiveOUT(marchive);
173 
174     // serialize all member data:
175     marchive << CHNVP(K);
176     marchive << CHNVP(T);
177     // marchive << CHNVP(shaft1); //***TODO*** serialize with shared ptr
178     // marchive << CHNVP(shaft2); //***TODO*** serialize with shared ptr
179     // marchive << CHNVP(shaft_stator); //***TODO*** serialize with shared ptr
180 }
181 
182 /// Method to allow de serialization of transient data from archives.
ArchiveIN(ChArchiveIn & marchive)183 void ChShaftsTorqueConverter::ArchiveIN(ChArchiveIn& marchive) {
184     // version number
185     /*int version =*/ marchive.VersionRead<ChShaftsTorqueConverter>();
186 
187     // deserialize parent class:
188     ChPhysicsItem::ArchiveIN(marchive);
189 
190     // deserialize all member data:
191     marchive >> CHNVP(K);
192     marchive >> CHNVP(T);
193     // marchive >> CHNVP(shaft1); //***TODO*** serialize with shared ptr
194     // marchive >> CHNVP(shaft2); //***TODO*** serialize with shared ptr
195     // marchive >> CHNVP(shaft_stator); //***TODO*** serialize with shared ptr
196 }
197 
198 }  // end namespace chrono