Нелинейные результаты с выхода таймера qt С++

70
7

Следующий код используется как "GPS-симулятор" внутри гораздо более крупной программы. Благодаря помощи великих людей на этом веб-сайте у меня теперь есть работа. Однако есть небольшая проблема, с которой мне все еще нужна помощь. GpsRunLoop (который генерирует gps-координаты) запускается со скоростью, зависящей от vaiable flyspeed. Flyspeed создается с помощью управления ползунком в ui. Самая медленная скорость составляет около 20 миль/ч с использованием значения скорости полета 120. Самая быстрая скорость составляет около 170 миль/ч с использованием значения скорости полета 15. "Маленькая проблема" заключается в том, что скорость не изменяется линейно. Когда скорость полета изменяется с 15 до 25, скорость изменяется с 170 миль в час до 85 миль/ч. На другом конце ползунка, когда скорость полета изменена с 105 tp 115, скорость изменяется с 22 до 20. Изменение скорости выглядит экспоненциальным. Я хотел бы сделать это изменение линейным, но все мои попытки до сих пор потерпели неудачу. Любая помощь будет очень высоко ценится!

double f,sk,ga,flat = 32.447414,flon = -100.131188, flat2, flon2, td;
int stp = 0,flyspeed = 67;
bool rungps;

void MainWindow::onGpsCalcLoop()
{
//Get initial values from gps run loop-------
double lat2 = flat2;
double lat1 = flat;
double lon2 = flon2;
double lon1 = flon;
//GPS distance and speed calculation -------
double dLat = .01745329 * (lat2 - lat1);
double dLon = .01745329 * (lon2 - lon1);
lat1 = .01745329 * lat1;
lat2 = .01745329 * lat2;
double a = qSin(dLat/2) * qSin(dLat/2) +
qSin(dLon/2) * qSin(dLon/2) * qCos(lat1) * qCos(lat2);
double c = 2 * qAtan2(qSqrt(a), qSqrt(1-a));
double d = 3975 * c;
//Distance calculation done. Next is total distance and speed------
td = td + d;
if (d > .1)
{
d = 0;
td = 0;
}
if (ui -> metric -> isChecked())
{
ui -> valuetest1 -> setValue(td*1.6);
ui -> valuetest2 -> setValue((d * 3600) * 1.6);
}
else
{
ui -> valuetest2 -> setValue(d * 3600);
ui -> valuetest1 -> setValue(td);
}
flat2 = flat;
flon2 = flon;
}
void MainWindow::onGpsRunLoop()
{
QString la,lo,ll;
flat = flat + .0000078; // For north and south use .0000102 for 'flat', 0.0 for 'flon'
flon = flon + .0000078; // For east and west use .0000121 for 'flon', 0.0 for flat
la = QString::number(flat, 'f', 6); // For all 45 degree directions use .0000078 for both 'flat' and 'flon'
lo = QString::number(flon, 'f', 6);
ll = la + "," + lo;
ui -> gps_latlon -> setText(ll);
}

void MainWindow::on_pushButton_clicked()
{
ui -> pushButton_2 -> setChecked(0);
rungps = true;
gpscalcTimer->start(1000);
gpsrunTimer->start(flyspeed);
}

void MainWindow::on_pushButton_2_clicked()
{
ui -> pushButton -> setChecked(0);
gpscalcTimer->stop();
gpsrunTimer->stop();
rungps = false;
}

void MainWindow::on_horizontalSlider_valueChanged(int value)
{
flyspeed = value;
ui -> valuetest3 -> setValue(flyspeed);
if(rungps)
{
gpsrunTimer->stop();
gpsrunTimer->start(flyspeed);
}
}

void MainWindow::on_metric_clicked()
{
ui -> label_4 -> setText("kilometers");
ui -> label_5 -> setText("kph");
}

void MainWindow::on_imperial_clicked()
{
ui -> label_4 -> setText("miles");
ui -> label_5 -> setText("mph");
}

Проект qt c++, который я использую для тестирования, можно загрузить по адресу:

https://www.dropbox.com/sh/i8opg7a3jkzrmcv/AACuSfx9r9DDOXKO_DacT4nHa?dl=0

спросил(а) 2016-01-08T20:14:00+03:00 4 года, 8 месяцев назад
1
Решение
56

Если я правильно понимаю, ваша flyspeed на самом деле является интервалом. Так что, конечно, так оно и происходит, это обратная связь. Если вы умножаете интервал на x, фактическая скорость делится на x.

Поэтому в основном, если вы хотите изменить скорость увеличения с v на v + d, вы фактически умножаете скорость на ((v + d)/v). Таким образом, вам нужно настроить flyspeed, разделив на это.

Однако то, что вы на самом деле хотите, - это сопоставить горизонтальное значение скорости ползунка с интервалом для flyspeed, что-то вроде этого:

// map slider value so that speed 1 is interval 1000 ms, speed 100 is 10 ms
void MainWindow::on_horizontalSlider_valueChanged(int value)
{
if (value <= 0) {
// speed is 0, stop timer, or something
if(rungps) gpsrunTimer->stop();
}
else {
double inverse = 1.0 / value; // 100 -> 0.01, speed 1 -> 1
double interval = inverse * 1000; // 0.01 -> 10 ms, 1 -> 1000 ms
flyspeed = interval; // implicitly truncating decimals
ui->valuetest3->setValue(flyspeed);
if(rungps)
{
gpsrunTimer->start(flyspeed);
}
}
}

Обратите внимание, что QTimer не очень точен даже до миллисекунды, и даже если бы это было так, это все равно было бы довольно неточным, так что вам нужен другой подход, если вам нужна точность... Тем не менее, проверьте свойство типа таймера QTimer с правильным типом он попытается достичь миллисекундной точности.

ответил(а) 2016-01-09T10:29:00+03:00 4 года, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема