| [995] | 1 | /**************************************************************************** |
|---|
| 2 | |
|---|
| [5495] | 3 | Copyright 2007 Virginia Polytechnic Institute and State University |
|---|
| [995] | 4 | |
|---|
| 5 | This file is part of the OSSIE ChannelDemo. |
|---|
| 6 | |
|---|
| 7 | OSSIE ChannelDemo is free software; you can redistribute it and/or modify |
|---|
| 8 | it under the terms of the GNU General Public License as published by |
|---|
| 9 | the Free Software Foundation; either version 2 of the License, or |
|---|
| 10 | (at your option) any later version. |
|---|
| 11 | |
|---|
| 12 | OSSIE ChannelDemo is distributed in the hope that it will be useful, |
|---|
| [926] | 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | GNU General Public License for more details. |
|---|
| [995] | 16 | |
|---|
| [926] | 17 | You should have received a copy of the GNU General Public License |
|---|
| [995] | 18 | along with OSSIE ChannelDemo; if not, write to the Free Software |
|---|
| [926] | 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 20 | |
|---|
| [995] | 21 | ****************************************************************************/ |
|---|
| 22 | |
|---|
| [2131] | 23 | |
|---|
| 24 | #include <string> |
|---|
| [926] | 25 | #include <iostream> |
|---|
| 26 | #include "ChannelDemo.h" |
|---|
| 27 | |
|---|
| [5495] | 28 | // Uniform random number generator, (0,1] |
|---|
| 29 | float randf() { |
|---|
| 30 | float x = (float) rand(); |
|---|
| 31 | return x / (float) RAND_MAX; |
|---|
| 32 | } |
|---|
| [926] | 33 | |
|---|
| [5495] | 34 | // Gaussian random number generator w/ zero mean, unit variance, N(0,1) |
|---|
| 35 | void randnf(float * i, float * q) |
|---|
| [926] | 36 | { |
|---|
| [5495] | 37 | // generate two uniform random numbers |
|---|
| 38 | float u1, u2; |
|---|
| [926] | 39 | |
|---|
| [5495] | 40 | // ensure u1 does not equal zero |
|---|
| 41 | do { |
|---|
| 42 | u1 = randf(); |
|---|
| 43 | } while (u1 == 0.0f); |
|---|
| [926] | 44 | |
|---|
| [5495] | 45 | u2 = randf(); |
|---|
| 46 | |
|---|
| 47 | float x = sqrt(-2*logf(u1)); |
|---|
| 48 | *i = x * sinf(6.283185307*u2); |
|---|
| 49 | *q = x * cosf(6.283185307*u2); |
|---|
| [926] | 50 | } |
|---|
| [5495] | 51 | /// Converts float to short, clipping as necessary |
|---|
| 52 | short float2short(float x) { |
|---|
| 53 | short y; |
|---|
| 54 | if (x > SHRT_MAX) { |
|---|
| 55 | y = SHRT_MAX; |
|---|
| 56 | } else if (x < SHRT_MIN) { |
|---|
| 57 | y = SHRT_MIN; |
|---|
| 58 | } else { |
|---|
| 59 | y = (short) x; |
|---|
| 60 | } |
|---|
| 61 | return y; |
|---|
| 62 | } |
|---|
| [926] | 63 | |
|---|
| [5801] | 64 | // rotates a complex vector by theta radians |
|---|
| 65 | void rotate(short I_in, short Q_in, float theta, short &I_out, short &Q_out) { |
|---|
| 66 | float c = cosf(theta); |
|---|
| 67 | float s = sinf(theta); |
|---|
| 68 | |
|---|
| 69 | I_out = (short) ( (float) (I_in*c) - (float) (Q_in*s) ); |
|---|
| 70 | Q_out = (short) ( (float) (I_in*s) + (float) (Q_in*c) ); |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| [5495] | 73 | ChannelDemo_i::ChannelDemo_i(const char *uuid, omni_condition *condition) : |
|---|
| 74 | Resource_impl(uuid), component_running(condition) |
|---|
| [926] | 75 | { |
|---|
| [5495] | 76 | dataInPort = new standardInterfaces_i::complexShort_p("samples_in"); |
|---|
| 77 | dataOutPort = new standardInterfaces_i::complexShort_u("samples_out"); |
|---|
| 78 | |
|---|
| 79 | // Initialize noise standard deviation |
|---|
| 80 | noise_std_dev = 1000; |
|---|
| 81 | |
|---|
| [5801] | 82 | // Initialize phase offset |
|---|
| 83 | phase_offset = 0.0f; |
|---|
| 84 | |
|---|
| [5495] | 85 | //Create the thread for the writer's processing function |
|---|
| 86 | processing_thread = new omni_thread(Run, (void *) this); |
|---|
| 87 | |
|---|
| 88 | //Start the thread containing the writer's processing function |
|---|
| 89 | processing_thread->start(); |
|---|
| 90 | |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | ChannelDemo_i::~ChannelDemo_i(void) |
|---|
| 94 | { |
|---|
| 95 | delete dataInPort; |
|---|
| 96 | delete dataOutPort; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | // Static function for omni thread |
|---|
| 100 | void ChannelDemo_i::Run( void * data ) |
|---|
| 101 | { |
|---|
| 102 | ((ChannelDemo_i*)data)->ProcessData(); |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | CORBA::Object_ptr ChannelDemo_i::getPort( const char* portName ) throw ( |
|---|
| 106 | CORBA::SystemException, CF::PortSupplier::UnknownPort) |
|---|
| 107 | { |
|---|
| 108 | DEBUG(3, ChannelDemo, "getPort() invoked with " << portName) |
|---|
| [2131] | 109 | |
|---|
| 110 | CORBA::Object_var p; |
|---|
| [926] | 111 | |
|---|
| [5495] | 112 | p = dataInPort->getPort(portName); |
|---|
| [926] | 113 | |
|---|
| [2131] | 114 | if (!CORBA::is_nil(p)) |
|---|
| 115 | return p._retn(); |
|---|
| [926] | 116 | |
|---|
| [5495] | 117 | p = dataOutPort->getPort(portName); |
|---|
| [926] | 118 | |
|---|
| [2131] | 119 | if (!CORBA::is_nil(p)) |
|---|
| 120 | return p._retn(); |
|---|
| [926] | 121 | |
|---|
| [2131] | 122 | /*exception*/ |
|---|
| 123 | throw CF::PortSupplier::UnknownPort(); |
|---|
| [926] | 124 | } |
|---|
| 125 | |
|---|
| [5495] | 126 | void ChannelDemo_i::start() throw (CORBA::SystemException, |
|---|
| 127 | CF::Resource::StartError) |
|---|
| [926] | 128 | { |
|---|
| [5495] | 129 | DEBUG(3, ChannelDemo, "start() invoked") |
|---|
| [926] | 130 | } |
|---|
| 131 | |
|---|
| 132 | void ChannelDemo_i::stop() throw (CORBA::SystemException, CF::Resource::StopError) |
|---|
| 133 | { |
|---|
| [5495] | 134 | DEBUG(3, ChannelDemo, "stop() invoked") |
|---|
| [926] | 135 | } |
|---|
| 136 | |
|---|
| [5495] | 137 | void ChannelDemo_i::releaseObject() throw (CORBA::SystemException, |
|---|
| 138 | CF::LifeCycle::ReleaseError) |
|---|
| [926] | 139 | { |
|---|
| [5495] | 140 | DEBUG(3, ChannelDemo, "releaseObject() invoked") |
|---|
| [2131] | 141 | |
|---|
| [995] | 142 | component_running->signal(); |
|---|
| [926] | 143 | } |
|---|
| 144 | |
|---|
| [5495] | 145 | void ChannelDemo_i::initialize() throw (CF::LifeCycle::InitializeError, |
|---|
| 146 | CORBA::SystemException) |
|---|
| [926] | 147 | { |
|---|
| [5495] | 148 | DEBUG(3, ChannelDemo, "initialize() invoked") |
|---|
| [2131] | 149 | } |
|---|
| [926] | 150 | |
|---|
| [8886] | 151 | void |
|---|
| 152 | ChannelDemo_i::query (CF::Properties & configProperties) |
|---|
| 153 | throw (CORBA::SystemException, CF::UnknownProperties) |
|---|
| 154 | { |
|---|
| 155 | // for queries of zero length, return all id/value pairs in propertySet |
|---|
| 156 | if (configProperties.length () == 0) |
|---|
| 157 | { |
|---|
| 158 | configProperties.length (propertySet.length ()); |
|---|
| 159 | for (unsigned int i = 0; i < propertySet.length (); i++) |
|---|
| 160 | { |
|---|
| 161 | configProperties[i].id = CORBA::string_dup (propertySet[i].id); |
|---|
| 162 | configProperties[i].value = propertySet[i].value; |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | return ; |
|---|
| 166 | } |
|---|
| 167 | else { |
|---|
| 168 | for (unsigned int i = 0; i < configProperties.length(); i++) { |
|---|
| 169 | for (unsigned int j=0; j < propertySet.length(); j++) { |
|---|
| 170 | if ( strcmp(configProperties[i].id, propertySet[i].id) == 0 ){ |
|---|
| 171 | configProperties[i].value = propertySet[i].value; |
|---|
| 172 | } |
|---|
| 173 | } |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| [5495] | 178 | void ChannelDemo_i::configure(const CF::Properties& props) |
|---|
| 179 | throw (CORBA::SystemException, |
|---|
| 180 | CF::PropertySet::InvalidConfiguration, |
|---|
| 181 | CF::PropertySet::PartialConfiguration) |
|---|
| [2131] | 182 | { |
|---|
| [8886] | 183 | static int init = 0; |
|---|
| 184 | |
|---|
| [5495] | 185 | DEBUG(3, ChannelDemo, "configure() invoked") |
|---|
| [926] | 186 | |
|---|
| [8886] | 187 | std::cout << "Component - CHANNEL DEMO" << std::endl; |
|---|
| 188 | if (init == 0){ |
|---|
| 189 | std::cout << " ChannelDemo - initial configure call .." << std::endl; |
|---|
| 190 | propertySet.length(props.length()); |
|---|
| 191 | for (unsigned int i=0; i < props.length(); i++) { |
|---|
| 192 | std::cout << "Property Id : " << props[i].id << std::endl; |
|---|
| 193 | propertySet[i].id = CORBA::string_dup(props[i].id); |
|---|
| 194 | propertySet[i].value = props[i].value; |
|---|
| 195 | } |
|---|
| 196 | init = 1; |
|---|
| 197 | return; |
|---|
| 198 | } |
|---|
| 199 | else { |
|---|
| [926] | 200 | |
|---|
| [8886] | 201 | std::cout << "props length : " << props.length() << std::endl; |
|---|
| 202 | //propertySet.length(props.length()); |
|---|
| 203 | std::cout << "ChannelDemo_i::configure set propertySet.length " << propertySet.length() << std::endl; |
|---|
| [5801] | 204 | |
|---|
| [8886] | 205 | for (unsigned int i = 0; i <props.length(); i++) { |
|---|
| 206 | if (strcmp(props[i].id, "DCE:a337c5f0-8245-11dc-860f-00123f63025f") == 0) { |
|---|
| 207 | // noise_std_dev (standard deviation of noise) |
|---|
| 208 | CORBA::Short simple_temp; |
|---|
| 209 | props[i].value >>= simple_temp; |
|---|
| 210 | // Test: setting propertySet[] to the given value. |
|---|
| 211 | noise_std_dev = simple_temp; |
|---|
| 212 | |
|---|
| 213 | std::cout << "Property id : " << props[i].id << std::endl; |
|---|
| 214 | // Update value of this property in propertySet also |
|---|
| 215 | for (unsigned int j=0; j < propertySet.length(); j++ ) { |
|---|
| 216 | if ( strcmp(propertySet[j].id, props[i].id) == 0 ) { |
|---|
| 217 | propertySet[i].value = props[i].value; |
|---|
| 218 | break; |
|---|
| 219 | } |
|---|
| 220 | } |
|---|
| 221 | DEBUG(1, ChannelDemo, "Setting noise standard deviation to " << noise_std_dev); |
|---|
| 222 | } |
|---|
| 223 | else if (strcmp(props[i].id, "DCE:1c4a3eb9-9e3a-4c20-849a-90c6eaef9e5a") == 0) { |
|---|
| 224 | // phase offset (degrees) |
|---|
| 225 | CORBA::Float simple_temp; |
|---|
| 226 | props[i].value >>= simple_temp; |
|---|
| 227 | // Test: Setting propertySet[i] to the given value |
|---|
| 228 | propertySet[i].value = props[i].value; |
|---|
| 229 | phase_offset = simple_temp; |
|---|
| 230 | DEBUG(1, ChannelDemo, "Setting phase offset to " << phase_offset << " degrees"); |
|---|
| 231 | // convert to radians |
|---|
| 232 | phase_offset *= M_PI/180.0f; |
|---|
| 233 | |
|---|
| 234 | std::cout << "Property id : " << props[i].id << std::endl; |
|---|
| 235 | // Update value of this property in propertySet also |
|---|
| 236 | for (unsigned int j=0; j < propertySet.length(); j++ ) { |
|---|
| 237 | if ( strcmp(propertySet[j].id, props[i].id) == 0 ) { |
|---|
| 238 | propertySet[i].value = props[i].value; |
|---|
| 239 | break; |
|---|
| 240 | } |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | } |
|---|
| 244 | else { |
|---|
| 245 | // unknown property |
|---|
| 246 | std::cerr << "ERROR: ChannelDemo_i::configure() unknown property \"" |
|---|
| 247 | << props[i].id << "\"" << std::endl; |
|---|
| 248 | throw CF::PropertySet::InvalidConfiguration(); |
|---|
| 249 | } |
|---|
| [926] | 250 | } |
|---|
| [2131] | 251 | } |
|---|
| 252 | } |
|---|
| [926] | 253 | |
|---|
| [5495] | 254 | void ChannelDemo_i::ProcessData() |
|---|
| [2131] | 255 | { |
|---|
| [5495] | 256 | DEBUG(3, ChannelDemo, "ProcessData() invoked") |
|---|
| [2131] | 257 | |
|---|
| [5495] | 258 | PortTypes::ShortSequence I_out, Q_out; |
|---|
| 259 | |
|---|
| 260 | |
|---|
| [2131] | 261 | PortTypes::ShortSequence *I_in(NULL), *Q_in(NULL); |
|---|
| [5495] | 262 | CORBA::UShort I_in_length, Q_in_length; |
|---|
| 263 | |
|---|
| 264 | // input/output data length |
|---|
| 265 | unsigned int N(0); |
|---|
| 266 | |
|---|
| [5801] | 267 | short I_rotated, Q_rotated; |
|---|
| 268 | |
|---|
| [5495] | 269 | // |
|---|
| 270 | float noise_i(0.0f); |
|---|
| 271 | float noise_q(0.0f); |
|---|
| 272 | |
|---|
| 273 | while(true) { |
|---|
| 274 | dataInPort->getData(I_in, Q_in); |
|---|
| 275 | |
|---|
| 276 | I_in_length = I_in->length(); |
|---|
| 277 | Q_in_length = Q_in->length(); |
|---|
| 278 | |
|---|
| 279 | if (I_in_length == Q_in_length) { |
|---|
| 280 | N = I_in_length; |
|---|
| 281 | } else { |
|---|
| 282 | std::cout << "ERROR! Input I/Q data are not the same length!" << std::endl; |
|---|
| 283 | throw 0; |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | I_out.length(N); |
|---|
| 287 | Q_out.length(N); |
|---|
| 288 | |
|---|
| [5803] | 289 | // add channel impairments |
|---|
| [5495] | 290 | for (unsigned int i=0; i<N; i++) { |
|---|
| [5801] | 291 | // Rotate input by phase_offset radians |
|---|
| 292 | rotate((*I_in)[i], (*Q_in)[i], phase_offset, I_rotated, Q_rotated); |
|---|
| 293 | |
|---|
| 294 | // Add noise |
|---|
| [5495] | 295 | randnf(&noise_i, &noise_q); |
|---|
| 296 | noise_i *= noise_std_dev; |
|---|
| 297 | noise_q *= noise_std_dev; |
|---|
| [5801] | 298 | I_out[i] = I_rotated + float2short(noise_i); |
|---|
| 299 | Q_out[i] = Q_rotated + float2short(noise_q); |
|---|
| [5495] | 300 | } |
|---|
| 301 | |
|---|
| 302 | dataInPort->bufferEmptied(); |
|---|
| 303 | dataOutPort->pushPacket(I_out, Q_out); |
|---|
| [926] | 304 | } |
|---|
| [2131] | 305 | } |
|---|
| [926] | 306 | |
|---|
| [5495] | 307 | |
|---|