For the function below, I would not add the noise (Inoise in the code below) in every time step but, for example, only in every second time step. So while dt=0.0025 serves as the time step for the numerical integration, I would, for example, add Inoise only in every second time step (i.e. in 0.005 steps).
What is the best way to insert this into my existing function?
runs = 1000;
t_end = 5;
dt = 0.0025;
t_steps = t_end/dt;
for(int j=0; j<runs; j++){
double vT = v0;
double mT = m0;
double hT = h0;
double nT = n0;
for(int i=0; i<t_steps; i++){
double IStim = 0.0;
if ((delay / dt <= (double)i) && ((double)i <= (delay + duration) / dt))
IStim = I;
mT = (mT + dt * alphaM(vT)) / (1.0 + dt * (alphaM(vT) + betaM(vT)));
hT = (hT + dt * alphaH(vT)) / (1.0 + dt * (alphaH(vT) + betaH(vT)));
nT = (nT + dt * alphaN(vT)) / (1.0 + dt * (alphaN(vT) + betaN(vT)));
const double iNa = gNa * pow(mT, 3.0) * hT * (vT - vNa);
const double iK = gK * pow(nT, 4.0) * (vT - vK);
const double iL = gL * (vT-vL);
const double Inoise = (doubleRand() * knoise * sqrt(gNa * A));
const double IIon = ((iNa + iK + iL) * A) + Inoise;
vT += ((-IIon + IStim) / C) * dt;
voltage[i] = vT;
if(vT > 60.0) {
count++;
break;
}
}
}
return count;
}
You could accumulate the elapsed time and only add the noise once enough steps have passed:
double elapsedTime = 0;
double INoiseThreshold = 0.005;
for(int j=0; j<runs; j++){
//...
for(int i=0; i<t_steps; i++){
//...
double Inoise = 0;
elapsedTime += dt;
if(elapsedTime >= INoiseThreshold){
Inoise = (doubleRand() * knoise * sqrt(gNa * A));
elapsedTime = 0;
}
const double IIon = ((iNa + iK + iL) * A) + Inoise;
//...
}
}
return count;
Instead of comparing the floating point numbers directly, you could check if their differences are within an small epsilon to allow for rounding errors.
Instead of making the value of Inoise dependent on the condition, you could make the presence in the IIon formula dependent e.g.:
const double IIon = ((iNa + iK + iL) * A) + (elapsedTime >= INoiseThreshold) ? Inoise : 0;
just remember to reset elapsedTime once it surpassed the threshold.
Related
I am trying to devellop a small option pricer using win32 API.
To do that I use monte carlo simulation to compute the price of a call option but there is a mistake in my simulation and I don't see where.
Someone can tell me why the two prices are different ?
The price for a call with the black and scholes formula is 6.84 but the one given by the monte carlo simulation is 7.54.
(There is no error in the price from the black and scholes formula)
This is the code :
std::vector<double> vecteur_pas(double T) {
std::vector<double> pas;
pas.push_back(0);
double x = T / nb_pas;
for (int i = 1; i <= nb_pas; i++) {
pas.push_back(pas[i-1] + x);
}
return pas;
std::vector <double> NormalRnd() {
std::vector <double> brow;
brow.push_back(0);
double unif_1, unif_2;
for (int i = 0; i < nb_pas; i++) {
unif_1 = (double(rand() + 0.5)) / (double(RAND_MAX) + 1.0);
unif_2 = (double(rand() + 0.5)) / (double(RAND_MAX) + 1.0);
brow.push_back(sqrt(-2 * log(unif_1)) * cos(2 * M_PI * unif_2));
}
return brow;
std::vector<double> MBG(double S, double mu, double vol, double T) {
std::vector<double> traj;
traj.push_back(S);
std::vector <double> b =NormalRnd();
std::vector<double> pas = vecteur_pas(T);
double drift = 0.0;
double diffusion = 0.0;
for (int i = 1; i <= nb_pas; i++) {
drift = (mu - 0.5 * pow(vol, 2)) * (pas[i]-pas[i-1]);
diffusion = vol * b[i] * sqrt(pas[i] - pas[i - 1]);
traj.push_back(traj[i - 1] * exp(drift + diffusion));
}
return traj;
The MBG function is called in a loop after :
for (int i = 0; i < 100000; i++)
{
if ((i % 1000) == 0)
{
SendDlgItemMessage(Calcul, IDE_PB, PBM_STEPIT, 0, 0);
}
vector<double> proc_prix = MBG(actif.S, actif.r, actif.v, actif.T);
double last_value = proc_prix[proc_prix.size() - 1];
Prime = Prime + std::max(last_value - actif.K, 0.0);
}
Prime = Prime / 100000;
This is the output
I have been working on creating a mixed wave signal. My code is in c++ :
Server signal:
void server_sineWave(BitDepth buffer[], double sin_freq, double beep_freq) {
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.5;
QWORD c = 0;
double d = (samplerate / sin_freq);
int initial = NUM_SAMPLES / 25;
for (QWORD i = 0; i < NUM_SAMPLES; i += channels) {
buffer[i] = amplitude * sin((2 * pi * sin_freq * i) / samplerate); // sin wave generated at "freq"
if (i == initial) {
for (QWORD j = 0; j < 480; j++) {
double stream = amplitude * sin((2 * pi * sin_freq * i / samplerate));
double beep = amplitude * sin((2 * pi * beep_freq * j / samplerate));
double multiplier = .4 * (1 - cos(2 * pi * j / 480));
buffer[i] = stream + (beep * multiplier);
i++;
}
initial = i + 19200.0;
}
}
}
Client signal:
void client_sineWave(BitDepth buffer[], double sin_freq, double beep_freq) {
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.5;
QWORD c = 0;
double d = (samplerate / sin_freq);
int initial = NUM_SAMPLES / 25;
for (QWORD i = 0; i < NUM_SAMPLES; i += channels) {
buffer[i] = amplitude * sin(2 * pi * sin_freq * i / samplerate); // sin wave generated at "freq"
if (i == initial) {
for (QWORD j = 0; j < 480; j++) {
double stream = amplitude * sin((2 * pi * sin_freq * i / samplerate));
double beep = amplitude * sin((2 * pi * beep_freq * j / samplerate));
double multiplier = .4 * (1 - cos(2 * pi * j / 480));
buffer[i] = stream + (beep * multiplier);
// buffer[i] += (beep * multiplier);
i++;
}
initial = i + 19200.0;
//(1000 + rand() % 10000)
//double deg = 360.0 / d;
//buffer[i] = buffer[i + (1 * (channels - 1))] = sin((c++ * deg) * pi / 180) * amplitude;
}
}
}
Mixing of server and client signals:
void mix(BitDepth buffer[], BitDepth server[], BitDepth client[], double duration_milliseconds) {
QWORD num_samples = duration_milliseconds * (NUM_SAMPLES / 10000.0);
double tmp = 0;
QWORD size = NUM_SAMPLES + num_samples;
BitDepth *server_delay = new BitDepth[size];
BitDepth *client_delay = new BitDepth[size];
for (QWORD i = 0; i < size; i++) {
if (i < num_samples) {
server_delay[i] = 0;
client_delay[i + NUM_SAMPLES] = 0;
}
if (i > num_samples) {
server_delay[i] = server[i - num_samples];
client_delay[i - num_samples] = client[i - num_samples];
}
}
for (QWORD i = 0; i < NUM_SAMPLES; i += channels) {
// double multiplier = .5 * (1 - cos(2 * pi * i / NUM_SAMPLES-1));
// double multiplier = (0.54 - 0.46 * cos(2.0 * M_PI * (double) i / (double) (NUM_SAMPLES - 1)));
// server_delay[i] = multiplier * (server_delay[i]);
// client_delay[i] = multiplier * (client_delay[i]);
tmp = server_delay[i] + client_delay[i];
if (tmp > 32767) {
tmp = 32767;
} else if (tmp < -32768) {
tmp = -32768;
}
buffer[i] = tmp;
}
}
My Result in spectrogram from the above code:
Now, when I change the amplitude by increasing value from 0.5 to 0.8, in the following line:
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.5;
to
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.8;
I get following result:
I am new in DSP c++ programming and I really don't know what is this issue and how to resolve this issue?
Please help me in solving this issue.
thanks.
As Suggested by #PaulR, clipping was causing a lot of harmonics.
Your waveform is clipping (because 0.8 + 0.8 > 1.0), which will generate a lot of harmonics - look at the data in your debugger and you’ll see lots of flat peaks at +/- 32k.
So, after taking care of this limit. My issue is resolved.
Thanks alot.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am writing a molecular dynamics program to create an lattice and populate it with atoms/molecules. These then are given random velocities and the system is initialized. Then throughout time the molecules interact with each other and exert forces on each other.
I've tried to make my program as readable as possible.
My issue is when the code is run, the values of everything I'm interested in, mainly the vectors _tempreture, _pressure, _totalEnergy, _interactionEnergy, _kineticEnergy all seem to converge (after 5 runs) to certain values. These values then do not change throughout the rest of the runs and sometimes will randomly spike, then drop back down.
I can't figure out the unexpected behavior of my code, and I've been looking at it hours upon hours. I hoping one of you bright guys will be able to help me.
//in MD.h
#ifndef MD_H
#define MD_H
#include <iostream>
#include <random>
#include <time.h>
#include <vector>
#include <string>
#include <fstream>
class MD{
public:
MD();
~MD();
void initLatice();
void simulate(int _runs);
void wrtieToFile(std::string fileName);
double randomValue(double upper, double lower);
private:
double _nMolecules;
double _estKineticEnergy;
double _dt;
double _density;
bool _tempscale;
double _energyCorrection;
double _pressureCorrection;
double _nFCC = 4;
double _truncationSeperation;
double _sidelength;
double _pi = 3.142;
std::vector<double> x_data, y_data, z_data;
std::vector<double> _vX, _vY, _vZ;
std::vector<double> _xPos, _yPos, _zPos;
std::vector<double> _totalEnergy, _kineticEnergy, _interactionEnergy, _pressure, _tempreture;
std::vector<double> _radialDist, _radialDistCoord;
};
#endif
in case anyone is wondering the next file doesn't contain the definition for writeToFile, I decided not to paste it on here to save space.
//in MD.cpp
#include "MD.h"
MD::MD() : _radialDist(201, 0.0), _radialDistCoord(201, 0.0) {
_dt = 0.005;
_density = 1.0;
_tempscale = true;
_nMolecules = pow(_nFCC, 3) * 4;
x_data = { 0.25, 0.75, 0.75, 0.25 };
y_data = { 0.25, 0.75, 0.25, 0.75 };
z_data = { 0.25, 0.25, 0.75, 0.75 };
_sidelength = pow((_nFCC / _density), 1. / 3.);
_truncationSeperation = 2.5;
if (_truncationSeperation > _sidelength / 2.0)
_truncationSeperation = _sidelength / 2.0;
_energyCorrection = (8.0 * _pi * _density)*(1.0 / (9.0 * pow(_truncationSeperation, 9)) - 1 / (3.0 * pow(_truncationSeperation, 3)));
_pressureCorrection = (16.0 * _pi * pow(_density, 2))*(2.0 / (9.0 * pow(_truncationSeperation, 9)) - 1 / (3.0 * pow(_truncationSeperation, 3)));
}
MD::~MD(){}
double MD::randomValue(double upper, double lower)
{
double returnValue;
do{
returnValue = upper + (rand() / (RAND_MAX / (lower - upper)));
} while (returnValue > upper || returnValue < lower);
return returnValue;
}
void MD::initLatice(){
int count = 0;
double x_init = 0, y_init = 0, z_init = 0;
double _tempreture = 1.0;
_estKineticEnergy = 0.5 * (3.0 * _nMolecules - 4.0) * _tempreture;
srand(time(NULL));
for (int i = 0; i < 4; i++){
for (int a = 1; a <= _nFCC; a++){
for (int b = 1; b <= _nFCC; b++){
for (int c = 1; c <= _nFCC; c++){
_xPos.push_back(_sidelength*(a - 1 + x_data[i]) / _nFCC);
_vX.push_back(randomValue(0.5, -0.5));
x_init += _vX[count] / _nMolecules;
_yPos.push_back(_sidelength*(b - 1 + y_data[i]) / _nFCC);
_vY.push_back(randomValue(0.5, -0.5));
y_init += _vY[count] / _nMolecules;
_zPos.push_back(_sidelength*(c - 1 + z_data[i]) / _nFCC);
_vZ.push_back(randomValue(0.5, -0.5));
z_init += _vZ[count] / _nMolecules;
count++;
}
}
}
}
double velocityScale = 0, kineticEnergy = 0;
for (int i = 0; i < _nMolecules; i++){
_vX[i] -= x_init;
_vY[i] -= y_init;
_vZ[i] -= z_init;
kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
}
velocityScale = sqrt(_estKineticEnergy / kineticEnergy);
for (int i = 0; i < _nMolecules; i++){
_vX[i] = _vX[i] * velocityScale;
_vY[i] = _vY[i] * velocityScale;
_vZ[i] = _vZ[i] * velocityScale;
}
}
void MD::simulate(int _runs){
double force = 0;
double seperationSquared = 0;
double interactionEnergy = 0;
double kineticEnergy = 0;
double pressure = 0;
for (int run = 0; run <= _runs; run++){
interactionEnergy = 0;
pressure = 0;
std::vector<double> force_x(256, 0.0);
std::vector<double> force_y(256, 0.0);
std::vector<double> force_z(256, 0.0);
for (int i = 0; i < _nMolecules - 1; i++){
double xI = _xPos[i], yI = _yPos[i], zI = _zPos[i];
for (int j = i + 1; j < _nMolecules; j++){
double x = xI - _xPos[j];
double y = yI - _yPos[j];
double z = zI - _zPos[j];
if (x > _sidelength / 2.0)
x -= _sidelength;
if (y > _sidelength / 2.0)
y -= _sidelength;
if (z > _sidelength / 2.0)
z -= _sidelength;
if (x < -_sidelength / 2.0)
x += _sidelength;
if (y < -_sidelength / 2.0)
y += _sidelength;
if (z < -_sidelength / 2.0)
z += _sidelength;
seperationSquared = pow(x, 2) + pow(y, 2) + pow(z, 2);
if (seperationSquared <= (pow(_truncationSeperation, 2))){
interactionEnergy += 4. * ((1. / pow(seperationSquared, 6)) - (1. / pow(seperationSquared, 3)));
force = 24. * ((2. / pow(seperationSquared, 7)) - (1. / pow(seperationSquared, 4)));
force_x[i] += x * force;
force_y[i] += y * force;
force_z[i] += z * force;
force_x[j] -= x * force;
force_y[j] -= y * force;
force_z[j] -= z * force;
pressure += force * seperationSquared;
int histCounter = ceil(sqrt(seperationSquared) * (200.0/_truncationSeperation));
_radialDist[histCounter] += 1.0;
}
}
}
//thermostating
double velocityScale = 0;
if (_tempscale == true){
kineticEnergy = 0;
for (int i = 0; i < _nMolecules; i++)
kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
velocityScale = sqrt(_estKineticEnergy / kineticEnergy);
}
else { velocityScale = 1.0; }
kineticEnergy = 0;
//applying verlets leapfrog algorithm
for (int i = 0; i < _nMolecules; i++){
_vX[i] = _vX[i] * velocityScale + force_x[i] * _dt;
_xPos[i] += _vX[i] * _dt;
_vY[i] = _vY[i] * velocityScale + force_y[i] * _dt;
_yPos[i] += _vY[i] * _dt;
_vZ[i] = _vZ[i] * velocityScale + force_z[i] * _dt;
_zPos[i] += _vZ[i] * _dt;
kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
//check if the particle is still within the box
if (_xPos[i] > _sidelength)
_xPos[i] -= _sidelength;
if (_yPos[i] > _sidelength)
_yPos[i] -= _sidelength;
if (_zPos[i] > _sidelength)
_zPos[i] -= _sidelength;
if (_xPos[i] < 0.0)
_xPos[i] += _sidelength;
if (_yPos[i] < 0.0)
_yPos[i] += _sidelength;
if (_zPos[i] < 0.0)
_zPos[i] += _sidelength;
}
_kineticEnergy.push_back(kineticEnergy / _nMolecules);
_interactionEnergy.push_back((interactionEnergy / _nMolecules) + _energyCorrection);
_totalEnergy.push_back(_kineticEnergy[run] + _interactionEnergy[run]);
if (_tempscale == true)
_tempreture.push_back(_nMolecules * 2. * _kineticEnergy[run] / (3.0 * _nMolecules - 4.0));
else
_tempreture.push_back(_nMolecules * 2. * _kineticEnergy[run] / (3.0 * _nMolecules - 3.0));
_pressure.push_back((2.0 * _kineticEnergy[run] * _nMolecules + pressure) / (3.0*(pow(_sidelength, 3) + _pressureCorrection)));
}
for (int i = 1; i <= 200; i++){
double r = i * _truncationSeperation / 200.0;
_radialDistCoord[i] = _radialDistCoord[i - 1] + 2.0 * _radialDist[i] * 10 / _runs / _nMolecules;
_radialDist[i] = _radialDist[i] / (2.0*_pi*r*r*(_truncationSeperation/200.0)*_density*_runs*_nMolecules);
}
}
and finally...
//in main.cpp
#include "MD.h"
int main(){
MD myMD;
myMD.initLatice();
myMD.simulate(400);
std::string fileName = "myFile.txt";
myMD.wrtieToFile(fileName);
return 0;
}
Many thanks!
I am using this code for calculating sunrise and sunset times.
// Get the daylight status of the current time.
bool
SunLight::CalculateDaylightStatus()
{
// Calculate the current time of day.
time_t currentTime = time(NULL);
m_LocalTime = localtime(¤tTime);
// Initialize the sunrise and set times.
*m_Sunrise = *m_LocalTime;
*m_Sunset = *m_LocalTime;
// Flags to check whether sunrise or set available on the day or not.
m_IsSunrise = false;
m_IsSunset = false;
m_RiseAzimuth = 0.0;
m_SetAzimuth = 0.0;
for (unsigned int i = 0; i < 3; i++)
{
m_RightAscention[i] = 0.0;
m_Decension[i] = 0.0;
m_VHz[i] = 0.0;
}
for (unsigned int i = 0; i < 2; i++)
{
m_SunPositionInSky[i] = 0.0;
m_RiseTime[i] = 0;
m_SetTime[i] = 0;
}
// Calculate the sunrise and set times.
CalculateSunRiseSetTimes();
return (mktime(m_LocalTime) >= mktime(m_Sunrise) && mktime(m_LocalTime) < mktime(m_Sunset))
? true
: false;
}
//---------------------------------------------------------------------
bool
SunLight::CalculateSunRiseSetTimes()
{
double zone = timezone/3600 - m_LocalTime->tm_isdst;
// Julian day relative to Jan 1.5, 2000.
double jd = GetJulianDay() - 2451545;
if ((Sign(zone) == Sign(m_Config->Longitude())) && (zone != 0))
{
return false;
}
double tz = zone / 24;
// Centuries since 1900.0
double ct = jd / 36525 + 1;
// Local sidereal time.
double t0 = LocalSiderealTimeForTimeZone(jd, tz, m_Config->Longitude()/360);
// Get sun position at start of day.
jd += tz;
// Calculate the position of the sun.
CalculateSunPosition(jd, ct);
double ra0 = m_SunPositionInSky[0];
double dec0 = m_SunPositionInSky[1];
// Get sun position at end of day.
jd += 1;
// Calculate the position of the sun.
CalculateSunPosition(jd, ct);
double ra1 = m_SunPositionInSky[0];
double dec1 = m_SunPositionInSky[1];
// make continuous
if (ra1 < ra0)
ra1 += 2 * M_PI;
m_RightAscention[0] = ra0;
m_Decension[0] = dec0;
// check each hour of this day
for (int k = 0; k < 24; k++)
{
m_RightAscention[2] = ra0 + (k + 1) * (ra1 - ra0) / 24;
m_Decension[2] = dec0 + (k + 1) * (dec1 - dec0) / 24;
m_VHz[2] = TestHour(k, t0, m_Config->Latitude());
// advance to next hour
m_RightAscention[0] = m_RightAscention[2];
m_Decension[0] = m_Decension[2];
m_VHz[0] = m_VHz[2];
}
// Update the tm structure with time values.
m_Sunrise->tm_hour = m_RiseTime[0];
m_Sunrise->tm_min = m_RiseTime[1];
m_Sunset->tm_hour = m_SetTime[0];
m_Sunset->tm_min = m_SetTime[1];
// neither sunrise nor sunset
if ((!m_IsSunrise) && (!m_IsSunset))
{
// Sun down all day.
if (m_VHz[2] < 0)
m_IsSunset = true;
// Sun up all day.
else
m_IsSunrise = true;
}
return true;
}
//---------------------------------------------------------------------
int
SunLight::Sign(double value)
{
if (value > 0.0)
return 1;
else if (value < 0.0)
return -1;
else
return 0;
}
//---------------------------------------------------------------------
// Local Sidereal Time for zone.
double
SunLight::LocalSiderealTimeForTimeZone(double jd, double z, double lon)
{
double s = 24110.5 + 8640184.812999999 * jd / 36525 + 86636.6 * z + 86400 * lon;
s = s / 86400;
s = s - floor(s);
return s * 360 * cDegToRad;
}
//---------------------------------------------------------------------
// Determine Julian day from calendar date
// (Jean Meeus, "Astronomical Algorithms", Willmann-Bell, 1991).
double
SunLight::GetJulianDay()
{
int month = m_LocalTime->tm_mon + 1;
int day = m_LocalTime->tm_mday;
int year = 1900 + m_LocalTime->tm_year;
bool gregorian = (year < 1583) ? false : true;
if ((month == 1) || (month == 2))
{
year = year - 1;
month = month + 12;
}
double a = floor((double)year / 100);
double b = 0;
if (gregorian)
b = 2 - a + floor(a / 4);
else
b = 0.0;
double jd = floor(365.25 * (year + 4716))
+ floor(30.6001 * (month + 1))
+ day + b - 1524.5;
return jd;
}
//---------------------------------------------------------------------
// Sun's position using fundamental arguments
// (Van Flandern & Pulkkinen, 1979).
void
SunLight::CalculateSunPosition(double jd, double ct)
{
double g, lo, s, u, v, w;
lo = 0.779072 + 0.00273790931 * jd;
lo = lo - floor(lo);
lo = lo * 2 * M_PI;
g = 0.993126 + 0.0027377785 * jd;
g = g - floor(g);
g = g * 2 * M_PI;
v = 0.39785 * sin(lo);
v = v - 0.01 * sin(lo - g);
v = v + 0.00333 * sin(lo + g);
v = v - 0.00021 * ct * sin(lo);
u = 1 - 0.03349 * cos(g);
u = u - 0.00014 * cos(2 * lo);
u = u + 0.00008 * cos(lo);
w = -0.0001 - 0.04129 * sin(2 * lo);
w = w + 0.03211 * sin(g);
w = w + 0.00104 * sin(2 * lo - g);
w = w - 0.00035 * sin(2 * lo + g);
w = w - 0.00008 * ct * sin(g);
// compute sun's right ascension
s = w / sqrt(u - v * v);
m_SunPositionInSky[0] = lo + atan(s / sqrt(1 - s * s));
// ...and declination
s = v / sqrt(u);
m_SunPositionInSky[1] = atan(s / sqrt(1 - s * s));
}
//---------------------------------------------------------------------
// Test an hour for an event.
double
SunLight::TestHour(int k, double t0, double prmLatitude)
{
double ha[3];
double a, b, c, d, e, s, z;
double time;
double az, dz, hz, nz;
int hr, min;
ha[0] = t0 - m_RightAscention[0] + k * cK1;
ha[2] = t0 - m_RightAscention[2] + k * cK1 + cK1;
ha[1] = (ha[2] + ha[0]) / 2; // hour angle at half hour
m_Decension[1] = (m_Decension[2] + m_Decension[0]) / 2; // declination at half hour
s = sin(prmLatitude * cDegToRad);
c = cos(prmLatitude * cDegToRad);
z = cos(90.833 * cDegToRad); // refraction + sun semi-diameter at horizon
if (k <= 0)
m_VHz[0] = s * sin(m_Decension[0]) + c * cos(m_Decension[0]) * cos(ha[0]) - z;
m_VHz[2] = s * sin(m_Decension[2]) + c * cos(m_Decension[2]) * cos(ha[2]) - z;
if (Sign(m_VHz[0]) == Sign(m_VHz[2]))
return m_VHz[2]; // no event this hour
m_VHz[1] = s * sin(m_Decension[1]) + c * cos(m_Decension[1]) * cos(ha[1]) - z;
a = 2 * m_VHz[0] - 4 * m_VHz[1] + 2 * m_VHz[2];
b = -3 * m_VHz[0] + 4 * m_VHz[1] - m_VHz[2];
d = b * b - 4 * a * m_VHz[0];
if (d < 0)
return m_VHz[2]; // no event this hour
d = sqrt(d);
e = (-b + d) / (2 * a);
if ((e > 1) || (e < 0))
e = (-b - d) / (2 * a);
time = (double)k + e + (double)1 / (double)120; // time of an event
hr = (int)floor(time);
min = (int)floor((time - hr) * 60);
hz = ha[0] + e * (ha[2] - ha[0]); // azimuth of the sun at the event
nz = -cos(m_Decension[1]) * sin(hz);
dz = c * sin(m_Decension[1]) - s * cos(m_Decension[1]) * cos(hz);
az = atan2(nz, dz) / cDegToRad;
if (az < 0) az = az + 360;
if ((m_VHz[0] < 0) && (m_VHz[2] > 0))
{
m_RiseTime[0] = hr;
m_RiseTime[1] = min;
m_RiseAzimuth = az;
m_IsSunrise = true;
}
if ((m_VHz[0] > 0) && (m_VHz[2] < 0))
{
m_SetTime[0] = hr;
m_SetTime[1] = min;
m_SetAzimuth = az;
m_IsSunset = true;
}
return m_VHz[2];
}
//---------------------------------------------------------------------
I need to introduce altitude in the formula which gives more accurate result. Can someone give me a quick solution what I have to modify to add altitude in the formula?
That algorithm is nowhere near calculating the times of sunrise and sunset. What you need is Jean Meeus' book "Astronomical Algorithms". You will need to account for the observer's longitude and latitude, the difference between dynamical time and universal time, and the eccentricity of the Earth's orbit to obtain even a low accuracy result.
This seems to be called sunrise equation. The formulas in that Wiki article are unbelievably simple, and they do account for the geographic location.
We need to change/reimplement standard DFT implementation in GSL, which is
int
FUNCTION(gsl_dft_complex,transform) (const BASE data[],
const size_t stride, const size_t n,
BASE result[],
const gsl_fft_direction sign)
{
size_t i, j, exponent;
const double d_theta = 2.0 * ((int) sign) * M_PI / (double) n;
/* FIXME: check that input length == output length and give error */
for (i = 0; i < n; i++)
{
ATOMIC sum_real = 0;
ATOMIC sum_imag = 0;
exponent = 0;
for (j = 0; j < n; j++)
{
double theta = d_theta * (double) exponent;
/* sum = exp(i theta) * data[j] */
ATOMIC w_real = (ATOMIC) cos (theta);
ATOMIC w_imag = (ATOMIC) sin (theta);
ATOMIC data_real = REAL(data,stride,j);
ATOMIC data_imag = IMAG(data,stride,j);
sum_real += w_real * data_real - w_imag * data_imag;
sum_imag += w_real * data_imag + w_imag * data_real;
exponent = (exponent + i) % n;
}
REAL(result,stride,i) = sum_real;
IMAG(result,stride,i) = sum_imag;
}
return 0;
}
In this implementation, GSL iterates over input vector twice for sample/input size. However, we need to construct for different frequency bins. For instance, we have 4096 samples, but we need to calculate DFT for 128 different frequencies. Could you help me to define or implement required DFT behaviour? Thanks in advance.
EDIT: We do not search for first m frequencies.
Actually, is below approach correct for finding DFT result with given frequency bin number?
N = sample size
B = frequency bin size
k = 0,...,127 X[k] = SUM(0,N){x[i]*exp(-j*2*pi*k*i/B)}
EDIT: I might have not explained the problem for DFT elaborately, nevertheless, I am happy to provide the answer below:
void compute_dft(const std::vector<double>& signal,
const std::vector<double>& frequency_band,
std::vector<double>& result,
const double sampling_rate)
{
if(0 == result.size() || result.size() != (frequency_band.size() << 1)){
result.resize(frequency_band.size() << 1, 0.0);
}
//note complex signal assumption
const double d_theta = -2.0 * PI * sampling_rate;
for(size_t k = 0; k < frequency_band.size(); ++k){
const double f_k = frequency_band[k];
double real_sum = 0.0;
double imag_sum = 0.0;
for(size_t n = 0; n < (signal.size() >> 1); ++n){
double theta = d_theta * f_k * (n + 1);
double w_real = cos(theta);
double w_imag = sin(theta);
double d_real = signal[2*n];
double d_imag = signal[2*n + 1];
real_sum += w_real * d_real - w_imag * d_imag;
imag_sum += w_real * d_imag + w_imag * d_real;
}
result[2*k] = real_sum;
result[2*k + 1] = imag_sum;
}
}
Assuming you just want the the first m output frequencies:
int
FUNCTION(gsl_dft_complex,transform) (const BASE data[],
const size_t stride,
const size_t n, // input size
const size_t m, // output size (m <= n)
BASE result[],
const gsl_fft_direction sign)
{
size_t i, j, exponent;
const double d_theta = 2.0 * ((int) sign) * M_PI / (double) n;
/* FIXME: check that m <= n and give error */
for (i = 0; i < m; i++) // for each of m output bins
{
ATOMIC sum_real = 0;
ATOMIC sum_imag = 0;
exponent = 0;
for (j = 0; j < n; j++) // for each of n input points
{
double theta = d_theta * (double) exponent;
/* sum = exp(i theta) * data[j] */
ATOMIC w_real = (ATOMIC) cos (theta);
ATOMIC w_imag = (ATOMIC) sin (theta);
ATOMIC data_real = REAL(data,stride,j);
ATOMIC data_imag = IMAG(data,stride,j);
sum_real += w_real * data_real - w_imag * data_imag;
sum_imag += w_real * data_imag + w_imag * data_real;
exponent = (exponent + i) % n;
}
REAL(result,stride,i) = sum_real;
IMAG(result,stride,i) = sum_imag;
}
return 0;
}